* test(#3314): backfill deterministic clock-seam coverage (failing-first) Replaces loose regex/range assertions with exact-value and boundary tests for the CLI-subprocess and in-process clock-touching call sites identified by H2's audit (epic #3053): cmdCurrentTimestamp, _wsParseRetryAfter (commands.cts), cmdInitManager's is_active gate and cmdInitQuick's quick_id generation (init.cts), and reapStaleTempFiles (io.cts). The CLI-subprocess-pinned tests are expected RED until a follow-up commit routes those call sites through realClock so GSD_TEST_MODE+GSD_NOW_MS can reach them. * refactor(#3314): route CLI-subprocess clock reads through realClock cmdCurrentTimestamp, cmdInitManager's is_active gate, and cmdInitQuick's quick_id generation read Date directly, which the GSD_TEST_MODE+GSD_NOW_MS subprocess pin cannot reach (it only fires inside realClock.now()). Behavior-preserving: realClock.now() falls through to Date.now() whenever GSD_TEST_MODE is unset, which is every real invocation. * docs(#3314): amend ADR-456 with reachability-based clock-control rule ADR-456 §(a) documented one mechanism (injected {clock=Date} + t.mock.timers). Adds the two this repo already relies on: t.mock.timers for in-process direct-Date reads, and the GSD_TEST_MODE+GSD_NOW_MS subprocess pin (routed through realClock) for CLI-spawned code. Updates TESTING-STANDARDS.md's matching passages, which already referenced this issue by number as the no-elapsed-assertion promotion precondition. * fix(#3314): address orthogonal review findings Spec-axis findings: file and link the no-elapsed-assertion promotion follow-up (#3331) instead of leaving TESTING-STANDARDS.md pointing at a dead #1885, and ship the module-by-module audit table in the ADR itself rather than only in a gitignored phase artifact. Standards-axis finding: pin the "hour-old file = not active" test via GSD_TEST_MODE+GSD_NOW_MS for consistency with the reachability rule this PR's own ADR amendment now documents. --------- Co-authored-by: sim <sim@local>
This commit is contained in:
@@ -475,6 +475,69 @@ describe('init manager', () => {
|
||||
assert.ok(output.phases[0].last_activity !== null);
|
||||
});
|
||||
|
||||
test('activity detection: hour-old file = not active', () => {
|
||||
writeState(tmpDir);
|
||||
writeRoadmap(tmpDir, [{ number: '1', name: 'Stale Phase' }]);
|
||||
|
||||
const PINNED_NOW_MS = 1_700_000_000_000; // 2023-11-14T22:13:20.000Z (second-aligned)
|
||||
const phaseDir = scaffoldPhase(tmpDir, 1, { slug: 'stale-phase', context: true });
|
||||
const files = fs.readdirSync(phaseDir);
|
||||
const old = new Date(PINNED_NOW_MS - 60 * 60 * 1000); // 1 hour before the pinned "now"
|
||||
for (const f of files) {
|
||||
fs.utimesSync(path.join(phaseDir, f), old, old);
|
||||
}
|
||||
|
||||
const result = runGsdTools('init manager', tmpDir, {
|
||||
GSD_TEST_MODE: '1', GSD_NOW_MS: String(PINNED_NOW_MS),
|
||||
});
|
||||
const output = JSON.parse(result.output);
|
||||
|
||||
assert.strictEqual(output.phases[0].is_active, false);
|
||||
});
|
||||
|
||||
// #3314 — ADR-456 subprocess clock pin: cmdInitManager's `is_active` gate
|
||||
// (nowMs - newestMtime < 300000) is CLI-subprocess tested, so only the
|
||||
// GSD_TEST_MODE+GSD_NOW_MS pin can control "now" here (t.mock.timers in the
|
||||
// test process cannot reach the spawned child). newestMtime is set via
|
||||
// fs.utimesSync to an exact epoch offset from the pinned "now" so the
|
||||
// 300000ms boundary is provable exactly, not just "roughly recent"/"roughly old".
|
||||
describe('is_active boundary (#3314 — exactly 300000ms, condition is strict <)', () => {
|
||||
const PINNED_NOW_MS = 1_700_000_000_000; // 2023-11-14T22:13:20.000Z (second-aligned)
|
||||
const PIN_ENV = { GSD_TEST_MODE: '1', GSD_NOW_MS: String(PINNED_NOW_MS) };
|
||||
|
||||
function scaffoldWithMtimeOffset(tmpDirLocal, offsetMs) {
|
||||
writeState(tmpDirLocal);
|
||||
writeRoadmap(tmpDirLocal, [{ number: '1', name: 'Boundary Phase' }]);
|
||||
const phaseDir = scaffoldPhase(tmpDirLocal, 1, { slug: 'boundary-phase', context: true });
|
||||
const mtimeMs = PINNED_NOW_MS - offsetMs;
|
||||
const mtimeDate = new Date(mtimeMs);
|
||||
for (const f of fs.readdirSync(phaseDir)) {
|
||||
fs.utimesSync(path.join(phaseDir, f), mtimeDate, mtimeDate);
|
||||
}
|
||||
}
|
||||
|
||||
test('boundary: 299999ms since last activity → is_active true', () => {
|
||||
scaffoldWithMtimeOffset(tmpDir, 299_999);
|
||||
const result = runGsdTools('init manager', tmpDir, PIN_ENV);
|
||||
const output = JSON.parse(result.output);
|
||||
assert.strictEqual(output.phases[0].is_active, true);
|
||||
});
|
||||
|
||||
test('boundary: exactly 300000ms since last activity → is_active false', () => {
|
||||
scaffoldWithMtimeOffset(tmpDir, 300_000);
|
||||
const result = runGsdTools('init manager', tmpDir, PIN_ENV);
|
||||
const output = JSON.parse(result.output);
|
||||
assert.strictEqual(output.phases[0].is_active, false);
|
||||
});
|
||||
|
||||
test('boundary: 300001ms since last activity → is_active false', () => {
|
||||
scaffoldWithMtimeOffset(tmpDir, 300_001);
|
||||
const result = runGsdTools('init manager', tmpDir, PIN_ENV);
|
||||
const output = JSON.parse(result.output);
|
||||
assert.strictEqual(output.phases[0].is_active, false);
|
||||
});
|
||||
});
|
||||
|
||||
test('conflict filter: blocks dependent phase execute when dep is active', () => {
|
||||
writeState(tmpDir);
|
||||
writeRoadmap(tmpDir, [
|
||||
|
||||
Reference in New Issue
Block a user