refactor(#2128): single-source 23 phase-token re-derivations; sanction 14 context-specific sites

Route 23 literal re-derivations of the canonical phase-number token through
phase-id.cjs `PHASE_NUMBER_TOKEN_SOURCE` (via new RegExp). Each conversion was
proven BYTE-IDENTICAL (old.source === new.source && old.flags === new.flags), so
the runtime regexes are unchanged — zero behavior change by construction.

The remaining 14 phase-token sites are genuine but context-specific and stay
literal with a `// phase-id-owner: <reason>` sanction: dir-name parses whose
dash-continuation semantics differ from extractPhaseToken, and the [A-Za-z]
case-variant / [.-] dot-or-dash separator forms that are not source-byte-equal
to the canonical token.

Scanner (`npm run check:phase-id-drift`) is now green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-07-10 08:49:36 -04:00
parent 09be501eb7
commit dfad3a7510
12 changed files with 60 additions and 30 deletions

View File

@@ -33,7 +33,7 @@
// eslint-disable-next-line @typescript-eslint/no-require-imports
import phaseIdMod = require('./phase-id.cjs');
const { OPTIONAL_PROJECT_CODE_PREFIX_SOURCE } = phaseIdMod;
const { OPTIONAL_PROJECT_CODE_PREFIX_SOURCE, PHASE_NUMBER_TOKEN_SOURCE } = phaseIdMod;
// ── Issue #26: regex constants (W005, W006-archived) ────────────────────────
// Matches legacy numeric dirs (01-setup), milestone-prefixed dirs (02-01-setup),
@@ -62,7 +62,7 @@ export function canonicalPlanStem(stem: string): string {
// #2043: the plan component (after the phase number) must be zero-padded
// (≥2 digits), so a digit-leading slug word (e.g. "46-6-rs-…") is not mistaken
// for a "46-6" phase/plan pair.
const m = stem.match(/^(\d+[A-Z]?(?:\.\d+)*-\d{2,})/i);
const m = stem.match(new RegExp(`^(${PHASE_NUMBER_TOKEN_SOURCE}-\\d{2,})`, 'i'));
return m ? m[1] : stem;
}