Skip to content

Commit 10ce988

Browse files
authored
Merge pull request #180 from LennartvdM/codex/add-structured-purity-report-output
Add structured purity batch report
2 parents a18a3b0 + 301a9d1 commit 10ce988

1 file changed

Lines changed: 112 additions & 0 deletions

File tree

web/app.js

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)