Skip to content

Commit a18a3b0

Browse files
authored
Merge pull request #179 from LennartvdM/codex/restore-human-readable-purity-summary-logs
Restore human-readable purity summary logs
2 parents c73f053 + e01d531 commit a18a3b0

1 file changed

Lines changed: 61 additions & 53 deletions

File tree

web/app.js

Lines changed: 61 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3741,12 +3741,57 @@ function formatPurityPercent(value) {
37413741

37423742
function buildPurityObservations(summary) {
37433743
const lines = [];
3744-
const analysis = summary?.analysis;
37453744
const totalRuns = Number.isFinite(summary?.totalRuns) ? summary.totalRuns : 0;
3746-
if (!analysis || !totalRuns) {
3745+
const impureRuns = Number.isFinite(summary?.impureRuns) ? summary.impureRuns : 0;
3746+
const runs = Array.isArray(summary?.runs) ? summary.runs : [];
3747+
const checkerErrorRuns = runs.filter((run) => run && run.didError).length;
3748+
const hasCheckerError = Boolean(summary?.didCheckerError) || checkerErrorRuns > 0;
3749+
const statusLabel = hasCheckerError ? 'ERROR' : summary?.hasAnyError ? 'FAILED' : 'OK';
3750+
const detailParts = [];
3751+
if (totalRuns <= 0) {
3752+
detailParts.push('No runs analyzed.');
3753+
} else {
3754+
if (impureRuns > 0) {
3755+
detailParts.push(`${impureRuns}/${totalRuns} runs show drift between raw and share totals.`);
3756+
}
3757+
if (checkerErrorRuns > 0) {
3758+
detailParts.push(`${checkerErrorRuns}/${totalRuns} runs had checker errors.`);
3759+
}
3760+
if (detailParts.length === 0) {
3761+
detailParts.push(`All ${totalRuns} runs match raw and share totals.`);
3762+
}
3763+
}
3764+
lines.push(`Overall: Purity status: ${statusLabel}. ${detailParts.join(' ')}`);
3765+
3766+
const analysis = summary?.analysis;
3767+
if (!analysis || totalRuns <= 0) {
37473768
return lines;
37483769
}
37493770

3771+
const avgRaw = formatPurityMinutes(analysis.avgRawTotal);
3772+
const avgShare = formatPurityMinutes(analysis.avgShareTotal);
3773+
const avgSequence = formatPurityMinutes(analysis.avgSequenceTotal);
3774+
lines.push(
3775+
`Overall: Average total minutes per run: raw=${avgRaw}, share=${avgShare}, sequence=${avgSequence}.`
3776+
);
3777+
3778+
const shareDiff = (Number(analysis.avgShareTotal) || 0) - (Number(analysis.avgRawTotal) || 0);
3779+
const percentDiff = analysis.avgRawTotal === 0 ? null : shareDiff / analysis.avgRawTotal;
3780+
const driftMagnitudeText = formatPurityMinutes(Math.abs(shareDiff));
3781+
const percentText = formatPurityPercent(percentDiff);
3782+
const percentSuffix = percentText === 'n/a' ? '' : ` (≈ ${percentText})`;
3783+
if (shareDiff < 0) {
3784+
lines.push(
3785+
`Overall: On average, share is missing ${driftMagnitudeText} minutes per run compared to raw${percentSuffix}.`
3786+
);
3787+
} else if (shareDiff > 0) {
3788+
lines.push(
3789+
`Overall: On average, share is over-reporting ${driftMagnitudeText} minutes per run compared to raw${percentSuffix}.`
3790+
);
3791+
} else {
3792+
lines.push('Overall: On average, share matches raw totals per run.');
3793+
}
3794+
37503795
const activityThresholdMinutes = 60;
37513796
const activityThresholdPercent = 0.1;
37523797
const activityAnalyses = Array.isArray(analysis.activities) ? analysis.activities.slice() : [];
@@ -3769,13 +3814,13 @@ function buildPurityObservations(summary) {
37693814

37703815
significantActivities.forEach((activity) => {
37713816
const label = activity.label || activity.key || 'activity';
3772-
const avgRawText = formatPurityMinutes(activity.avgRawPerRun);
3773-
const avgShareText = formatPurityMinutes(activity.avgSharePerRun);
3774-
const driftMinutesText = formatPurityMinutes(activity.avgShareDriftMinutes || 0);
3817+
const driftMinutes = Number(activity.avgShareDriftMinutes) || 0;
3818+
const driftMagnitudeText = formatPurityMinutes(Math.abs(driftMinutes));
37753819
const percentText = formatPurityPercent(activity.avgShareDriftPercent);
3776-
const percentSuffix = percentText === 'n/a' ? '' : ` (≈ ${percentText})`;
3820+
const percentSuffix = percentText === 'n/a' ? '' : ` (≈ ${percentText} vs raw)`;
3821+
const descriptor = driftMinutes < 0 ? 'undercounted' : 'overcounted';
37773822
lines.push(
3778-
`ACTIVITY | ${label} | avg raw/share per run: ${avgRawText} / ${avgShareText} | drift: ${driftMinutesText} min${percentSuffix}`
3823+
`Activity '${label}' is ${descriptor} in share by an average of ${driftMagnitudeText} minutes per run${percentSuffix}.`
37793824
);
37803825
});
37813826

@@ -3800,52 +3845,13 @@ function buildPurityObservations(summary) {
38003845
}
38013846
const minMagnitudeText = formatPurityMinutes(minMagnitude);
38023847
lines.push(
3803-
`RUNS | worst total drift: ${runLabels.join(', ')} (share ${descriptor}${minMagnitudeText} min each)`
3848+
`Runs: Largest total drift in runs ${runLabels.join(', ')} (share ${descriptor}${minMagnitudeText} minutes each).`
38043849
);
38053850
}
38063851

38073852
return lines;
38083853
}
38093854

3810-
function buildPuritySummaryLines(summary, observations) {
3811-
const lines = [];
3812-
const totalRuns = Number.isFinite(summary?.totalRuns) ? summary.totalRuns : 0;
3813-
const pureRuns = Number.isFinite(summary?.pureRuns) ? summary.pureRuns : 0;
3814-
const impureRuns = Number.isFinite(summary?.impureRuns) ? summary.impureRuns : 0;
3815-
const runs = Array.isArray(summary?.runs) ? summary.runs : [];
3816-
const checkerErrorRuns = runs.filter((run) => run && run.didError).length;
3817-
const hasCheckerError = Boolean(summary?.didCheckerError);
3818-
const errorCount = hasCheckerError ? Math.max(1, checkerErrorRuns) : checkerErrorRuns;
3819-
const statusLabel = hasCheckerError ? 'ERROR' : summary?.hasAnyError ? 'FAILED' : 'OK';
3820-
const statusParts = [`runs: ${totalRuns} total, ${pureRuns} pure, ${impureRuns} impure`];
3821-
if (errorCount > 0) {
3822-
statusParts.push(`checker errors: ${errorCount}`);
3823-
}
3824-
lines.push(`STATUS | ${statusLabel} | ${statusParts.join(' | ')}`);
3825-
3826-
const analysis = summary?.analysis;
3827-
if (analysis && totalRuns > 0) {
3828-
const avgRaw = formatPurityMinutes(analysis.avgRawTotal);
3829-
const avgShare = formatPurityMinutes(analysis.avgShareTotal);
3830-
const avgSequence = formatPurityMinutes(analysis.avgSequenceTotal);
3831-
lines.push(`TOTALS | avg raw/share/sequence per run: ${avgRaw} / ${avgShare} / ${avgSequence}`);
3832-
3833-
const shareDiff = (Number(analysis.avgShareTotal) || 0) - (Number(analysis.avgRawTotal) || 0);
3834-
const percentDiff = analysis.avgRawTotal === 0 ? null : shareDiff / analysis.avgRawTotal;
3835-
const driftMinutesText = formatPurityMinutes(shareDiff);
3836-
const percentText = formatPurityPercent(percentDiff);
3837-
const percentSuffix = percentText === 'n/a' ? '' : ` (≈ ${percentText})`;
3838-
lines.push(`TOTALS | avg drift (share vs raw): ${driftMinutesText} min per run${percentSuffix}`);
3839-
}
3840-
3841-
if (Array.isArray(observations) && observations.length > 0) {
3842-
lines.push(...observations);
3843-
}
3844-
3845-
lines.push('NOTE | Full raw purity data continues below…');
3846-
return lines;
3847-
}
3848-
38493855
function cancelBatchFitMeasurement() {
38503856
if (
38513857
batchState.pendingFitFrame &&
@@ -4112,18 +4118,20 @@ function logBatchPurityReport(summary) {
41124118
const pureRuns = Number.isFinite(summary.pureRuns) ? summary.pureRuns : 0;
41134119
const impureRuns = Number.isFinite(summary.impureRuns) ? summary.impureRuns : 0;
41144120
const runs = Array.isArray(summary.runs) ? summary.runs : [];
4115-
const errorRuns = runs.filter((run) => run && run.didError).length;
4116-
const logLevel = summary.hasAnyError ? 'warn' : 'info';
4121+
4122+
appendLogEntry({
4123+
level: 'warn',
4124+
message: `[Purity] Batch analysis: ${totalRuns} runs, pure=${pureRuns}, impure=${impureRuns}`,
4125+
});
41174126

41184127
try {
41194128
const observationLines = buildPurityObservations(summary);
4120-
const summaryLines = buildPuritySummaryLines(summary, observationLines);
4121-
summaryLines.forEach((line) => {
4122-
appendLogEntry({ level: logLevel, message: `[Purity][Summary] ${line}` });
4129+
observationLines.forEach((line) => {
4130+
appendLogEntry({ level: 'warn', message: `[Purity] ${line}` });
41234131
});
41244132
} catch (error) {
41254133
const message = error instanceof Error ? error.message : String(error);
4126-
appendLogEntry({ level: 'warn', message: `[Purity][Summary] ERROR building summary: ${message}` });
4134+
appendLogEntry({ level: 'warn', message: `[Purity] ERROR building summary: ${message}` });
41274135
}
41284136

41294137
try {

0 commit comments

Comments
 (0)