feat(discuss): add discussion manifest for mechanical process verification
Closes the remaining gap in multi-milestone enforcement: the code previously validated only the END STATE (files exist) but not the PROCESS (each gate was presented to the user). New mechanism: - discuss.md instructs the LLM to write .gsd/DISCUSSION-MANIFEST.json after EACH Phase 3 gate decision, tracking gates_completed vs total - checkAutoStartAfterDiscuss() Gate 4: BLOCKS auto-start if gates_completed < total (not just a warning) - Manifest is deleted after auto-start (only needed during discussion) - Single-milestone discussions don't use manifest (backward-compatible) - DISCUSSION-MANIFEST.json added to baseline gitignore patterns This creates a three-layer enforcement: Layer 1 (Prompt): ask_user_questions calls at each gate Layer 2 (Files): CONTEXT.md/DRAFT/directory existence check Layer 3 (Manifest): gates_completed == total process verification Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ccb2a08d67
commit
f27ed34fc0
3 changed files with 57 additions and 0 deletions
|
|
@ -23,6 +23,7 @@ const BASELINE_PATTERNS = [
|
|||
".gsd/metrics.json",
|
||||
".gsd/completed-units.json",
|
||||
".gsd/STATE.md",
|
||||
".gsd/DISCUSSION-MANIFEST.json",
|
||||
|
||||
// ── OS junk ──
|
||||
".DS_Store",
|
||||
|
|
|
|||
|
|
@ -88,6 +88,38 @@ export function checkAutoStartAfterDiscuss(): boolean {
|
|||
} catch { /* non-fatal — PROJECT.md parsing failure shouldn't block auto-start */ }
|
||||
}
|
||||
|
||||
// Gate 4: Discussion manifest process verification (multi-milestone only)
|
||||
// The LLM writes DISCUSSION-MANIFEST.json after each Phase 3 gate decision.
|
||||
// If the manifest exists but gates_completed < total, the LLM hasn't finished
|
||||
// presenting all readiness gates to the user — block auto-start.
|
||||
const manifestPath = join(basePath, ".gsd", "DISCUSSION-MANIFEST.json");
|
||||
if (existsSync(manifestPath)) {
|
||||
try {
|
||||
const manifest = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
||||
const total = typeof manifest.total === "number" ? manifest.total : 0;
|
||||
const completed = typeof manifest.gates_completed === "number" ? manifest.gates_completed : 0;
|
||||
|
||||
if (total > 1 && completed < total) {
|
||||
// Discussion not complete — block auto-start until all gates are done
|
||||
return false;
|
||||
}
|
||||
|
||||
// Cross-check manifest milestones against PROJECT.md if available
|
||||
if (projectFile) {
|
||||
const projectContent = readFileSync(projectFile, "utf-8");
|
||||
const projectIds = parseMilestoneSequenceFromProject(projectContent);
|
||||
const manifestIds = Object.keys(manifest.milestones ?? {});
|
||||
const untracked = projectIds.filter(id => !manifestIds.includes(id));
|
||||
if (untracked.length > 0) {
|
||||
ctx.ui.notify(
|
||||
`Discussion manifest missing gates for: ${untracked.join(", ")}`,
|
||||
"warning",
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch { /* malformed manifest — warn but don't block */ }
|
||||
}
|
||||
|
||||
// Draft promotion cleanup: if a CONTEXT-DRAFT.md exists alongside the new
|
||||
// CONTEXT.md, delete the draft — it's been consumed by the discussion.
|
||||
try {
|
||||
|
|
@ -95,6 +127,9 @@ export function checkAutoStartAfterDiscuss(): boolean {
|
|||
if (draftFile) unlinkSync(draftFile);
|
||||
} catch { /* non-fatal — stale draft doesn't break anything, CONTEXT.md wins */ }
|
||||
|
||||
// Cleanup: remove discussion manifest after auto-start (only needed during discussion)
|
||||
try { unlinkSync(manifestPath); } catch { /* may not exist for single-milestone */ }
|
||||
|
||||
pendingAutoStart = null;
|
||||
startAuto(ctx, pi, basePath, false, { step }).catch(() => {});
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -227,6 +227,27 @@ For each remaining milestone **one at a time, in sequence**, use `ask_user_quest
|
|||
|
||||
Each context file (full or draft) should be rich enough that a future agent encountering it fresh — with no memory of this conversation — can understand the intent, constraints, dependencies, what this milestone unlocks, and what "done" looks like.
|
||||
|
||||
#### Milestone Gate Tracking (MANDATORY for multi-milestone)
|
||||
|
||||
After EVERY Phase 3 gate decision, immediately write or update `.gsd/DISCUSSION-MANIFEST.json` with the cumulative state. This file is mechanically validated by the system before auto-mode starts — if gates are incomplete, auto-mode will NOT start.
|
||||
|
||||
```json
|
||||
{
|
||||
"primary": "M001",
|
||||
"milestones": {
|
||||
"M001": { "gate": "discussed", "context": "full" },
|
||||
"M002": { "gate": "discussed", "context": "full" },
|
||||
"M003": { "gate": "queued", "context": "none" }
|
||||
},
|
||||
"total": 3,
|
||||
"gates_completed": 3
|
||||
}
|
||||
```
|
||||
|
||||
Write this file AFTER each gate decision, not just at the end. Update `gates_completed` incrementally. The system reads this file and BLOCKS auto-start if `gates_completed < total`.
|
||||
|
||||
For single-milestone projects, do NOT write this file — it is only for multi-milestone discussions.
|
||||
|
||||
#### Phase 4: Finalize
|
||||
|
||||
7. Update `.gsd/STATE.md`
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue