* test(#3641): failing-first bracket-window validate rows * fix(#3641): thread phase convention into hasphaseentries for v004/v005 * test(#3641): review rows - digit-anchor, decoy, probe parity, t.after * fix(#3641): digit-anchor bracket entry token; thread probe scope axis * fix(#3641): align frontmatter bound with probe; changeset * chore(#3641): backfill changeset pr number --------- Co-authored-by: sim <sim@local>
This commit is contained in:
@@ -34,6 +34,11 @@ import { platformWriteSync } from './shell-command-projection.cjs';
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
import planningWorkspace = require('./planning-workspace.cjs');
|
||||
const { planningPaths, withPlanningLock, findContextMdIn } = planningWorkspace;
|
||||
// #3641: milestone-scope's convention resolution reads the project config
|
||||
// (no cycle — config-loader does not import this module).
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
import configLoaderForScope = require('./config-loader.cjs');
|
||||
const { loadConfig: loadConfigForScope } = configLoaderForScope;
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
import scanPhasePlans = require('./plan-scan.cjs');
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
@@ -707,7 +712,35 @@ function cmdRoadmapMilestoneScope(cwd: string, raw: boolean): void {
|
||||
}
|
||||
|
||||
const rawContent = fs.readFileSync(roadmapPath, 'utf-8');
|
||||
const { value: window, scope } = extractCurrentMilestoneScoped(rawContent, cwd);
|
||||
// #3641: resolve phase_id_convention and thread it into the scope axis, so
|
||||
// this probe and `roadmap validate`'s V005 answer the SAME question the
|
||||
// SAME way for a bracket-convention project — a window the classifier
|
||||
// calls TRUNCATED in validate must never read COMPLETE here (the #3262
|
||||
// capture/compare guard consumes this scope). Resolution mirrors the
|
||||
// validate router's: .planning/config.json first, ROADMAP.md frontmatter
|
||||
// as fallback.
|
||||
let phaseIdConvention: string | undefined | null;
|
||||
try {
|
||||
const cfg = loadConfigForScope(cwd);
|
||||
phaseIdConvention = cfg['phase_id_convention'] as string | undefined | null;
|
||||
} catch {
|
||||
phaseIdConvention = undefined;
|
||||
}
|
||||
if (phaseIdConvention === undefined || phaseIdConvention === null) {
|
||||
// Bounded per local/no-unbounded-quantifier (#2128): frontmatter is a
|
||||
// short header block — 4KB is orders of magnitude beyond any real one.
|
||||
const fmMatch = rawContent.match(/^---\r?\n([\s\S]{0,4000}?)\r?\n---/);
|
||||
if (fmMatch) {
|
||||
const kvMatch = fmMatch[1].match(/^phase_id_convention:\s*(.*)$/m);
|
||||
if (kvMatch) {
|
||||
const val = kvMatch[1].trim();
|
||||
if (val !== 'null' && val !== '') {
|
||||
phaseIdConvention = val.replace(/^["']|["']$/g, '');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const { value: window, scope } = extractCurrentMilestoneScoped(rawContent, cwd, undefined, phaseIdConvention);
|
||||
// Document order (Set insertion order) — deterministic for a given document.
|
||||
const phases = [...scanMilestonePhaseIds(window)];
|
||||
output({ scope, phases, phase_count: phases.length }, raw, undefined);
|
||||
|
||||
Reference in New Issue
Block a user