fix(#2012): scope phase.complete Progress-row regex to ## Progress section (#2032)

* fix(#2012): scope Progress-row regex to ## Progress section (was binding to earlier table)

The Progress-row writer used a non-global regex that matched ANY table row
starting with the phase number. When an earlier table (e.g. Requirements
coverage | Phase | Requirements | Count |) preceded ## Progress, the regex
bound to the wrong row (3-column), no-op'd, and never reached the real
Progress row. roadmap_updated stayed true (it's existsSync), masking the
failure.

- src/phase.cts: scope the tableRowPattern regex to the ## Progress section
  (indexOf + slice) so it only matches Progress-table rows.
- tests/phase.test.cjs: regression test — ROADMAP with a phase-numbered
  Requirements table before ## Progress → Progress row updated, Requirements
  row untouched.

Closes #2012

* docs(#2012): backfill changeset pr 2032
This commit is contained in:
Tom Boucher
2026-07-05 17:39:11 -04:00
committed by GitHub
parent 460956bfed
commit f77179248d
3 changed files with 65 additions and 2 deletions

View File

@@ -1460,7 +1460,10 @@ function cmdPhaseComplete(cwd: string, phaseNum: string, raw: boolean): void {
`^(\\|\\s*${phaseEscaped}\\.?\\s[^|]*(?:\\|[^\\n]*))$`,
'im',
);
roadmapContent = roadmapContent.replace(tableRowPattern, (fullRow) => {
// Scope the Progress-row search to the ## Progress section so the regex
// doesn't bind to an earlier table (e.g. | Phase | Requirements | Count |)
// whose rows also start with the phase number. (#2012)
const updateProgressRow = (fullRow: string): string => {
const cells = fullRow.split('|').slice(1, -1);
const dateShape = /^\d{4}-\d{2}-\d{2}$/;
if (cells.length === 5) {
@@ -1477,7 +1480,15 @@ function cmdPhaseComplete(cwd: string, phaseNum: string, raw: boolean): void {
cells[3] = dateShape.test(existingDate4) ? cells[3] : ` ${today} `;
}
return '|' + cells.join('|') + '|';
});
};
const progressIdx = roadmapContent.indexOf('## Progress');
if (progressIdx >= 0) {
const beforeProgress = roadmapContent.slice(0, progressIdx);
const progressSection = roadmapContent.slice(progressIdx);
roadmapContent = beforeProgress + progressSection.replace(tableRowPattern, updateProgressRow);
} else {
roadmapContent = roadmapContent.replace(tableRowPattern, updateProgressRow);
}
const planCountPattern = new RegExp(
`(#{2,4}\\s*Phase\\s+${phaseEscaped}[\\s\\S]*?\\*\\*Plans:\\*\\*\\s*)[^\\n]+`,