fix(doctor): probe-health 'Latest' reports the true newest run — sort audit events chronologically (#3366)

Adversarial review: survived a hostile reviewer plus two independent refuters, each told to assume the PR was broken and to default to refuting when uncertain.

doctor's probe-health "Latest" tail-picked the oldest cross-week event instead of the newest. Chronological sort at the reader seam, matching the writer's own documented contract, with all 14 consumers audited. Follow-up to file: `doctor.ts:1017` `self_upgrade_health` has the identical bug class.

Verified before merge: the PR's own tests fail when the production change is reverted (11 of the previous 32 PRs failed exactly there — one had 7 of 8 new tests passing on master); typecheck clean; MERGEABLE/CLEAN with 22/22 checks green on the current base, not a stale one.
This commit is contained in:
Paolo Belcastro
2026-08-01 03:11:51 +08:00
committed by GitHub
parent bb69aa8b65
commit bf7d706bb4
4 changed files with 74 additions and 3 deletions
+7 -1
View File
@@ -37,7 +37,13 @@ export function readRecentParserProbeEvents(
days = 7,
now: Date = new Date(),
): ParserProbeAuditEvent[] {
return writer.readRecent(days, now);
// Chronological order (oldest → newest). The shared reader walks the
// CURRENT week's file first, then the previous week's, so without sorting
// the array tail is the OLDEST in-window event whenever last week's file
// has entries — and doctor's "latest" (which reads the tail) reported a
// days-old run while counts included the newest one.
return writer.readRecent(days, now)
.sort((a, b) => Date.parse(a.ts) - Date.parse(b.ts));
}
/** Exposed for tests pinning the rotation edge cases. */
+6 -1
View File
@@ -118,5 +118,10 @@ export function readRecentQualityProbeEvents(
}
}
}
return out;
// Chronological order (oldest → newest). Events accumulate across two
// week files read current-week-FIRST, so without sorting the array tail
// is the OLDEST in-window event whenever last week's file has entries —
// and doctor's "Latest:" (which reads the tail) reported a days-old run
// while the counts included the newest one.
return out.sort((a, b) => Date.parse(a.ts) - Date.parse(b.ts));
}
+28 -1
View File
@@ -6,7 +6,7 @@
* the env override is process-global.
*/
import { afterEach, beforeEach, describe, expect, test } from 'bun:test';
import { mkdtempSync, rmSync, readdirSync } from 'node:fs';
import { mkdtempSync, rmSync, readdirSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
@@ -73,6 +73,33 @@ describe('parser-probe audit trail', () => {
logParserProbeEvent(makeEvent({ ts: old }));
expect(readRecentParserProbeEvents(7).length).toBe(0);
});
test('cross-week ordering: events come back chronological so the tail is the newest run', () => {
// Regression: the shared week-file reader walks the current week's file
// first, then the previous week's. Without sorting, the array tail —
// which doctor's conversation_parser_probe_health reports as "latest" —
// was the OLDEST in-window event whenever last week's file had entries.
// Write the two week files directly so the cross-file case is genuinely
// exercised (the writer routes by write time, not event ts).
const now = new Date('2026-07-23T12:00:00Z');
const thisWeekFile = computeParserProbeAuditFilename(now);
const prevWeekFile = computeParserProbeAuditFilename(new Date(now.getTime() - 7 * 86400000));
writeFileSync(join(auditDir, thisWeekFile), [
JSON.stringify(makeEvent({ ts: '2026-07-22T08:00:00Z' })),
JSON.stringify(makeEvent({ ts: '2026-07-23T08:00:00Z' })),
].join('\n') + '\n');
writeFileSync(join(auditDir, prevWeekFile), [
JSON.stringify(makeEvent({ ts: '2026-07-17T08:00:00Z' })),
JSON.stringify(makeEvent({ ts: '2026-07-18T08:00:00Z' })),
].join('\n') + '\n');
const events = readRecentParserProbeEvents(7, now);
expect(events.map(e => e.ts)).toEqual([
'2026-07-17T08:00:00Z',
'2026-07-18T08:00:00Z',
'2026-07-22T08:00:00Z',
'2026-07-23T08:00:00Z',
]);
});
});
describe('parserProbeRanWithin — 24h rate-limit gate', () => {
+33
View File
@@ -298,6 +298,39 @@ describe('computeNightlyQualityProbeHealthCheck — pure doctor branch coverage'
expect(check.message).toMatch(/1 non-PASS run /); // "run " not "runs "
});
test('cross-week ordering: reader sorts chronologically so "Latest" is the newest run', async () => {
// Regression: the reader walks the CURRENT week's file first, then the
// previous week's. Without sorting, the array tail — which this check
// reports as "Latest:" — was the OLDEST in-window event whenever last
// week's file had entries (observed live: counts updated as new runs
// landed while "Latest" stayed pinned days behind).
const { computeQualityProbeAuditFilename, readRecentQualityProbeEvents } =
await import('../src/core/audit-quality-probe.ts');
const { computeNightlyQualityProbeHealthCheck } = await import('../src/commands/doctor.ts');
const now = new Date('2026-07-23T12:00:00Z');
const thisWeekFile = computeQualityProbeAuditFilename(now);
const prevWeekFile = computeQualityProbeAuditFilename(new Date(now.getTime() - 7 * 86400000));
writeFileSync(join(auditTmp, thisWeekFile), [
JSON.stringify({ outcome: 'fail', ts: '2026-07-22T08:00:00Z' }),
JSON.stringify({ outcome: 'fail', ts: '2026-07-23T08:00:00Z' }),
].join('\n') + '\n');
writeFileSync(join(auditTmp, prevWeekFile), [
JSON.stringify({ outcome: 'fail', ts: '2026-07-17T08:00:00Z' }),
JSON.stringify({ outcome: 'fail', ts: '2026-07-18T08:00:00Z' }),
].join('\n') + '\n');
await withEnv({ GBRAIN_AUDIT_DIR: auditTmp }, async () => {
const events = readRecentQualityProbeEvents(7, now);
expect(events.map(e => e.ts)).toEqual([
'2026-07-17T08:00:00Z',
'2026-07-18T08:00:00Z',
'2026-07-22T08:00:00Z',
'2026-07-23T08:00:00Z',
]);
const check = computeNightlyQualityProbeHealthCheck(true, events);
expect(check.message).toContain('Latest: fail at 2026-07-23T08:00:00Z');
});
});
test('single PASS event uses singular grammar', async () => {
const { computeNightlyQualityProbeHealthCheck } = await import('../src/commands/doctor.ts');
const events = [{ outcome: 'pass', ts: '2026-05-22T03:00:00Z' }];