@@ -4119,6 +4119,118 @@ function logBatchPurityReport(summary) {
41194119 const impureRuns = Number . isFinite ( summary . impureRuns ) ? summary . impureRuns : 0 ;
41204120 const runs = Array . isArray ( summary . runs ) ? summary . runs : [ ] ;
41214121
4122+ try {
4123+ const analysis = summary ?. analysis || null ;
4124+ const avgRaw = Number . isFinite ( analysis ?. avgRawTotal ) ? analysis . avgRawTotal : 0 ;
4125+ const avgShare = Number . isFinite ( analysis ?. avgShareTotal ) ? analysis . avgShareTotal : 0 ;
4126+ const avgSequence = Number . isFinite ( analysis ?. avgSequenceTotal ) ? analysis . avgSequenceTotal : 0 ;
4127+ const shareDriftMinutes = avgShare - avgRaw ;
4128+ const shareDriftPercentValue = avgRaw === 0 ? null : shareDriftMinutes / avgRaw ;
4129+ const shareDriftPercent = shareDriftPercentValue ?? 0 ;
4130+ const humanHeader = `Batch analysis: ${ totalRuns } runs | pure=${ pureRuns } , impure=${ impureRuns } ` ;
4131+
4132+ const activityAnalyses = Array . isArray ( analysis ?. activities ) ? analysis . activities : [ ] ;
4133+ const activityAverages = activityAnalyses . map ( ( activity , index ) => {
4134+ const id = activity ?. key || activity ?. label || `activity-${ index + 1 } ` ;
4135+ const avgRawPerRun = Number . isFinite ( activity ?. avgRawPerRun ) ? activity . avgRawPerRun : 0 ;
4136+ const avgSharePerRun = Number . isFinite ( activity ?. avgSharePerRun ) ? activity . avgSharePerRun : 0 ;
4137+ const driftMinutes = Number . isFinite ( activity ?. avgShareDriftMinutes )
4138+ ? activity . avgShareDriftMinutes
4139+ : 0 ;
4140+ const driftPercent = Number . isFinite ( activity ?. avgShareDriftPercent )
4141+ ? activity . avgShareDriftPercent
4142+ : 0 ;
4143+ return {
4144+ id,
4145+ avgRaw : avgRawPerRun ,
4146+ avgShare : avgSharePerRun ,
4147+ driftMinutes,
4148+ driftPercent,
4149+ } ;
4150+ } ) ;
4151+
4152+ const significantActivities = activityAnalyses
4153+ . filter ( ( activity ) => {
4154+ if ( ! activity ) {
4155+ return false ;
4156+ }
4157+ const driftMinutes = Number ( activity . avgShareDriftMinutes ) || 0 ;
4158+ const driftPercent = Number ( activity . avgShareDriftPercent ) || 0 ;
4159+ return Math . abs ( driftMinutes ) >= 60 || Math . abs ( driftPercent ) >= 0.1 ;
4160+ } )
4161+ . sort ( ( a , b ) => Math . abs ( b . avgShareDriftMinutes || 0 ) - Math . abs ( a . avgShareDriftMinutes || 0 ) )
4162+ . slice ( 0 , 3 ) ;
4163+
4164+ const activitySummaries = significantActivities . map ( ( activity ) => {
4165+ const label = activity ?. label || activity ?. key || 'activity' ;
4166+ const avgRawText = formatPurityMinutes ( activity ?. avgRawPerRun ) ;
4167+ const avgShareText = formatPurityMinutes ( activity ?. avgSharePerRun ) ;
4168+ const driftMinutesValue = Number ( activity ?. avgShareDriftMinutes ) || 0 ;
4169+ const driftMagnitudeText = formatPurityMinutes ( Math . abs ( driftMinutesValue ) ) ;
4170+ const driftPercentText = formatPurityPercent ( activity ?. avgShareDriftPercent ) ;
4171+ const percentSuffix = driftPercentText === 'n/a' ? '' : ` (${ driftPercentText } )` ;
4172+ const descriptor = driftMinutesValue < 0 ? 'undercounted' : 'overcounted' ;
4173+ return `Activity '${ label } ': avg raw/share = ${ avgRawText } /${ avgShareText } (${ descriptor } by ${ driftMagnitudeText } min${ percentSuffix } ).` ;
4174+ } ) ;
4175+
4176+ const runAnalyses = Array . isArray ( analysis ?. runs ) ? analysis . runs : [ ] ;
4177+ const worstRuns = runAnalyses
4178+ . filter ( ( run ) => run && Number . isFinite ( run . totalDriftMinutes ) )
4179+ . map ( ( run ) => ( {
4180+ runIndex : Number . isFinite ( run . runIndex ) ? run . runIndex : 0 ,
4181+ driftMinutes : Number . isFinite ( run . totalDriftMinutes ) ? run . totalDriftMinutes : 0 ,
4182+ } ) )
4183+ . sort ( ( a , b ) => Math . abs ( b . driftMinutes || 0 ) - Math . abs ( a . driftMinutes || 0 ) )
4184+ . slice ( 0 , 3 ) ;
4185+
4186+ const worstRunSummaries = worstRuns . length
4187+ ? [
4188+ `Worst drift in runs ${ worstRuns
4189+ . map ( ( run ) => `#${ run . runIndex || 0 } ` )
4190+ . join ( ', ' ) } (share vs raw drift minutes: ${ worstRuns
4191+ . map ( ( run ) => formatPurityMinutes ( run . driftMinutes ) )
4192+ . join ( ', ' ) } ).`,
4193+ ]
4194+ : [ ] ;
4195+
4196+ const avgRawText = formatPurityMinutes ( avgRaw ) ;
4197+ const avgShareText = formatPurityMinutes ( avgShare ) ;
4198+ const avgSequenceText = formatPurityMinutes ( avgSequence ) ;
4199+ const shareDriftText = formatPurityMinutes ( shareDriftMinutes ) ;
4200+ const shareDriftPercentText = formatPurityPercent ( shareDriftPercentValue ) ;
4201+ const humanLines = [
4202+ `Purity status: ${ pureRuns === totalRuns && totalRuns > 0 ? 'PASSED' : 'FAILED' } .` ,
4203+ `Average totals per run (raw/share/sequence): ${ avgRawText } / ${ avgShareText } / ${ avgSequenceText } .` ,
4204+ `Average drift of share vs raw: ${ shareDriftText } minutes (${ shareDriftPercentText } ).` ,
4205+ ...activitySummaries ,
4206+ ...worstRunSummaries ,
4207+ ] ;
4208+
4209+ const purityReport = {
4210+ kind : 'purity_batch_report' ,
4211+ batchSize : totalRuns ,
4212+ pureRuns,
4213+ impureRuns,
4214+ totals : {
4215+ avgRaw,
4216+ avgShare,
4217+ avgSequence,
4218+ avgShareDriftMinutes : shareDriftMinutes ,
4219+ avgShareDriftPercent : shareDriftPercent ,
4220+ } ,
4221+ activities : activityAverages ,
4222+ worstRuns,
4223+ human : {
4224+ header : humanHeader ,
4225+ lines : humanLines ,
4226+ } ,
4227+ } ;
4228+
4229+ console . warn ( '[Purity][REPORT] ' + JSON . stringify ( purityReport ) ) ;
4230+ } catch ( error ) {
4231+ console . error ( '[Purity] Failed to build structured purity report:' , error ) ;
4232+ }
4233+
41224234 appendLogEntry ( {
41234235 level : 'warn' ,
41244236 message : `[Purity] Batch analysis: ${ totalRuns } runs, pure=${ pureRuns } , impure=${ impureRuns } ` ,
0 commit comments