enhance(#3783): audit-uat summary segments current-milestone vs archived debt (#4336)

* test(#3783): add failing coverage for audit-uat summary segmentation

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(#3783): segment audit-uat summary into current_milestone and archived buckets

Additive: current_milestone/archived are new; total_items, total_files, parse_gap_files, by_phase, and by_category are unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* docs(#3783): add changeset fragment for audit-uat summary segmentation

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* chore(#3783): allowlist the new audit-uat-summary-segmentation test file

lint-test-file-count.cjs baselines the "audit" module (keyed off bin/lib/audit.cjs)
at 6 pre-existing files; this adds the new dedicated suite as a 7th, matching the
module's existing one-file-per-feature-slice precedent.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* test(#3783): fix phase/file number mismatch in the mixed-milestone fixture

The active phase fixture used dir "02-current" with file "01-UAT.md" — a
cross-phase stray per phase-id.cts's isPhaseArtifact/scopeToPhase (#3511),
so the file was silently excluded from the scan and current_milestone read
{files:0, items:0} instead of {files:1, items:1}. Confirmed by direct CLI
run against a hand-built fixture before recommitting. Renamed the file to
02-UAT.md to match its directory's phase number, matching every other
fixture in this suite.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* docs(#3783): backfill changeset PR number to 4336

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: sim <sim@local>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-09-05 19:03:14 -04:00
committed by GitHub
parent f9f72cb54c
commit 0be5bf865a
4 changed files with 281 additions and 1 deletions

View File

@@ -331,6 +331,8 @@ function cmdAuditUat(cwd: string, raw: boolean): void {
parse_gap_files: number;
by_category: Record<string, number>;
by_phase: Record<string, number>;
current_milestone: { files: number; items: number };
archived: { files: number; items: number; by_milestone: Record<string, number> };
} = {
total_files: results.length,
total_items: results.reduce((sum, r) => sum + r.items.length, 0),
@@ -354,9 +356,26 @@ function cmdAuditUat(cwd: string, raw: boolean): void {
parse_gap_files: results.filter((r) => r.parse_gap).length,
by_category: {},
by_phase: {},
// #3783: additive segmentation so a consumer reads one field instead of
// re-deriving the `archived_milestone` filter itself. Deliberately does
// NOT touch total_items/parse_gap_files — see the parse_gap_files
// comment above for why splitting THAT counter by archive status was
// tried and reverted; this is a purely additive pair of new keys.
current_milestone: { files: 0, items: 0 },
archived: { files: 0, items: 0, by_milestone: {} },
};
for (const r of results) {
const resultItemCount = r.items.length;
if (r.archived_milestone) {
summary.archived.files++;
summary.archived.items += resultItemCount;
summary.archived.by_milestone[r.archived_milestone] =
(summary.archived.by_milestone[r.archived_milestone] || 0) + resultItemCount;
} else {
summary.current_milestone.files++;
summary.current_milestone.items += resultItemCount;
}
// Deliberate (#3707 follow-up MINOR): this seeds a `by_phase` key at 0
// even for a parse-gap-only phase whose `items` is empty — do NOT "tidy"
// this away as dead code. The 0-valued key is itself the cue that this