fix(#4731): read hard-wrapped Goal/Requirements fields past the line break (#4826)

admin_reason: missing-secondary-reviewer — self-authored overnight sweep; isolated adversarial review round completed (MEDIUM table-bleed finding fixed with RED/GREEN evidence) and sha-pinned bench 46331/0 on the merged head.
This commit is contained in:
Tom Boucher
2026-09-17 15:59:38 -04:00
committed by GitHub
parent fb3e228a0d
commit bff99a8bb5
7 changed files with 279 additions and 21 deletions

View File

@@ -141,7 +141,6 @@ const { resolveCapabilityRuntimeState } = capabilityStateMod;
void stripShippedMilestones;
// Accept all bold/colon variants of the Requirements header (#2769)
const REQUIREMENTS_HEADER_RE = /^\*\*Requirements:?\*\*[^\S\n]*:?[^\S\n]*([^\n]*)$/m;
// #2056/#2104: isForeignPrefixedPhaseQuery is imported from phase-id.cts
// (the canonical predicate). parsePhasePrefix is no longer needed locally.
@@ -939,9 +938,14 @@ function cmdInitExecutePhase(
has_reviews: false,
};
});
const reqMatch = (roadmapPhase?.['section'] as string | undefined)?.match(REQUIREMENTS_HEADER_RE);
const reqExtracted = reqMatch
? reqMatch[1].replace(/[\[\]]/g, '').split(',').map((s) => s.trim()).filter(Boolean).join(', ')
// #4731: multiline-aware — the Requirements field may hard-wrap, so the
// value is extracted past the line break before the ID scan.
const phaseSection = roadmapPhase?.['section'] as string | undefined;
const reqLine = phaseSection
? roadmapParser.extractPhaseFieldMultiline(phaseSection, 'Requirements')
: null;
const reqExtracted = reqLine
? reqLine.replace(/[\[\]]/g, '').split(',').map((s) => s.trim()).filter(Boolean).join(', ')
: null;
const phase_req_ids = reqExtracted && reqExtracted !== 'TBD' ? reqExtracted : null;
@@ -1109,9 +1113,14 @@ function cmdInitPlanPhase(
has_reviews: false,
};
});
const reqMatch = (roadmapPhase?.['section'] as string | undefined)?.match(REQUIREMENTS_HEADER_RE);
const reqExtracted = reqMatch
? reqMatch[1].replace(/[\[\]]/g, '').split(',').map((s) => s.trim()).filter(Boolean).join(', ')
// #4731: multiline-aware — the Requirements field may hard-wrap, so the
// value is extracted past the line break before the ID scan.
const phaseSection = roadmapPhase?.['section'] as string | undefined;
const reqLine = phaseSection
? roadmapParser.extractPhaseFieldMultiline(phaseSection, 'Requirements')
: null;
const reqExtracted = reqLine
? reqLine.replace(/[\[\]]/g, '').split(',').map((s) => s.trim()).filter(Boolean).join(', ')
: null;
const phase_req_ids = reqExtracted && reqExtracted !== 'TBD' ? reqExtracted : null;
@@ -2841,8 +2850,7 @@ function cmdInitManager(cwd: string, raw: boolean): void {
: content.length;
const section = content.slice(sectionStart, sectionEnd);
const goalMatch = section.match(/\*\*Goal(?::\*\*|\*\*:)\s*([^\n]+)/i);
const goal = goalMatch ? goalMatch[1].trim() : null;
const goal = roadmapParser.extractPhaseFieldMultiline(section, 'Goal');
const dependsMatch = section.match(/\*\*Depends on(?::\*\*|\*\*:)\s*([^\n]+)/i);
const depends_on = dependsMatch ? dependsMatch[1].trim() : null;