Merge pull request #3669 from Tibsfox/fix/find-missing-summaries-skip-closed
fix(gsd): exclude closed slices from findMissingSummaries check
This commit is contained in:
commit
f8c5a9c6ee
3 changed files with 65 additions and 7 deletions
|
|
@ -93,14 +93,22 @@ function missingSliceStop(mid: string, phase: string): DispatchAction {
|
|||
/**
|
||||
* Check for milestone slices missing SUMMARY files.
|
||||
* Returns array of missing slice IDs, or empty array if all present or DB unavailable.
|
||||
*
|
||||
* Excludes skipped slices (intentionally summary-less) and legacy-complete
|
||||
* slices whose DB status is authoritative even without on-disk SUMMARY (#3620).
|
||||
*/
|
||||
function findMissingSummaries(basePath: string, mid: string): string[] {
|
||||
if (!isDbAvailable()) return [];
|
||||
const sliceIds = getMilestoneSlices(mid).map(s => s.id);
|
||||
return sliceIds.filter(sid => {
|
||||
const summaryPath = resolveSliceFile(basePath, mid, sid, "SUMMARY");
|
||||
return !summaryPath || !existsSync(summaryPath);
|
||||
});
|
||||
const slices = getMilestoneSlices(mid);
|
||||
// Skipped slices never produce SUMMARYs; legacy-complete slices may lack them
|
||||
const CLOSED_STATUSES = new Set(["skipped", "complete", "done"]);
|
||||
return slices
|
||||
.filter(s => !CLOSED_STATUSES.has(s.status))
|
||||
.filter(s => {
|
||||
const summaryPath = resolveSliceFile(basePath, mid, s.id, "SUMMARY");
|
||||
return !summaryPath || !existsSync(summaryPath);
|
||||
})
|
||||
.map(s => s.id);
|
||||
}
|
||||
|
||||
// ─── Rewrite Circuit Breaker ──────────────────────────────────────────────
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* Regression test for #3669 — findMissingSummaries skips closed slices
|
||||
*
|
||||
* When a slice has status "skipped", "complete", or "done", it should be
|
||||
* excluded from the missing-summary check because closed slices intentionally
|
||||
* lack SUMMARY files (or their DB status is authoritative).
|
||||
*
|
||||
* This is a structural verification test — it reads the source to confirm the
|
||||
* CLOSED_STATUSES guard exists at the filter site.
|
||||
*/
|
||||
|
||||
import { describe, test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname, join } from 'node:path';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
const source = readFileSync(join(__dirname, '..', 'auto-dispatch.ts'), 'utf-8');
|
||||
|
||||
describe('findMissingSummaries closed-status exclusion (#3669)', () => {
|
||||
test('CLOSED_STATUSES set includes skipped, complete, and done', () => {
|
||||
// The source must define a CLOSED_STATUSES set with all three statuses
|
||||
assert.match(source, /CLOSED_STATUSES.*=.*new Set\(/,
|
||||
'CLOSED_STATUSES set should be defined');
|
||||
assert.match(source, /"skipped"/, 'CLOSED_STATUSES should include "skipped"');
|
||||
assert.match(source, /"complete"/, 'CLOSED_STATUSES should include "complete"');
|
||||
assert.match(source, /"done"/, 'CLOSED_STATUSES should include "done"');
|
||||
});
|
||||
|
||||
test('filter uses CLOSED_STATUSES.has() to exclude closed slices', () => {
|
||||
assert.match(source, /CLOSED_STATUSES\.has\(s\.status\)/,
|
||||
'filter should call CLOSED_STATUSES.has(s.status)');
|
||||
});
|
||||
|
||||
test('findMissingSummaries function exists', () => {
|
||||
assert.match(source, /function findMissingSummaries\(/,
|
||||
'findMissingSummaries function should be defined');
|
||||
});
|
||||
|
||||
test('filter is negated (excludes closed, keeps open)', () => {
|
||||
// The filter should use !CLOSED_STATUSES.has() to exclude closed slices
|
||||
assert.match(source, /!CLOSED_STATUSES\.has\(s\.status\)/,
|
||||
'filter should negate CLOSED_STATUSES.has() to exclude closed slices');
|
||||
});
|
||||
});
|
||||
|
|
@ -920,8 +920,10 @@ describe("completion and verification failures", () => {
|
|||
base = createFullFixture();
|
||||
openDatabase(join(base, ".gsd", "gsd.db"));
|
||||
insertMilestone({ id: "M001", title: "Active", status: "active" });
|
||||
insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "complete" });
|
||||
insertSlice({ id: "S02", milestoneId: "M001", title: "Second", status: "complete" });
|
||||
// Use "pending" status — closed slices (complete/done/skipped) are
|
||||
// excluded from SUMMARY checks per #3620.
|
||||
insertSlice({ id: "S01", milestoneId: "M001", title: "First", status: "pending" });
|
||||
insertSlice({ id: "S02", milestoneId: "M001", title: "Second", status: "pending" });
|
||||
// No S01-SUMMARY.md or S02-SUMMARY.md on disk
|
||||
|
||||
const ctx = buildDispatchCtx(base, "M001", {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue