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:
@@ -16,7 +16,7 @@ import configLoaderMod = require('./config-loader.cjs');
|
||||
const { loadConfig } = configLoaderMod;
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
import phaseIdMod = require('./phase-id.cjs');
|
||||
const { escapeRegex, normalizePhaseName, extractPhaseToken, parsePhaseFromProse } = phaseIdMod;
|
||||
const { escapeRegex, normalizePhaseName, extractPhaseToken, parsePhaseFromProse, PHASE_NUMBER_TOKEN_SOURCE } = phaseIdMod;
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
import roadmapParserMod = require('./roadmap-parser.cjs');
|
||||
const { getMilestoneInfo, getMilestonePhaseFilter, extractCurrentMilestone } = roadmapParserMod;
|
||||
@@ -1406,6 +1406,7 @@ function buildStateFrontmatter(bodyContent: string, cwd: string | undefined): Re
|
||||
// neither the denominator nor the numerator (mirrors the heading
|
||||
// exclusion below). Project-code-aware via phaseKeyFromDir.
|
||||
if (retiredPhaseNums.size > 0 && retiredPhaseNums.has(phaseKeyFromDir(dir))) continue;
|
||||
// phase-id-owner: dir-name dedup grouping; diverges from extractPhaseToken/phaseKeyFromDir on project-code-prefixed and multi-segment milestone dirs. Kept local.
|
||||
const m = dir.match(/^0*(\d+[A-Za-z]?(?:\.\d+)*)/);
|
||||
const key = m ? m[1].toLowerCase() : dir;
|
||||
if (!seenPhaseNums.has(key)) {
|
||||
@@ -2394,7 +2395,7 @@ function cmdStateSync(cwd: string, options: StateSyncOptions | undefined, raw: b
|
||||
if (completed) diskCompletedPhases++;
|
||||
|
||||
// Track the highest phase with incomplete plans (or any plans)
|
||||
const phaseMatch = dir.match(/^(\d+[A-Z]?(?:\.\d+)*)/i);
|
||||
const phaseMatch = dir.match(new RegExp(`^(${PHASE_NUMBER_TOKEN_SOURCE})`, 'i'));
|
||||
if (phaseMatch && plans > 0) {
|
||||
if (summaries < plans) {
|
||||
// Incomplete phase — this is likely the current one
|
||||
|
||||
Reference in New Issue
Block a user