enhance(#2142): archive quick tasks at milestone close-out (#3592)

* test(#2142): failing-first coverage for quick-task archival at milestone close-out

* enhance(#2142): archive quick tasks at milestone close-out

* fix(#2142): resolve review findings — readme injection, move/reset ordering, owned state write

* fix(#2142): fold archival under milestone namespace, expose index IR, dedupe reset decision

* test(#2142): assert archive-dir-relative summary path in index IR

* docs(#2142): backfill changeset pr number to 3592

* test(#2142): skip newline-fixture injection test on windows (control chars illegal in path names)

---------

Co-authored-by: sim <sim@local>
This commit is contained in:
Tom Boucher
2026-08-17 14:51:00 -04:00
committed by GitHub
parent b08af152e4
commit 98ecb2ba8c
18 changed files with 1776 additions and 22 deletions

View File

@@ -3,7 +3,7 @@ const assert = require('node:assert/strict');
const fs = require('fs');
const os = require('os');
const path = require('path');
const { cleanup } = require('./helpers.cjs');
const { cleanup, toPosixPath } = require('./helpers.cjs');
const { makeFakeClock } = require('./helpers/clock.cjs');
const planningWorkspaceDirect = require('../gsd-core/bin/lib/planning-workspace.cjs');
@@ -654,3 +654,43 @@ describe('bug #1883 — findContextMdIn distinguishes a permission error from em
'array path returns null when no match');
});
});
// ─────────────────────────────────────────────────────────────────────────────
// #2142: quick task workspace path (planningPaths().quick)
// ─────────────────────────────────────────────────────────────────────────────
describe('#2142: quick task workspace path (planningPaths().quick)', () => {
const cwd = '/fake/repo';
let savedProject;
let savedWorkstream;
beforeEach(() => {
savedProject = process.env.GSD_PROJECT;
savedWorkstream = process.env.GSD_WORKSTREAM;
delete process.env.GSD_PROJECT;
delete process.env.GSD_WORKSTREAM;
});
afterEach(() => {
if (savedProject !== undefined) process.env.GSD_PROJECT = savedProject;
else delete process.env.GSD_PROJECT;
if (savedWorkstream !== undefined) process.env.GSD_WORKSTREAM = savedWorkstream;
else delete process.env.GSD_WORKSTREAM;
});
test('exposesQuickDirectoryPath: planningPaths(cwd).quick ends with .planning/quick', () => {
const paths = planningPaths(cwd, null);
assert.strictEqual(toPosixPath(paths.quick), toPosixPath(path.join(cwd, '.planning', 'quick')));
assert.ok(toPosixPath(paths.quick).endsWith('.planning/quick'));
});
test('resolvesQuickPathUnderWorkstream: quick resolves under the workstream base like phases', () => {
const paths = planningPaths(cwd, 'feature-x');
assert.strictEqual(
toPosixPath(paths.quick),
toPosixPath(path.join(cwd, '.planning', 'workstreams', 'feature-x', 'quick')),
);
// Same parent directory as `phases` — quick is workstream-aware exactly like phases.
assert.strictEqual(path.dirname(paths.quick), path.dirname(paths.phases));
});
});