* test(#3685): failing-first regression coverage for phase-complete write flags `phase complete` reports `roadmap_updated`/`state_updated` from `fs.existsSync(path)`, so both read `true` whenever the file merely exists — including when the transaction wrote nothing. Add the regression tests that prove it, plus the negative-space and true-direction pins, before the fix. New in tests/phase.test.cjs: - roadmap_updated is false when the transaction rewrites nothing (FAILS today) - state_updated is false when the transaction rewrites nothing, and stays false on a third consecutive run (FAILS today) - both flags are true when the transaction genuinely rewrites (pins the true direction so the fix cannot be tightened into always-false) - each flag stays false when its file is absent The STATE.md cases pin the clock via GSD_TEST_MODE + GSD_NOW_MS (src/clock.cts:43-70) because syncStateFrontmatter stamps a millisecond-resolution `last_updated:` on every write, which would otherwise make the no-op unobservable. Also strengthens four pre-existing `=== true` assertions on these fields that passed vacuously: each now pairs the flag assertion with a content-changed assertion against a pre-call snapshot, so the `true` is earned. Refs #3685 * fix(#3685): report phase-complete write flags from the transaction, not the filesystem `phase complete` computed `roadmap_updated` and `state_updated` as `fs.existsSync(path)`, so both read `true` for any project that had the file at all — including a run that rewrote nothing. The flags are the only signal a caller has that the rollup landed, so a no-op was indistinguishable from a successful write and a stale ROADMAP went unnoticed until something downstream read wrong numbers. Both flags now reflect whether that file's content actually changed in the transaction, computed at the existing `writes.push({filePath, before, after})` sites — the same contract `requirements_updated` has honored since #2316-3, and the same correction #2640/#2974 already applied to `phase remove`. Nothing about what gets written changes; only what gets reported. Fixes #3685 * chore(changeset): backfill PR number for #3685 fragment --------- Co-authored-by: sim <sim@local>
This commit is contained in:
@@ -2261,6 +2261,12 @@ function cmdPhaseComplete(cwd: string, phaseNum: string, raw: boolean): void {
|
||||
? (phaseInfo['summaries'] as string[]).length
|
||||
: 0;
|
||||
let requirementsUpdated = false;
|
||||
// #3685: mirror requirementsUpdated's diff-tracking contract at the
|
||||
// writes.push({filePath, before, after}) sites below, rather than
|
||||
// reporting via fs.existsSync (which is true whenever the file merely
|
||||
// exists, not when the transaction actually wrote a change).
|
||||
let roadmapUpdated = false;
|
||||
let stateUpdated = false;
|
||||
|
||||
const warnings: string[] = [];
|
||||
// ADR-3408 §8.5 / D2 (#3374): "liberal but visible" — when the write-seam
|
||||
@@ -2680,6 +2686,7 @@ function cmdPhaseComplete(cwd: string, phaseNum: string, raw: boolean): void {
|
||||
before: originalRoadmapContent,
|
||||
after: roadmapContent,
|
||||
});
|
||||
roadmapUpdated = roadmapContent !== originalRoadmapContent;
|
||||
|
||||
const reqPath = path.join(planningDir(cwd), 'REQUIREMENTS.md');
|
||||
if (fs.existsSync(reqPath)) {
|
||||
@@ -3253,6 +3260,7 @@ function cmdPhaseComplete(cwd: string, phaseNum: string, raw: boolean): void {
|
||||
}
|
||||
|
||||
writes.push({ filePath: statePath, before: originalStateContent, after: stateContent });
|
||||
stateUpdated = stateContent !== originalStateContent;
|
||||
}
|
||||
|
||||
anyPlanningWrite = writePlanningFileSet(writes) > 0;
|
||||
@@ -3319,8 +3327,8 @@ function cmdPhaseComplete(cwd: string, phaseNum: string, raw: boolean): void {
|
||||
next_phase_name: nextPhaseName,
|
||||
is_last_phase: isLastPhase,
|
||||
date: today,
|
||||
roadmap_updated: fs.existsSync(roadmapPath),
|
||||
state_updated: fs.existsSync(statePath),
|
||||
roadmap_updated: roadmapUpdated,
|
||||
state_updated: stateUpdated,
|
||||
requirements_updated: requirementsUpdated,
|
||||
auto_pruned: autoPruned,
|
||||
warnings,
|
||||
|
||||
Reference in New Issue
Block a user