@garygentry/feature-forge 0.3.2 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/adapters/claude/.feature-forge-bundle.json +1 -1
- package/adapters/claude/agents/forge-verifier.md +3 -1
- package/adapters/claude/references/decisions/single-writer-threat-model.md +53 -0
- package/adapters/claude/references/epic-state-schema.json +50 -0
- package/adapters/claude/references/forge-config-schema.json +18 -0
- package/adapters/claude/references/forge-decisions-schema.json +33 -0
- package/adapters/claude/references/pipeline-state-schema.json +34 -2
- package/adapters/claude/references/ralph-loop-contract.md +6 -3
- package/adapters/claude/references/shared-conventions.md +15 -4
- package/adapters/claude/references/stage-exit-protocol.md +55 -11
- package/adapters/claude/scripts/epic-manifest.py +82 -4
- package/adapters/claude/scripts/fix-sweep.py +1180 -0
- package/adapters/claude/scripts/forge-session.py +1124 -26
- package/adapters/claude/skills/forge/SKILL.md +5 -5
- package/adapters/claude/skills/forge/references/pipeline-state-schema.json +34 -2
- package/adapters/claude/skills/forge/references/shared-conventions.md +15 -4
- package/adapters/claude/skills/forge/references/stage-exit-protocol.md +55 -11
- package/adapters/claude/skills/forge-0-epic/references/edit-mode.md +5 -1
- package/adapters/claude/skills/forge-0-epic/references/epic-manifest-subcommands.md +5 -0
- package/adapters/claude/skills/forge-0-epic/references/pipeline-state-schema.json +34 -2
- package/adapters/claude/skills/forge-0-epic/references/shared-conventions.md +15 -4
- package/adapters/claude/skills/forge-0-epic/references/stage-exit-protocol.md +55 -11
- package/adapters/claude/skills/forge-1-prd/SKILL.md +3 -1
- package/adapters/claude/skills/forge-1-prd/references/shared-conventions.md +15 -4
- package/adapters/claude/skills/forge-1-prd/references/stage-exit-protocol.md +55 -11
- package/adapters/claude/skills/forge-2-tech/SKILL.md +5 -1
- package/adapters/claude/skills/forge-2-tech/references/shared-conventions.md +15 -4
- package/adapters/claude/skills/forge-2-tech/references/stage-exit-protocol.md +55 -11
- package/adapters/claude/skills/forge-3-specs/SKILL.md +5 -1
- package/adapters/claude/skills/forge-3-specs/references/shared-conventions.md +15 -4
- package/adapters/claude/skills/forge-3-specs/references/stage-exit-protocol.md +55 -11
- package/adapters/claude/skills/forge-4-backlog/SKILL.md +41 -3
- package/adapters/claude/skills/forge-4-backlog/references/shared-conventions.md +15 -4
- package/adapters/claude/skills/forge-4-backlog/references/stage-exit-protocol.md +55 -11
- package/adapters/claude/skills/forge-5-loop/SKILL.md +36 -36
- package/adapters/claude/skills/forge-5-loop/references/agent-selection.md +16 -0
- package/adapters/claude/skills/forge-5-loop/references/ralph-loop-contract.md +6 -3
- package/adapters/claude/skills/forge-5-loop/references/recovery-procedure.md +349 -0
- package/adapters/claude/skills/forge-5-loop/references/result-reporting.md +40 -11
- package/adapters/claude/skills/forge-5-loop/references/runner-contract.md +22 -4
- package/adapters/claude/skills/forge-5-loop/references/shared-conventions.md +15 -4
- package/adapters/claude/skills/forge-5-loop/references/stage-exit-protocol.md +55 -11
- package/adapters/claude/skills/forge-6-docs/SKILL.md +29 -6
- package/adapters/claude/skills/forge-6-docs/references/shared-conventions.md +15 -4
- package/adapters/claude/skills/forge-6-docs/references/stage-exit-protocol.md +55 -11
- package/adapters/claude/skills/forge-fix/SKILL.md +34 -0
- package/adapters/claude/skills/forge-fix/references/shared-conventions.md +15 -4
- package/adapters/claude/skills/forge-fix/references/stage-exit-protocol.md +55 -11
- package/adapters/claude/skills/forge-guide/references/forge-config-schema.json +18 -0
- package/adapters/claude/skills/forge-guide/references/ralph-loop-contract.md +6 -3
- package/adapters/claude/skills/forge-guide/references/shared-conventions.md +15 -4
- package/adapters/claude/skills/forge-verify/SKILL.md +10 -11
- package/adapters/claude/skills/forge-verify/references/decisions/single-writer-threat-model.md +53 -0
- package/adapters/claude/skills/forge-verify/references/findings-template.md +30 -0
- package/adapters/claude/skills/forge-verify/references/shared-conventions.md +15 -4
- package/adapters/claude/skills/forge-verify/references/stage-exit-protocol.md +55 -11
- package/adapters/claude/skills/forge-verify/references/verification-checklists/backlog.md +73 -0
- package/adapters/claude/skills/forge-verify/references/verification-checklists/impl.md +85 -0
- package/adapters/claude/skills/forge-verify/references/verification-checklists/specs.md +43 -1
- package/adapters/codex/.feature-forge-bundle.json +1 -1
- package/adapters/codex/agents/forge-verifier.toml +3 -1
- package/adapters/codex/references/decisions/single-writer-threat-model.md +53 -0
- package/adapters/codex/references/epic-state-schema.json +50 -0
- package/adapters/codex/references/forge-config-schema.json +18 -0
- package/adapters/codex/references/forge-decisions-schema.json +33 -0
- package/adapters/codex/references/pipeline-state-schema.json +34 -2
- package/adapters/codex/references/process-overview.md +2 -2
- package/adapters/codex/references/ralph-loop-contract.md +6 -3
- package/adapters/codex/references/shared-conventions.md +44 -33
- package/adapters/codex/references/stage-exit-protocol.md +64 -20
- package/adapters/codex/scripts/epic-manifest.py +82 -4
- package/adapters/codex/scripts/fix-sweep.py +1180 -0
- package/adapters/codex/scripts/forge-session.py +1124 -26
- package/adapters/codex/skills/forge/SKILL.md +8 -8
- package/adapters/codex/skills/forge/references/pipeline-state-schema.json +34 -2
- package/adapters/codex/skills/forge/references/process-overview.md +2 -2
- package/adapters/codex/skills/forge/references/shared-conventions.md +44 -33
- package/adapters/codex/skills/forge/references/stage-exit-protocol.md +64 -20
- package/adapters/codex/skills/forge-0-epic/references/edit-mode.md +14 -10
- package/adapters/codex/skills/forge-0-epic/references/epic-manifest-subcommands.md +8 -3
- package/adapters/codex/skills/forge-0-epic/references/pipeline-state-schema.json +34 -2
- package/adapters/codex/skills/forge-0-epic/references/shared-conventions.md +44 -33
- package/adapters/codex/skills/forge-0-epic/references/stage-exit-protocol.md +64 -20
- package/adapters/codex/skills/forge-1-prd/SKILL.md +3 -1
- package/adapters/codex/skills/forge-1-prd/references/shared-conventions.md +44 -33
- package/adapters/codex/skills/forge-1-prd/references/stage-exit-protocol.md +64 -20
- package/adapters/codex/skills/forge-2-tech/SKILL.md +5 -1
- package/adapters/codex/skills/forge-2-tech/references/shared-conventions.md +44 -33
- package/adapters/codex/skills/forge-2-tech/references/stage-exit-protocol.md +64 -20
- package/adapters/codex/skills/forge-3-specs/SKILL.md +5 -1
- package/adapters/codex/skills/forge-3-specs/references/shared-conventions.md +44 -33
- package/adapters/codex/skills/forge-3-specs/references/stage-exit-protocol.md +64 -20
- package/adapters/codex/skills/forge-4-backlog/SKILL.md +41 -3
- package/adapters/codex/skills/forge-4-backlog/references/shared-conventions.md +44 -33
- package/adapters/codex/skills/forge-4-backlog/references/stage-exit-protocol.md +64 -20
- package/adapters/codex/skills/forge-5-loop/SKILL.md +36 -36
- package/adapters/codex/skills/forge-5-loop/references/agent-selection.md +17 -1
- package/adapters/codex/skills/forge-5-loop/references/ralph-loop-contract.md +6 -3
- package/adapters/codex/skills/forge-5-loop/references/recovery-procedure.md +349 -0
- package/adapters/codex/skills/forge-5-loop/references/result-reporting.md +40 -11
- package/adapters/codex/skills/forge-5-loop/references/runner-contract.md +26 -8
- package/adapters/codex/skills/forge-5-loop/references/shared-conventions.md +44 -33
- package/adapters/codex/skills/forge-5-loop/references/stage-exit-protocol.md +64 -20
- package/adapters/codex/skills/forge-6-docs/SKILL.md +29 -6
- package/adapters/codex/skills/forge-6-docs/references/shared-conventions.md +44 -33
- package/adapters/codex/skills/forge-6-docs/references/stage-exit-protocol.md +64 -20
- package/adapters/codex/skills/forge-fix/SKILL.md +34 -0
- package/adapters/codex/skills/forge-fix/references/shared-conventions.md +44 -33
- package/adapters/codex/skills/forge-fix/references/stage-exit-protocol.md +64 -20
- package/adapters/codex/skills/forge-guide/SKILL.md +1 -1
- package/adapters/codex/skills/forge-guide/references/forge-config-schema.json +18 -0
- package/adapters/codex/skills/forge-guide/references/process-overview.md +2 -2
- package/adapters/codex/skills/forge-guide/references/ralph-loop-contract.md +6 -3
- package/adapters/codex/skills/forge-guide/references/shared-conventions.md +44 -33
- package/adapters/codex/skills/forge-init/SKILL.md +1 -1
- package/adapters/codex/skills/forge-verify/SKILL.md +11 -12
- package/adapters/codex/skills/forge-verify/references/decisions/single-writer-threat-model.md +53 -0
- package/adapters/codex/skills/forge-verify/references/findings-template.md +32 -2
- package/adapters/codex/skills/forge-verify/references/shared-conventions.md +44 -33
- package/adapters/codex/skills/forge-verify/references/stage-exit-protocol.md +64 -20
- package/adapters/codex/skills/forge-verify/references/verification-checklists/backlog.md +73 -0
- package/adapters/codex/skills/forge-verify/references/verification-checklists/epic.md +1 -1
- package/adapters/codex/skills/forge-verify/references/verification-checklists/impl.md +85 -0
- package/adapters/codex/skills/forge-verify/references/verification-checklists/specs.md +43 -1
- package/adapters/copilot/.feature-forge-bundle.json +1 -1
- package/adapters/copilot/agents/forge-verifier.md +3 -1
- package/adapters/copilot/references/decisions/single-writer-threat-model.md +53 -0
- package/adapters/copilot/references/epic-state-schema.json +50 -0
- package/adapters/copilot/references/forge-config-schema.json +18 -0
- package/adapters/copilot/references/forge-decisions-schema.json +33 -0
- package/adapters/copilot/references/pipeline-state-schema.json +34 -2
- package/adapters/copilot/references/process-overview.md +2 -2
- package/adapters/copilot/references/ralph-loop-contract.md +6 -3
- package/adapters/copilot/references/shared-conventions.md +44 -33
- package/adapters/copilot/references/stage-exit-protocol.md +64 -20
- package/adapters/copilot/scripts/epic-manifest.py +82 -4
- package/adapters/copilot/scripts/fix-sweep.py +1180 -0
- package/adapters/copilot/scripts/forge-session.py +1124 -26
- package/adapters/copilot/skills/forge/forge.md +8 -8
- package/adapters/copilot/skills/forge/references/pipeline-state-schema.json +34 -2
- package/adapters/copilot/skills/forge/references/process-overview.md +2 -2
- package/adapters/copilot/skills/forge/references/shared-conventions.md +44 -33
- package/adapters/copilot/skills/forge/references/stage-exit-protocol.md +64 -20
- package/adapters/copilot/skills/forge-0-epic/references/edit-mode.md +14 -10
- package/adapters/copilot/skills/forge-0-epic/references/epic-manifest-subcommands.md +8 -3
- package/adapters/copilot/skills/forge-0-epic/references/pipeline-state-schema.json +34 -2
- package/adapters/copilot/skills/forge-0-epic/references/shared-conventions.md +44 -33
- package/adapters/copilot/skills/forge-0-epic/references/stage-exit-protocol.md +64 -20
- package/adapters/copilot/skills/forge-1-prd/forge-1-prd.md +3 -1
- package/adapters/copilot/skills/forge-1-prd/references/shared-conventions.md +44 -33
- package/adapters/copilot/skills/forge-1-prd/references/stage-exit-protocol.md +64 -20
- package/adapters/copilot/skills/forge-2-tech/forge-2-tech.md +5 -1
- package/adapters/copilot/skills/forge-2-tech/references/shared-conventions.md +44 -33
- package/adapters/copilot/skills/forge-2-tech/references/stage-exit-protocol.md +64 -20
- package/adapters/copilot/skills/forge-3-specs/forge-3-specs.md +5 -1
- package/adapters/copilot/skills/forge-3-specs/references/shared-conventions.md +44 -33
- package/adapters/copilot/skills/forge-3-specs/references/stage-exit-protocol.md +64 -20
- package/adapters/copilot/skills/forge-4-backlog/forge-4-backlog.md +41 -3
- package/adapters/copilot/skills/forge-4-backlog/references/shared-conventions.md +44 -33
- package/adapters/copilot/skills/forge-4-backlog/references/stage-exit-protocol.md +64 -20
- package/adapters/copilot/skills/forge-5-loop/forge-5-loop.md +36 -36
- package/adapters/copilot/skills/forge-5-loop/references/agent-selection.md +17 -1
- package/adapters/copilot/skills/forge-5-loop/references/ralph-loop-contract.md +6 -3
- package/adapters/copilot/skills/forge-5-loop/references/recovery-procedure.md +349 -0
- package/adapters/copilot/skills/forge-5-loop/references/result-reporting.md +40 -11
- package/adapters/copilot/skills/forge-5-loop/references/runner-contract.md +26 -8
- package/adapters/copilot/skills/forge-5-loop/references/shared-conventions.md +44 -33
- package/adapters/copilot/skills/forge-5-loop/references/stage-exit-protocol.md +64 -20
- package/adapters/copilot/skills/forge-6-docs/forge-6-docs.md +29 -6
- package/adapters/copilot/skills/forge-6-docs/references/shared-conventions.md +44 -33
- package/adapters/copilot/skills/forge-6-docs/references/stage-exit-protocol.md +64 -20
- package/adapters/copilot/skills/forge-fix/forge-fix.md +34 -0
- package/adapters/copilot/skills/forge-fix/references/shared-conventions.md +44 -33
- package/adapters/copilot/skills/forge-fix/references/stage-exit-protocol.md +64 -20
- package/adapters/copilot/skills/forge-guide/forge-guide.md +1 -1
- package/adapters/copilot/skills/forge-guide/references/forge-config-schema.json +18 -0
- package/adapters/copilot/skills/forge-guide/references/process-overview.md +2 -2
- package/adapters/copilot/skills/forge-guide/references/ralph-loop-contract.md +6 -3
- package/adapters/copilot/skills/forge-guide/references/shared-conventions.md +44 -33
- package/adapters/copilot/skills/forge-init/forge-init.md +1 -1
- package/adapters/copilot/skills/forge-verify/forge-verify.md +11 -12
- package/adapters/copilot/skills/forge-verify/references/decisions/single-writer-threat-model.md +53 -0
- package/adapters/copilot/skills/forge-verify/references/findings-template.md +32 -2
- package/adapters/copilot/skills/forge-verify/references/shared-conventions.md +44 -33
- package/adapters/copilot/skills/forge-verify/references/stage-exit-protocol.md +64 -20
- package/adapters/copilot/skills/forge-verify/references/verification-checklists/backlog.md +73 -0
- package/adapters/copilot/skills/forge-verify/references/verification-checklists/epic.md +1 -1
- package/adapters/copilot/skills/forge-verify/references/verification-checklists/impl.md +85 -0
- package/adapters/copilot/skills/forge-verify/references/verification-checklists/specs.md +43 -1
- package/adapters/cursor/.feature-forge-bundle.json +1 -1
- package/adapters/cursor/agents/forge-verifier.mdc +3 -1
- package/adapters/cursor/references/decisions/single-writer-threat-model.md +53 -0
- package/adapters/cursor/references/epic-state-schema.json +50 -0
- package/adapters/cursor/references/forge-config-schema.json +18 -0
- package/adapters/cursor/references/forge-decisions-schema.json +33 -0
- package/adapters/cursor/references/pipeline-state-schema.json +34 -2
- package/adapters/cursor/references/process-overview.md +2 -2
- package/adapters/cursor/references/ralph-loop-contract.md +6 -3
- package/adapters/cursor/references/shared-conventions.md +44 -33
- package/adapters/cursor/references/stage-exit-protocol.md +64 -20
- package/adapters/cursor/scripts/epic-manifest.py +82 -4
- package/adapters/cursor/scripts/fix-sweep.py +1180 -0
- package/adapters/cursor/scripts/forge-session.py +1124 -26
- package/adapters/cursor/skills/forge/forge.mdc +8 -8
- package/adapters/cursor/skills/forge/references/pipeline-state-schema.json +34 -2
- package/adapters/cursor/skills/forge/references/process-overview.md +2 -2
- package/adapters/cursor/skills/forge/references/shared-conventions.md +44 -33
- package/adapters/cursor/skills/forge/references/stage-exit-protocol.md +64 -20
- package/adapters/cursor/skills/forge-0-epic/references/edit-mode.md +14 -10
- package/adapters/cursor/skills/forge-0-epic/references/epic-manifest-subcommands.md +8 -3
- package/adapters/cursor/skills/forge-0-epic/references/pipeline-state-schema.json +34 -2
- package/adapters/cursor/skills/forge-0-epic/references/shared-conventions.md +44 -33
- package/adapters/cursor/skills/forge-0-epic/references/stage-exit-protocol.md +64 -20
- package/adapters/cursor/skills/forge-1-prd/forge-1-prd.mdc +3 -1
- package/adapters/cursor/skills/forge-1-prd/references/shared-conventions.md +44 -33
- package/adapters/cursor/skills/forge-1-prd/references/stage-exit-protocol.md +64 -20
- package/adapters/cursor/skills/forge-2-tech/forge-2-tech.mdc +5 -1
- package/adapters/cursor/skills/forge-2-tech/references/shared-conventions.md +44 -33
- package/adapters/cursor/skills/forge-2-tech/references/stage-exit-protocol.md +64 -20
- package/adapters/cursor/skills/forge-3-specs/forge-3-specs.mdc +5 -1
- package/adapters/cursor/skills/forge-3-specs/references/shared-conventions.md +44 -33
- package/adapters/cursor/skills/forge-3-specs/references/stage-exit-protocol.md +64 -20
- package/adapters/cursor/skills/forge-4-backlog/forge-4-backlog.mdc +41 -3
- package/adapters/cursor/skills/forge-4-backlog/references/shared-conventions.md +44 -33
- package/adapters/cursor/skills/forge-4-backlog/references/stage-exit-protocol.md +64 -20
- package/adapters/cursor/skills/forge-5-loop/forge-5-loop.mdc +36 -36
- package/adapters/cursor/skills/forge-5-loop/references/agent-selection.md +17 -1
- package/adapters/cursor/skills/forge-5-loop/references/ralph-loop-contract.md +6 -3
- package/adapters/cursor/skills/forge-5-loop/references/recovery-procedure.md +349 -0
- package/adapters/cursor/skills/forge-5-loop/references/result-reporting.md +40 -11
- package/adapters/cursor/skills/forge-5-loop/references/runner-contract.md +26 -8
- package/adapters/cursor/skills/forge-5-loop/references/shared-conventions.md +44 -33
- package/adapters/cursor/skills/forge-5-loop/references/stage-exit-protocol.md +64 -20
- package/adapters/cursor/skills/forge-6-docs/forge-6-docs.mdc +29 -6
- package/adapters/cursor/skills/forge-6-docs/references/shared-conventions.md +44 -33
- package/adapters/cursor/skills/forge-6-docs/references/stage-exit-protocol.md +64 -20
- package/adapters/cursor/skills/forge-fix/forge-fix.mdc +34 -0
- package/adapters/cursor/skills/forge-fix/references/shared-conventions.md +44 -33
- package/adapters/cursor/skills/forge-fix/references/stage-exit-protocol.md +64 -20
- package/adapters/cursor/skills/forge-guide/forge-guide.mdc +1 -1
- package/adapters/cursor/skills/forge-guide/references/forge-config-schema.json +18 -0
- package/adapters/cursor/skills/forge-guide/references/process-overview.md +2 -2
- package/adapters/cursor/skills/forge-guide/references/ralph-loop-contract.md +6 -3
- package/adapters/cursor/skills/forge-guide/references/shared-conventions.md +44 -33
- package/adapters/cursor/skills/forge-init/forge-init.mdc +1 -1
- package/adapters/cursor/skills/forge-verify/forge-verify.mdc +11 -12
- package/adapters/cursor/skills/forge-verify/references/decisions/single-writer-threat-model.md +53 -0
- package/adapters/cursor/skills/forge-verify/references/findings-template.md +32 -2
- package/adapters/cursor/skills/forge-verify/references/shared-conventions.md +44 -33
- package/adapters/cursor/skills/forge-verify/references/stage-exit-protocol.md +64 -20
- package/adapters/cursor/skills/forge-verify/references/verification-checklists/backlog.md +73 -0
- package/adapters/cursor/skills/forge-verify/references/verification-checklists/epic.md +1 -1
- package/adapters/cursor/skills/forge-verify/references/verification-checklists/impl.md +85 -0
- package/adapters/cursor/skills/forge-verify/references/verification-checklists/specs.md +43 -1
- package/adapters/gemini/.feature-forge-bundle.json +1 -1
- package/adapters/gemini/agents/forge-verifier.md +3 -1
- package/adapters/gemini/gemini-extension.json +1 -1
- package/adapters/gemini/references/decisions/single-writer-threat-model.md +53 -0
- package/adapters/gemini/references/epic-state-schema.json +50 -0
- package/adapters/gemini/references/forge-config-schema.json +18 -0
- package/adapters/gemini/references/forge-decisions-schema.json +33 -0
- package/adapters/gemini/references/pipeline-state-schema.json +34 -2
- package/adapters/gemini/references/process-overview.md +2 -2
- package/adapters/gemini/references/ralph-loop-contract.md +6 -3
- package/adapters/gemini/references/shared-conventions.md +44 -33
- package/adapters/gemini/references/stage-exit-protocol.md +64 -20
- package/adapters/gemini/scripts/epic-manifest.py +82 -4
- package/adapters/gemini/scripts/fix-sweep.py +1180 -0
- package/adapters/gemini/scripts/forge-session.py +1124 -26
- package/adapters/gemini/skills/forge/forge.md +8 -8
- package/adapters/gemini/skills/forge/references/pipeline-state-schema.json +34 -2
- package/adapters/gemini/skills/forge/references/process-overview.md +2 -2
- package/adapters/gemini/skills/forge/references/shared-conventions.md +44 -33
- package/adapters/gemini/skills/forge/references/stage-exit-protocol.md +64 -20
- package/adapters/gemini/skills/forge-0-epic/references/edit-mode.md +14 -10
- package/adapters/gemini/skills/forge-0-epic/references/epic-manifest-subcommands.md +8 -3
- package/adapters/gemini/skills/forge-0-epic/references/pipeline-state-schema.json +34 -2
- package/adapters/gemini/skills/forge-0-epic/references/shared-conventions.md +44 -33
- package/adapters/gemini/skills/forge-0-epic/references/stage-exit-protocol.md +64 -20
- package/adapters/gemini/skills/forge-1-prd/forge-1-prd.md +3 -1
- package/adapters/gemini/skills/forge-1-prd/references/shared-conventions.md +44 -33
- package/adapters/gemini/skills/forge-1-prd/references/stage-exit-protocol.md +64 -20
- package/adapters/gemini/skills/forge-2-tech/forge-2-tech.md +5 -1
- package/adapters/gemini/skills/forge-2-tech/references/shared-conventions.md +44 -33
- package/adapters/gemini/skills/forge-2-tech/references/stage-exit-protocol.md +64 -20
- package/adapters/gemini/skills/forge-3-specs/forge-3-specs.md +5 -1
- package/adapters/gemini/skills/forge-3-specs/references/shared-conventions.md +44 -33
- package/adapters/gemini/skills/forge-3-specs/references/stage-exit-protocol.md +64 -20
- package/adapters/gemini/skills/forge-4-backlog/forge-4-backlog.md +41 -3
- package/adapters/gemini/skills/forge-4-backlog/references/shared-conventions.md +44 -33
- package/adapters/gemini/skills/forge-4-backlog/references/stage-exit-protocol.md +64 -20
- package/adapters/gemini/skills/forge-5-loop/forge-5-loop.md +36 -36
- package/adapters/gemini/skills/forge-5-loop/references/agent-selection.md +17 -1
- package/adapters/gemini/skills/forge-5-loop/references/ralph-loop-contract.md +6 -3
- package/adapters/gemini/skills/forge-5-loop/references/recovery-procedure.md +349 -0
- package/adapters/gemini/skills/forge-5-loop/references/result-reporting.md +40 -11
- package/adapters/gemini/skills/forge-5-loop/references/runner-contract.md +26 -8
- package/adapters/gemini/skills/forge-5-loop/references/shared-conventions.md +44 -33
- package/adapters/gemini/skills/forge-5-loop/references/stage-exit-protocol.md +64 -20
- package/adapters/gemini/skills/forge-6-docs/forge-6-docs.md +29 -6
- package/adapters/gemini/skills/forge-6-docs/references/shared-conventions.md +44 -33
- package/adapters/gemini/skills/forge-6-docs/references/stage-exit-protocol.md +64 -20
- package/adapters/gemini/skills/forge-fix/forge-fix.md +34 -0
- package/adapters/gemini/skills/forge-fix/references/shared-conventions.md +44 -33
- package/adapters/gemini/skills/forge-fix/references/stage-exit-protocol.md +64 -20
- package/adapters/gemini/skills/forge-guide/forge-guide.md +1 -1
- package/adapters/gemini/skills/forge-guide/references/forge-config-schema.json +18 -0
- package/adapters/gemini/skills/forge-guide/references/process-overview.md +2 -2
- package/adapters/gemini/skills/forge-guide/references/ralph-loop-contract.md +6 -3
- package/adapters/gemini/skills/forge-guide/references/shared-conventions.md +44 -33
- package/adapters/gemini/skills/forge-init/forge-init.md +1 -1
- package/adapters/gemini/skills/forge-verify/forge-verify.md +11 -12
- package/adapters/gemini/skills/forge-verify/references/decisions/single-writer-threat-model.md +53 -0
- package/adapters/gemini/skills/forge-verify/references/findings-template.md +32 -2
- package/adapters/gemini/skills/forge-verify/references/shared-conventions.md +44 -33
- package/adapters/gemini/skills/forge-verify/references/stage-exit-protocol.md +64 -20
- package/adapters/gemini/skills/forge-verify/references/verification-checklists/backlog.md +73 -0
- package/adapters/gemini/skills/forge-verify/references/verification-checklists/epic.md +1 -1
- package/adapters/gemini/skills/forge-verify/references/verification-checklists/impl.md +85 -0
- package/adapters/gemini/skills/forge-verify/references/verification-checklists/specs.md +43 -1
- package/adapters/pi/.feature-forge-bundle.json +1 -1
- package/adapters/pi/agents/forge-verifier.md +3 -1
- package/adapters/pi/references/decisions/single-writer-threat-model.md +53 -0
- package/adapters/pi/references/epic-state-schema.json +50 -0
- package/adapters/pi/references/forge-config-schema.json +18 -0
- package/adapters/pi/references/forge-decisions-schema.json +33 -0
- package/adapters/pi/references/pipeline-state-schema.json +34 -2
- package/adapters/pi/references/process-overview.md +2 -2
- package/adapters/pi/references/ralph-loop-contract.md +6 -3
- package/adapters/pi/references/shared-conventions.md +33 -22
- package/adapters/pi/references/stage-exit-protocol.md +63 -19
- package/adapters/pi/scripts/epic-manifest.py +82 -4
- package/adapters/pi/scripts/fix-sweep.py +1180 -0
- package/adapters/pi/scripts/forge-session.py +1124 -26
- package/adapters/pi/skills/forge/SKILL.md +5 -5
- package/adapters/pi/skills/forge/references/pipeline-state-schema.json +34 -2
- package/adapters/pi/skills/forge/references/process-overview.md +2 -2
- package/adapters/pi/skills/forge/references/shared-conventions.md +33 -22
- package/adapters/pi/skills/forge/references/stage-exit-protocol.md +63 -19
- package/adapters/pi/skills/forge-0-epic/references/edit-mode.md +8 -4
- package/adapters/pi/skills/forge-0-epic/references/epic-manifest-subcommands.md +6 -1
- package/adapters/pi/skills/forge-0-epic/references/pipeline-state-schema.json +34 -2
- package/adapters/pi/skills/forge-0-epic/references/shared-conventions.md +33 -22
- package/adapters/pi/skills/forge-0-epic/references/stage-exit-protocol.md +63 -19
- package/adapters/pi/skills/forge-1-prd/SKILL.md +3 -1
- package/adapters/pi/skills/forge-1-prd/references/shared-conventions.md +33 -22
- package/adapters/pi/skills/forge-1-prd/references/stage-exit-protocol.md +63 -19
- package/adapters/pi/skills/forge-2-tech/SKILL.md +5 -1
- package/adapters/pi/skills/forge-2-tech/references/shared-conventions.md +33 -22
- package/adapters/pi/skills/forge-2-tech/references/stage-exit-protocol.md +63 -19
- package/adapters/pi/skills/forge-3-specs/SKILL.md +5 -1
- package/adapters/pi/skills/forge-3-specs/references/shared-conventions.md +33 -22
- package/adapters/pi/skills/forge-3-specs/references/stage-exit-protocol.md +63 -19
- package/adapters/pi/skills/forge-4-backlog/SKILL.md +41 -3
- package/adapters/pi/skills/forge-4-backlog/references/shared-conventions.md +33 -22
- package/adapters/pi/skills/forge-4-backlog/references/stage-exit-protocol.md +63 -19
- package/adapters/pi/skills/forge-5-loop/SKILL.md +36 -36
- package/adapters/pi/skills/forge-5-loop/references/agent-selection.md +16 -0
- package/adapters/pi/skills/forge-5-loop/references/ralph-loop-contract.md +6 -3
- package/adapters/pi/skills/forge-5-loop/references/recovery-procedure.md +349 -0
- package/adapters/pi/skills/forge-5-loop/references/result-reporting.md +40 -11
- package/adapters/pi/skills/forge-5-loop/references/runner-contract.md +25 -7
- package/adapters/pi/skills/forge-5-loop/references/shared-conventions.md +33 -22
- package/adapters/pi/skills/forge-5-loop/references/stage-exit-protocol.md +63 -19
- package/adapters/pi/skills/forge-6-docs/SKILL.md +29 -6
- package/adapters/pi/skills/forge-6-docs/references/shared-conventions.md +33 -22
- package/adapters/pi/skills/forge-6-docs/references/stage-exit-protocol.md +63 -19
- package/adapters/pi/skills/forge-fix/SKILL.md +34 -0
- package/adapters/pi/skills/forge-fix/references/shared-conventions.md +33 -22
- package/adapters/pi/skills/forge-fix/references/stage-exit-protocol.md +63 -19
- package/adapters/pi/skills/forge-guide/references/forge-config-schema.json +18 -0
- package/adapters/pi/skills/forge-guide/references/process-overview.md +2 -2
- package/adapters/pi/skills/forge-guide/references/ralph-loop-contract.md +6 -3
- package/adapters/pi/skills/forge-guide/references/shared-conventions.md +33 -22
- package/adapters/pi/skills/forge-verify/SKILL.md +10 -11
- package/adapters/pi/skills/forge-verify/references/decisions/single-writer-threat-model.md +53 -0
- package/adapters/pi/skills/forge-verify/references/findings-template.md +31 -1
- package/adapters/pi/skills/forge-verify/references/shared-conventions.md +33 -22
- package/adapters/pi/skills/forge-verify/references/stage-exit-protocol.md +63 -19
- package/adapters/pi/skills/forge-verify/references/verification-checklists/backlog.md +73 -0
- package/adapters/pi/skills/forge-verify/references/verification-checklists/epic.md +1 -1
- package/adapters/pi/skills/forge-verify/references/verification-checklists/impl.md +85 -0
- package/adapters/pi/skills/forge-verify/references/verification-checklists/specs.md +43 -1
- package/package.json +1 -1
|
@@ -18,6 +18,8 @@ You are the "second set of eyes." You receive artifacts (PRDs, tech specs, imple
|
|
|
18
18
|
|
|
19
19
|
You have READ-ONLY access. You cannot and should not modify any files. Your output is returned as your response — the parent agent handles writing the findings document to disk.
|
|
20
20
|
|
|
21
|
+
**Your last message is the only thing the parent receives.** The Agent tool returns your final response and nothing else — no transcript, no intermediate messages, no tool results. If your run ends on a status or transition line ("Let me read the dispatch handler table."), *that line* is the entire verification result the parent gets, and the digest you spent the whole run building is silently dropped (issue #183). Your final response must therefore BE the complete report — the full Output Format block below, starting at `# Verification Report:` — never a summary of it, never an opening line, never "the report follows." Before ending, check your last message: if it is not the complete report, emit the complete report.
|
|
22
|
+
|
|
21
23
|
**You ARE the verifier — you never dispatch one.** You have no Agent/Task tool. Your pre-loaded `forge-verify` skill contains a "Subagent Delegation (parent orchestrator only)" section describing how a *parent* dispatches a `forge-verifier` — that guidance is for the parent, not for you. Ignore it: do not attempt to delegate, spawn a subagent, or return a "verification is running / will surface shortly" placeholder. Execute the verification checks yourself and return the findings block. Delegating from here is a self-referential loop that produces no work and no findings artifact.
|
|
22
24
|
|
|
23
25
|
## How You Work
|
|
@@ -60,7 +62,7 @@ At the end of each verification pass, update your memory with any new patterns y
|
|
|
60
62
|
|
|
61
63
|
## Output Format
|
|
62
64
|
|
|
63
|
-
Return your findings as your final response using exactly this markdown structure. The parent agent will write it to `.verification/VERIFY-{mode}-{date}.md`:
|
|
65
|
+
Return your findings as your final response using exactly this markdown structure — the final response IS the report (emit the entire block, not a description of it). The parent agent will write it to `.verification/VERIFY-{mode}-{date}.md`:
|
|
64
66
|
|
|
65
67
|
```markdown
|
|
66
68
|
# Verification Report: {feature} ({mode})
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Decision: single-writer state model — detection welcome, locking out of scope
|
|
2
|
+
|
|
3
|
+
**Decided:** 2026-08-08 · **Issue:** [#180](https://github.com/garygentry/feature-forge/issues/180) · **Owner:** repository owner
|
|
4
|
+
|
|
5
|
+
## The decision
|
|
6
|
+
|
|
7
|
+
Concurrent multi-session mutation of forge state is **out of scope**. Every forge state
|
|
8
|
+
writer — `forge-session.py` (`.pipeline-state.json`) and `epic-manifest.py`
|
|
9
|
+
(`epic-manifest.json`, `.epic-state.json`) — assumes a **single writer**. Atomicity
|
|
10
|
+
(sibling temp file → flush/fsync → `os.replace`) protects against an *interrupted* write;
|
|
11
|
+
it is not, and is not intended to be, mutual exclusion between simultaneous writers.
|
|
12
|
+
|
|
13
|
+
The standing posture is **detection, not locking**:
|
|
14
|
+
|
|
15
|
+
- **No locking mechanism will be added on the authority of a verification finding or a
|
|
16
|
+
single feature's spec.** If concurrent multi-session use ever becomes a supported
|
|
17
|
+
workflow, that is a product decision needing its own PRD — and a state lock alone would
|
|
18
|
+
be false comfort, because git operations, the two-commit provenance protocol, and
|
|
19
|
+
adapter regeneration are equally unsynchronized.
|
|
20
|
+
- **Cheap, opportunistic detection is welcome if someone proposes it** — e.g. an
|
|
21
|
+
epic-root writer re-reading and failing loudly on an unexpected `revision` before
|
|
22
|
+
`os.replace`. It is an explicitly optional hardening, not a requirement, and nothing is
|
|
23
|
+
scheduled.
|
|
24
|
+
|
|
25
|
+
## Accepted residual risk
|
|
26
|
+
|
|
27
|
+
Everything in-session is sequential, and member `.pipeline-state.json` files are
|
|
28
|
+
disjoint. The one real exposure: two sessions working **different members of one epic**
|
|
29
|
+
share two epic-root files, `epic-manifest.json` and `.epic-state.json`. A lost
|
|
30
|
+
read-modify-write increment of the manifest's `revision` can leave it unchanged after a
|
|
31
|
+
semantic mutation landed, and the freshness comparison then classifies a **stale epic
|
|
32
|
+
verification as `fresh`** — a correctness consequence, not just a lost edit.
|
|
33
|
+
|
|
34
|
+
This is **accepted and documented**, not mitigated. Anyone who hits it has this document
|
|
35
|
+
to cite; do not run two concurrent sessions against members of the same epic.
|
|
36
|
+
|
|
37
|
+
## What this means for verification (CHECK-S27)
|
|
38
|
+
|
|
39
|
+
When `CHECK-S27` ("Concurrent access scenarios are addressed if relevant") fires against
|
|
40
|
+
forge state writes, the answer is a **citation, not a design**: cite this document (or
|
|
41
|
+
the per-feature requirement restating it, e.g. `stage-exit-coverage` `REQ-REL-04`,
|
|
42
|
+
`epic-orchestration` `REQ-ROBUST-03`). A PRD silent on concurrency gets a one-sentence
|
|
43
|
+
position recorded; a verifier must never answer the silence by specifying a mechanism.
|
|
44
|
+
|
|
45
|
+
## Provenance
|
|
46
|
+
|
|
47
|
+
Both precedents ran the same check; the only variable was whether the PRD had a position:
|
|
48
|
+
|
|
49
|
+
- `stage-exit-coverage` V-006 raised CHECK-S27 against a silent PRD, was filed as a
|
|
50
|
+
`gap`, and induced a ~140-line portable lock protocol answering no requirement. It was
|
|
51
|
+
removed (`302c93f`), and the PRD now records the position as `REQ-REL-04`.
|
|
52
|
+
- `epic-orchestration` V-008 raised the same check against a PRD that had scoped
|
|
53
|
+
concurrency out (`REQ-ROBUST-03`), was filed as an `improvement`, and cost one sentence.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "Feature Forge Epic Verification State",
|
|
4
|
+
"description": "Epic-scoped verification state for a single epic. Lives at {specsDir}/{epic}/.epic-state.json. Written only by forge-session.py's `state-verify` verb for epic targets (`--stage forge-0-epic`, resolved through `_load_epic_state_for_write`) — never by hand. Deliberately NOT a member `.pipeline-state.json` variant: epic verification is epic-scoped, artifact freshness is judged against the epic manifest's `revision` (never a member production-stage `version`), and there is no fallback between the two state files in either direction (REQ-SEC-01).",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"required": ["epic", "updatedAt", "stages"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"epic": {
|
|
9
|
+
"type": "string",
|
|
10
|
+
"description": "Epic name (matches the directory name under specsDir). epic-manifest.json's own `epic` value is canonical on conflict — the writer refuses a mismatched identity rather than resolving it."
|
|
11
|
+
},
|
|
12
|
+
"updatedAt": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"format": "date-time"
|
|
15
|
+
},
|
|
16
|
+
"stages": {
|
|
17
|
+
"type": "object",
|
|
18
|
+
"properties": {
|
|
19
|
+
"forge-verify-epic": { "$ref": "#/definitions/verifyEntry" }
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"definitions": {
|
|
24
|
+
"verifyEntry": {
|
|
25
|
+
"type": "object",
|
|
26
|
+
"required": ["status"],
|
|
27
|
+
"description": "MIRROR of pipeline-state-schema.json#/definitions/verifyEntry (minus this description) — the repo's stdlib schema validator (tests/_state_schema.py) resolves same-file `#/definitions/*` refs only, so the definition is duplicated rather than cross-file-referenced, and tests/test_epic_state_schema_conformance.py pins the two definitions equal so they cannot drift. Edit them together.",
|
|
28
|
+
"properties": {
|
|
29
|
+
"status": {
|
|
30
|
+
"type": "string",
|
|
31
|
+
"enum": ["pending", "auto-verify-pending", "passed", "findings-reported", "findings-applied", "skipped"]
|
|
32
|
+
},
|
|
33
|
+
"findingsFile": {
|
|
34
|
+
"type": ["string", "null"],
|
|
35
|
+
"description": "Path to the verification findings document"
|
|
36
|
+
},
|
|
37
|
+
"findingsCount": {
|
|
38
|
+
"type": ["integer", "null"],
|
|
39
|
+
"description": "Number of findings reported"
|
|
40
|
+
},
|
|
41
|
+
"verifiedAt": { "type": ["string", "null"], "format": "date-time" },
|
|
42
|
+
"fixedAt": { "type": ["string", "null"], "format": "date-time" },
|
|
43
|
+
"commitHash": { "type": ["string", "null"], "description": "Git commit SHA of the verify/fix artifact commit. Recorded via the two-commit Git Commit Protocol (shared-conventions.md) so it points at the artifact commit, never an orphaned amend." },
|
|
44
|
+
"verifiedStageVersion": { "type": ["integer", "null"], "description": "The production stage's `version` at the moment this verify was resolved. The navigator's freshness ledger compares it to the stage's current `version`: equal means the verify is fresh; a mismatch (artifact revised since) or an absent field (legacy state) means stale, so auto-verify re-fires. Recorded by forge-verify/forge-fix when writing a passed/findings-applied status." },
|
|
45
|
+
"scheduledAt": { "type": ["string", "null"], "format": "date-time", "description": "UTC ISO-8601 timestamp at which unattended in-stage verification was scheduled for this entry. Written alongside the `auto-verify-pending` status and DELETED (not nulled) by any terminal result, so an absent field means 'not scheduled'." },
|
|
46
|
+
"scheduledStageVersion": { "type": ["integer", "null"], "minimum": 1, "description": "The artifact revision current when verification was scheduled — the production stage's `version` for a feature, the epic manifest's `revision` for an epic. Makes rescheduling idempotent (an identical revision does not rewrite the entry) and lets a read tell debt owed on the current artifact from debt stranded on an older one. Deleted by any terminal result." }
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -67,6 +67,12 @@
|
|
|
67
67
|
"default": true,
|
|
68
68
|
"description": "When true (default), the /feature-forge:forge navigator auto-invokes the next pipeline stage via the Skill tool after the user confirms it, instead of only printing the command to copy. Set false to keep the old copy-paste behavior (the navigator suggests the command but never launches it). Ignored on non-Claude hosts, which always fall back to printing the command."
|
|
69
69
|
},
|
|
70
|
+
"docsStage": {
|
|
71
|
+
"type": "string",
|
|
72
|
+
"enum": ["prompt", "skip"],
|
|
73
|
+
"default": "prompt",
|
|
74
|
+
"description": "How forge-6-docs' Documentation Decision Gate behaves at stage entry. \"prompt\" (default) asks generate-vs-skip once per run; \"skip\" records the stage as deliberately skipped with no prompt — the skill runs the state-skip verb and closes the pipeline honestly (stage-exit --outcome skipped), so docs are never implied-mandatory for teams that document differently. The gate's refuse-to-erase guard still applies: docs that already exist are never silently reclassified, whatever this is set to. Read directly by forge-6-docs (not part of loopRunner resolution); an unrecognized or absent value behaves as \"prompt\"."
|
|
75
|
+
},
|
|
70
76
|
"autoVerify": {
|
|
71
77
|
"type": "boolean",
|
|
72
78
|
"default": false,
|
|
@@ -195,6 +201,18 @@
|
|
|
195
201
|
"default": "",
|
|
196
202
|
"description": "Project-default coding agent id, so a project can fix its agent once without specifying it every run. Empty string ⇒ no project default (the runner's own default — claude-cli for rauf — applies, behaving exactly as today). Overridden by the per-run agent selector (run > project precedence, resolved inside forge before the single --agent is emitted). Ignored when agentArgument is absent."
|
|
197
203
|
},
|
|
204
|
+
"agentMode": {
|
|
205
|
+
"type": "string",
|
|
206
|
+
"enum": ["prompt", "auto"],
|
|
207
|
+
"default": "prompt",
|
|
208
|
+
"description": "Gates forge-5's Step 2d agent AskUserQuestion. \"prompt\" (default) presents the agent question — byte-identical to today. \"auto\" suppresses ONLY the interactive pick: the agent resolves from defaultAgent (or the runner default when unset), and the availability probe, the verdict classification (UNKNOWN hard-reject before side-effects / UNAVAILABLE proceed-or-choose / probe-failure handling), and the Claude-alias model guard ALL still run; the resolved 'Agent: {id} (source: …)' confirmation line still shows, so the choice is never hidden. Meaningless when agentArgument is absent/empty — that capability gate already removes the entire agent surface, and this field adds no second gate. An unrecognized value behaves as \"prompt\"."
|
|
209
|
+
},
|
|
210
|
+
"reviewMode": {
|
|
211
|
+
"type": "string",
|
|
212
|
+
"enum": ["prompt", "always", "never"],
|
|
213
|
+
"default": "prompt",
|
|
214
|
+
"description": "Gates forge-5's Step 2d Run-mode AskUserQuestion (rauf only — ignored when name != \"rauf\", where no Run-mode question exists). \"prompt\" (default) surfaces the question with the review pass pre-selected — byte-identical to today. \"always\" skips the question and appends --review unconditionally; the rendered command in the confirmation still shows --review, so the choice is never hidden. \"never\" skips the question and launches the bare rendered command. Under \"always\"/\"never\", a NARROWER situational retry-blocked question still surfaces when — and only when — the backlog has blocked items (the --review decision itself is fixed by the mode and never re-asked); with no blocked items the launch is prompt-free. An unrecognized value behaves as \"prompt\"."
|
|
215
|
+
},
|
|
198
216
|
"preconditionFile": {
|
|
199
217
|
"type": "string",
|
|
200
218
|
"default": ".rauf.json",
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"title": "forge-decisions",
|
|
4
|
+
"type": "object",
|
|
5
|
+
"additionalProperties": false,
|
|
6
|
+
"required": ["schemaVersion", "feature", "createdAt", "updatedAt", "decisions"],
|
|
7
|
+
"properties": {
|
|
8
|
+
"schemaVersion": { "type": "string", "enum": ["1"] },
|
|
9
|
+
"feature": { "type": "string" },
|
|
10
|
+
"createdAt": { "type": "string" },
|
|
11
|
+
"updatedAt": { "type": "string" },
|
|
12
|
+
"decisions": { "type": "array", "items": { "$ref": "#/definitions/decision" } }
|
|
13
|
+
},
|
|
14
|
+
"definitions": {
|
|
15
|
+
"decision": {
|
|
16
|
+
"type": "object",
|
|
17
|
+
"additionalProperties": false,
|
|
18
|
+
"required": ["itemId", "question", "answer", "deferred", "decidedAt",
|
|
19
|
+
"recordedBy", "appliedAt", "appliedBy"],
|
|
20
|
+
"properties": {
|
|
21
|
+
"itemId": { "type": "string" },
|
|
22
|
+
"question": { "type": "string" },
|
|
23
|
+
"answer": { "type": ["string", "null"] },
|
|
24
|
+
"deferred": { "type": "boolean" },
|
|
25
|
+
"clusterId": { "type": "string" },
|
|
26
|
+
"decidedAt": { "type": "string" },
|
|
27
|
+
"recordedBy": { "type": "string" },
|
|
28
|
+
"appliedAt": { "type": ["string", "null"] },
|
|
29
|
+
"appliedBy": { "type": ["string", "null"] }
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
},
|
|
38
38
|
"notes": {
|
|
39
39
|
"type": "string",
|
|
40
|
-
"description": "Free-form notes persisted between sessions (user can add context before stepping away)"
|
|
40
|
+
"description": "Free-form notes persisted between sessions (user can add context before stepping away). A single string with latest-note-wins semantics: `state-note` (its only sanctioned writer) OVERWRITES the previous value — an author folds any still-relevant earlier note into the one combined string. Read by the navigator dashboard AND by each downstream stage's Step 1 carried-over note check (forge-2-tech through forge-5-loop), which surfaces it as stage input; it never overrides artifacts or config."
|
|
41
41
|
},
|
|
42
42
|
"epicChangeRequests": {
|
|
43
43
|
"type": "array",
|
|
@@ -127,7 +127,7 @@
|
|
|
127
127
|
"forge-4-backlog": { "$ref": "#/definitions/stageEntry" },
|
|
128
128
|
"forge-verify-backlog": { "$ref": "#/definitions/verifyEntry" },
|
|
129
129
|
"forge-5-loop": { "$ref": "#/definitions/stageEntry" },
|
|
130
|
-
"forge-6-docs": { "$ref": "#/definitions/
|
|
130
|
+
"forge-6-docs": { "$ref": "#/definitions/docsStageEntry" },
|
|
131
131
|
"forge-verify-impl": { "$ref": "#/definitions/verifyEntry" },
|
|
132
132
|
"forge-verify-prd": { "$ref": "#/definitions/verifyEntry" },
|
|
133
133
|
"forge-verify-tech": { "$ref": "#/definitions/verifyEntry" }
|
|
@@ -165,6 +165,38 @@
|
|
|
165
165
|
}
|
|
166
166
|
}
|
|
167
167
|
},
|
|
168
|
+
"docsStageEntry": {
|
|
169
|
+
"type": "object",
|
|
170
|
+
"required": ["status"],
|
|
171
|
+
"description": "The forge-6-docs stage entry: identical to stageEntry except that `skipped` is a legal status and `skippedAt` records when the deliberate skip was written (by the `state-skip` verb, never by hand). `skipped` is a terminal, done-for-selection status — the pipeline ends without the stage claiming artifacts it never produced (#197). Deliberately scoped to the docs stage: a skipped PRD or specs stage is not a representable state, so the shared stageEntry enum does NOT carry `skipped`.",
|
|
172
|
+
"properties": {
|
|
173
|
+
"status": {
|
|
174
|
+
"type": "string",
|
|
175
|
+
"enum": ["pending", "in-progress", "complete", "stale", "skipped"]
|
|
176
|
+
},
|
|
177
|
+
"version": {
|
|
178
|
+
"type": "integer",
|
|
179
|
+
"description": "Incremented each time this stage's artifacts are revised"
|
|
180
|
+
},
|
|
181
|
+
"artifacts": {
|
|
182
|
+
"type": "array",
|
|
183
|
+
"items": { "type": "string" },
|
|
184
|
+
"description": "Relative paths to artifacts produced by this stage"
|
|
185
|
+
},
|
|
186
|
+
"startedAt": { "type": ["string", "null"], "format": "date-time" },
|
|
187
|
+
"completedAt": { "type": ["string", "null"], "format": "date-time" },
|
|
188
|
+
"skippedAt": { "type": ["string", "null"], "format": "date-time", "description": "UTC ISO-8601 timestamp of the deliberate skip (status: skipped). Written by `state-skip`; absent on every other status." },
|
|
189
|
+
"commitHash": {
|
|
190
|
+
"type": ["string", "null"],
|
|
191
|
+
"description": "Git commit SHA of this stage's artifact commit (Commit 1 of the two-commit Git Commit Protocol in shared-conventions.md). Written by a small follow-up commit so it points at the artifact commit itself, never at an orphaned amend or the hash-recording commit. null until recorded (or when there was no new artifact commit)."
|
|
192
|
+
},
|
|
193
|
+
"basedOnVersions": {
|
|
194
|
+
"type": "object",
|
|
195
|
+
"description": "Upstream stage versions this artifact was built against",
|
|
196
|
+
"additionalProperties": { "type": "integer" }
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
},
|
|
168
200
|
"verifyEntry": {
|
|
169
201
|
"type": "object",
|
|
170
202
|
"required": ["status"],
|
|
@@ -58,9 +58,12 @@ defined authoritatively in rauf's
|
|
|
58
58
|
> item aside and **keeps working other runnable items to completion** (rauf:
|
|
59
59
|
> `runner.ts` needs_human handler). So a supervising session can surface those
|
|
60
60
|
> events live (visibility) and cancel early, but it cannot inject an answer and
|
|
61
|
-
> resume the set-aside item mid-run — resolution is
|
|
62
|
-
>
|
|
63
|
-
>
|
|
61
|
+
> resume the set-aside item mid-run — resolution is the **Post-Run Recovery
|
|
62
|
+
> Procedure** (`skills/forge-5-loop/references/recovery-procedure.md`): record the
|
|
63
|
+
> answer via `decision-record` at the moment of collection, then drive recovery
|
|
64
|
+
> from the record after the run ends. A first-class pause/resume-with-answer
|
|
65
|
+
> capability is a desirable runner enhancement (see
|
|
66
|
+
> `plans/rauf-enhancement-recommendations.md`).
|
|
64
67
|
|
|
65
68
|
## rauf is the default and reference implementation
|
|
66
69
|
|
|
@@ -36,7 +36,7 @@ I found that the codebase uses React and TanStack Router.
|
|
|
36
36
|
|
|
37
37
|
### Decision Support: Help the User Choose
|
|
38
38
|
|
|
39
|
-
When
|
|
39
|
+
When a question posed through `AskUserQuestion` carries substantive options (a real choice — not a trivial yes/no confirmation), do not just list them. The interview stages have already done codebase research and integration analysis; surfacing that synthesis at the decision moment is the whole point. For every such question:
|
|
40
40
|
|
|
41
41
|
- **Lead with a recommended option.** Place it first and label it `(recommended)` (matching the `AskUserQuestion` "(Recommended)" convention).
|
|
42
42
|
- **Put the trade-off in each option's `description`.** Say why you'd pick it and what you give up versus the alternatives — the cost, not just the benefit.
|
|
@@ -53,6 +53,17 @@ For genuinely comparable artifacts (competing module structures, two code snippe
|
|
|
53
53
|
|
|
54
54
|
The **Branch Setup** block below is the reference pattern: a strong recommendation as the first option, rationale inline, the alternative still available, never a hard-stop.
|
|
55
55
|
|
|
56
|
+
## Stage Review Gate
|
|
57
|
+
|
|
58
|
+
Every authoring stage ends its "Review with User" step in exactly one of two shapes. Which shape a stage uses is declared **here, once** — each stage's review step points at this block by title, and the shape is never re-derived from the surrounding prose or inferred from how sibling stages behave (three stages block and one does not; majority-shape inference is precisely the failure this block exists to prevent):
|
|
59
|
+
|
|
60
|
+
- **Blocking review (gate).** The stage presents the artifact and collects feedback through `AskUserQuestion`; it does **not** proceed until the user answers, iterating until they confirm. Stages: **forge-1-prd** (Step 5), **forge-2-tech** (Step 6), **forge-3-specs** (Step 6).
|
|
61
|
+
- **Non-blocking review (invitation).** The stage states the artifact is ready and invites adjustments **as a statement, not a question** — and then **proceeds to the next step in the same turn unless the user asks for changes**. The invitation obliges the agent to *continue*: emitting the invitation sentence and stopping treats the non-gate as a gate and strands the stage `in-progress` with its completion step unrun — a defect, not caution. Stage: **forge-4-backlog** (Step 6).
|
|
62
|
+
|
|
63
|
+
**Why the shapes differ.** A blocking review guards an artifact whose content was just authored from open-ended interview or synthesis — the user is the only authority on "complete", so the stage must wait. forge-4's backlog is *derived* from specs the user already approved, was planned interactively in its Step 3, and is machine-validated in its Step 5; a second hard gate would re-ask a settled question, and the loop never launches without forge-5-loop's own Step 2d confirmation anyway. The invitation is a courtesy checkpoint, not an approval gate (removed deliberately in #78's consistency sweep).
|
|
64
|
+
|
|
65
|
+
A stage that changes shape changes it **in this block first**; the per-stage pointer stays a pointer.
|
|
66
|
+
|
|
56
67
|
## Configuration Reading
|
|
57
68
|
|
|
58
69
|
Read `forge.config.json` from the project root. If it doesn't exist, use defaults.
|
|
@@ -130,7 +141,7 @@ mkdir -p "<specsDir>"
|
|
|
130
141
|
[ -f "<specsDir>/AGENTS.md" ] || cp "$R/references/templates/specs-hygiene/AGENTS.md" "<specsDir>/AGENTS.md"
|
|
131
142
|
```
|
|
132
143
|
|
|
133
|
-
If the host is Claude (the
|
|
144
|
+
If the host is Claude (the Claude-native question tool is available), also ensure the Claude-framed variant:
|
|
134
145
|
|
|
135
146
|
```bash
|
|
136
147
|
R="$(bash -c 'for d in "${CLAUDE_PLUGIN_ROOT:-}" "$HOME"/.claude/skills/feature-forge "$HOME"/.claude/plugins/cache/*/feature-forge/* "$HOME"/.claude/plugins/*/feature-forge "$HOME"/.agents/skills/feature-forge ./.agents/skills/feature-forge; do [ -x "$d/scripts/forge-root.sh" ] && exec "$d/scripts/forge-root.sh"; done')"
|
|
@@ -191,7 +202,7 @@ Pipeline state is written by the `state-*` verbs of `scripts/forge-session.py`
|
|
|
191
202
|
|
|
192
203
|
If a `state-*` verb exits 2, surface the plain `Error:` line from stderr verbatim, do **not** proceed to the next step of the surrounding protocol, and do **not** hand-author the JSON as a workaround. The stage remains resumable because the entry stamp is already on disk — re-run the verb once the cause is fixed.
|
|
193
204
|
|
|
194
|
-
**The
|
|
205
|
+
**The nine `state-*` verbs.** `state-enter` (Stage-Entry Guard), `state-artifact` (incremental artifact tracking), `state-complete` (Git Commit Protocol), `state-skip` (the deliberate forge-6-docs documentation skip — scoped to that one stage; writes `status: "skipped"` + `skippedAt`, refuses to erase a record of docs that exist, and is the only sanctioned writer of a skipped docs stage), `state-branch` (Branch Setup and Branch Reconciliation), `state-note` (the Immediate Downstream Note below, and the optional completion note at stage closure), `state-decision` (deferred decisions), `state-ecr` (epic change requests), and `state-verify` (one `forge-verify-*` verification transition — below). The `--epic` member requirement and the exit-2 failure protocol above apply to **every** one of them, `state-verify` included; no verify entry is ever hand-authored.
|
|
195
206
|
|
|
196
207
|
### `state-verify` — verification results and provenance
|
|
197
208
|
|
|
@@ -395,7 +406,7 @@ Invoke this block **at the head of any post-entry step that writes a stage artif
|
|
|
395
406
|
|
|
396
407
|
1. **Proceed** when `stages.{stage}.status` is `"in-progress"` (this session's Entry Stamp — you are finishing the run you started) or absent/`pending`. Run the write / exit normally.
|
|
397
408
|
|
|
398
|
-
2. **Detect-and-refuse** when ALL of these hold: `stages.{stage}.status ∈ {"complete", "stale"}` **AND** the stage's artifacts (incl. `TRACEABILITY.md` for forge-3-specs) exist on disk **AND** a `commitHash` is recorded for the stage **AND** you did **not** author this stage earlier in the current session. This is a stale/replayed continuation of an already-finished, committed stage. Do **not** overwrite the artifact or re-run the exit. Route instead to the **Stage-Entry Guard**'s *Re-authoring* path: surface the same `AskUserQuestion`
|
|
409
|
+
2. **Detect-and-refuse** when ALL of these hold: `stages.{stage}.status ∈ {"complete", "stale"}` **AND** the stage's artifacts (incl. `TRACEABILITY.md` for forge-3-specs) exist on disk **AND** a `commitHash` is recorded for the stage **AND** you did **not** author this stage earlier in the current session. This is a stale/replayed continuation of an already-finished, committed stage. Do **not** overwrite the artifact or re-run the exit. Route instead to the **Stage-Entry Guard**'s *Re-authoring* path: surface the same warning via `AskUserQuestion` ("A completed {stage} artifact already exists for '{feature}' (v{n}{, marked stale}). Continuing will create a new version. Proceed?"). Only on explicit confirmation re-enter from the Entry Stamp (the version bumps at exit); otherwise **stop** and report that the stage is already complete — cite the recorded `commitHash` and offer `/feature-forge:forge {feature}` to see true state.
|
|
399
410
|
|
|
400
411
|
When you cannot confirm you authored the current run, treat it as a replay and refuse: a false refuse costs one confirmation click; a false proceed overwrites a committed artifact and re-churns a stage version. `--force` follows Force Mode (skip the gate, treat as a deliberate re-author).
|
|
401
412
|
|
|
@@ -47,8 +47,8 @@ an epic member. Only the flags below are stage-specific; pass no others.
|
|
|
47
47
|
|---|---|---|
|
|
48
48
|
| `forge-0-epic` | `forge-0-epic` | `--next-feature "{member}"` when a concrete member exists |
|
|
49
49
|
| `forge-1-prd` … `forge-4-backlog` | that stage's own id | none beyond identity/capability |
|
|
50
|
-
| `forge-5-loop` | `forge-5-loop` | `--outcome` — one of `complete`, `partial`, `blocked`, `needs-human`, `deferred` |
|
|
51
|
-
| `forge-6-docs` | `forge-6-docs` | `--outcome` — `complete` or `
|
|
50
|
+
| `forge-5-loop` | `forge-5-loop` | `--outcome` — one of `complete`, `partial`, `blocked`, `needs-human`, `deferred`, `resolved`; optional `--cause dependency-starvation` with `--outcome partial` |
|
|
51
|
+
| `forge-6-docs` | `forge-6-docs` | `--outcome` — `complete`, `blocked`, or `skipped` (deliberate docs skip, persisted via `state-skip` before the exit; routes like `complete` with honest wording) |
|
|
52
52
|
| direct `forge-verify` | `forge-verify` | `--owner direct`, `--outcome` (`passed`, `findings`, `skipped`, `failed`), and served-stage metadata |
|
|
53
53
|
| nested `forge-verify` | `forge-verify` | `--owner nested`, plus the same outcome and served-stage metadata |
|
|
54
54
|
| direct/nested `forge-fix` | `forge-fix` | the matching `--owner`, a `FixOutcome` (`no-findings`, `decisions`, `failed`, `applied`, `reverified`, `reverify-findings`, `deferred`), and served-stage metadata |
|
|
@@ -100,9 +100,9 @@ Obey the DIRECTIVES it prints, in the consumption order this protocol fixes: sur
|
|
|
100
100
|
|
|
101
101
|
The stamp is shown with `--host claude`; the adapter build substitutes `pi`/`generic` per
|
|
102
102
|
target, and §"Host and capability determination" below governs the value. The literal is
|
|
103
|
-
deliberate — `scripts/build-adapters.py` keys its host translation on the exact
|
|
104
|
-
|
|
105
|
-
that line that is not a placeholder.
|
|
103
|
+
deliberate — `scripts/build-adapters.py` keys its host translation on the exact canon
|
|
104
|
+
value of that flag, and the stamp sites are compared byte-for-byte, so it is the one token
|
|
105
|
+
in that line that is not a placeholder.
|
|
106
106
|
|
|
107
107
|
## Host and capability determination
|
|
108
108
|
|
|
@@ -110,8 +110,9 @@ Before the call, compute the two inputs independently. They are unrelated: **a h
|
|
|
110
110
|
implies a capability**, and the script takes `--verify-capability` at face value.
|
|
111
111
|
|
|
112
112
|
**`--host`** describes only the active adapter command surface — `claude`, `pi`, or
|
|
113
|
-
`generic`. It selects command syntax (
|
|
114
|
-
fresh-session wording (
|
|
113
|
+
`generic`. It selects command syntax (Claude's stage-command prefix vs Pi's `/skill:` vs
|
|
114
|
+
host-neutral) and fresh-session wording (Claude's clear command vs Pi's `/new` vs neutral
|
|
115
|
+
prose). Nothing else.
|
|
115
116
|
|
|
116
117
|
**`--verify-capability interactive`** is passed only when **both** of these hold:
|
|
117
118
|
|
|
@@ -151,7 +152,8 @@ production successor** while verification is unresolved.
|
|
|
151
152
|
- a capable Pi session is `--host pi --verify-capability interactive`, and receives the
|
|
152
153
|
same logical gate a capable Claude session does;
|
|
153
154
|
- Pi without a dispatchable verifier is `--host pi --verify-capability manual`;
|
|
154
|
-
- a Claude session that cannot dispatch
|
|
155
|
+
- a Claude session that cannot dispatch keeps the Claude host value with
|
|
156
|
+
`--verify-capability manual`.
|
|
155
157
|
|
|
156
158
|
Interactive gate options keep their explicit labels, their recommended default, and their
|
|
157
159
|
one-line trade-off descriptions (below). The manual path prints the verify command as the
|
|
@@ -199,6 +201,44 @@ second sentinel-terminated block **inside** an outer stage's exit, breaking the
|
|
|
199
201
|
exactly-one-terminal-block rule — and the canon guard cannot catch it, because both
|
|
200
202
|
wordings legitimately appear in the same file. Judge the token, not the phrasing.
|
|
201
203
|
|
|
204
|
+
## Caller-side resumption: the declared resume point
|
|
205
|
+
|
|
206
|
+
The `owner:` token and `terminalOwnedBy` arbitrate who prints — but they specify only
|
|
207
|
+
the **callee** side: a nested skill stays quiet and returns its structured result. This
|
|
208
|
+
section is the reciprocal, caller-side half of that contract.
|
|
209
|
+
|
|
210
|
+
**On a sub-skill's return, the caller re-owns the terminal.** Every closing instruction
|
|
211
|
+
in the callee's own body — its report-and-stop posture, its "confirm the result" close,
|
|
212
|
+
its own next-steps habits — is void for this turn. The caller resumes at its **declared
|
|
213
|
+
resume point**, in the same turn, and its remaining steps run to its own terminal.
|
|
214
|
+
|
|
215
|
+
**Every Skill-tool delegation site declares, at the invocation, what happens on
|
|
216
|
+
return.** Suppression without resumption is the failure mode this section closes: the
|
|
217
|
+
callee's closing posture is the freshest instruction in context while the caller's next
|
|
218
|
+
step is the oldest, so an undeclared return silently ends the run one layer too early —
|
|
219
|
+
the caller's remaining steps (validation, state writes, commit, stage exit) dropped,
|
|
220
|
+
with no error surfaced. An implicit "let it run to its natural stopping point" is that
|
|
221
|
+
bug spelled politely, and it is banned on delegation sites. A site takes one of two
|
|
222
|
+
declared postures:
|
|
223
|
+
|
|
224
|
+
- **Delegate-and-resume** — the callee is a sub-step of the caller: the site names the
|
|
225
|
+
caller's own step that control returns to, and the caller continues there in the same
|
|
226
|
+
turn. The callee never owns the caller's terminal. The worked instance is
|
|
227
|
+
`forge-4-backlog` Step 4's **Return contract** for the `author-backlog` delegation
|
|
228
|
+
(control returns at Step 5; the sub-skill's direct-invocation posture — its approval
|
|
229
|
+
gate and its validate-and-confirm close — is explicitly disapplied on the delegated
|
|
230
|
+
path). New delegation sites follow that pattern rather than re-deriving it.
|
|
231
|
+
- **Terminal handoff** — the caller's job ends at the invocation and the invoked skill
|
|
232
|
+
owns the terminal from there on (e.g. the navigator's `autoInvokeNextStage`
|
|
233
|
+
"continue in this session" advance into the next production stage). Declaring the
|
|
234
|
+
handoff is what keeps it distinct from an accidental drop.
|
|
235
|
+
|
|
236
|
+
Scope: this contract governs **Skill-tool delegation within one session**. The
|
|
237
|
+
truncated-verifier-return guard (forge-verify's `findings-template.md`, "Truncated
|
|
238
|
+
Verifier Returns") is a different mechanism — it polices what an **Agent-dispatched
|
|
239
|
+
subagent's** return payload must contain, not where a caller resumes. A dispatch site
|
|
240
|
+
can be subject to both; satisfy each on its own terms.
|
|
241
|
+
|
|
202
242
|
## Directive consumption order
|
|
203
243
|
|
|
204
244
|
`stage-exit` emits a DIRECTIVES object and (for a direct owner) a NEXT-STEPS block. The
|
|
@@ -299,7 +339,11 @@ first:
|
|
|
299
339
|
a stage's artifact commit.
|
|
300
340
|
- **Skip for now** — go straight to the NEXT-STEPS block without verifying. Record this
|
|
301
341
|
stage's verify status as `skipped` in pipeline state (via `state-verify`, never by hand)
|
|
302
|
-
**only** on an explicit skip — a skip does not go stale.
|
|
342
|
+
**only** on an explicit skip — a skip does not go stale. Exception: if the existing
|
|
343
|
+
entry records `passed` or `findings-applied` (a resolved result whose freshness has
|
|
344
|
+
merely lapsed), write **nothing** — `state-verify` refuses to demote a resolved status
|
|
345
|
+
to `skipped` (#203), and the recorded result stands on its own; the user's decline is
|
|
346
|
+
honored by simply not re-verifying.
|
|
303
347
|
|
|
304
348
|
**Advancement is allowed only after a pass, or after an explicit skip has been
|
|
305
349
|
persisted.** Choosing to stop, or losing the interaction, produces no advancing terminal
|
|
@@ -358,8 +402,8 @@ directive is informational — you do **not** re-derive the wording:
|
|
|
358
402
|
unchanged; the block appends a non-blocking reminder line ("You also flagged N epic
|
|
359
403
|
change(s) to reconcile when convenient …"). This is *finish-then-edit*.
|
|
360
404
|
|
|
361
|
-
Either way the added lines are host-neutral (no
|
|
362
|
-
sentinel; just print the NEXT-STEPS block verbatim as always.
|
|
405
|
+
Either way the added lines are host-neutral (they name no fresh-session command) and sit
|
|
406
|
+
**above** the sentinel; just print the NEXT-STEPS block verbatim as always.
|
|
363
407
|
|
|
364
408
|
### Deferred decisions — do not solicit next-stage decisions at this exit
|
|
365
409
|
|
|
@@ -12,9 +12,12 @@ Usage:
|
|
|
12
12
|
python3 epic-manifest.py render-status <epic> [--specs-dir DIR] [--json]
|
|
13
13
|
python3 epic-manifest.py add-feature <epic> <name> --charter TEXT \
|
|
14
14
|
[--depends-on A,B] [--specs-dir DIR] [--json]
|
|
15
|
+
python3 epic-manifest.py adopt-feature <epic> <name> [--charter TEXT] \
|
|
16
|
+
[--depends-on A,B] [--specs-dir DIR] [--json]
|
|
15
17
|
python3 epic-manifest.py remove-feature <epic> <name> [--specs-dir DIR] [--json]
|
|
16
18
|
python3 epic-manifest.py reorder <epic> --order A,B,C [--specs-dir DIR] [--json]
|
|
17
19
|
python3 epic-manifest.py set-dep <epic> <name> --depends-on A,B [--specs-dir DIR] [--json]
|
|
20
|
+
python3 epic-manifest.py set-charter <epic> <name> --charter TEXT [--specs-dir DIR] [--json]
|
|
18
21
|
python3 epic-manifest.py set-status <epic> --status STATE [--specs-dir DIR] [--json]
|
|
19
22
|
|
|
20
23
|
Exit codes:
|
|
@@ -179,6 +182,12 @@ class FeatureStatus(TypedDict):
|
|
|
179
182
|
blockingEpicChangeRequests: The subset of ``openEpicChangeRequests`` with
|
|
180
183
|
``blocksCurrent == true`` (pause-now, reconcile-before-specs). Always
|
|
181
184
|
``<= openEpicChangeRequests``.
|
|
185
|
+
docsStatus: The member's recorded ``stages["forge-6-docs"].status``, or
|
|
186
|
+
None when absent/malformed. DISTINCT from the orchestration rollup
|
|
187
|
+
(which reads forge-5-loop + impl verify and deliberately ignores
|
|
188
|
+
docs): consumers gating a DOCUMENTATION decision — the epic-level
|
|
189
|
+
doc offer (#173) — read this, treating ``complete`` and ``skipped``
|
|
190
|
+
(#197's deliberate skip) both as docs-settled.
|
|
182
191
|
"""
|
|
183
192
|
|
|
184
193
|
name: str
|
|
@@ -188,6 +197,7 @@ class FeatureStatus(TypedDict):
|
|
|
188
197
|
unmetDeps: list[str]
|
|
189
198
|
openEpicChangeRequests: int
|
|
190
199
|
blockingEpicChangeRequests: int
|
|
200
|
+
docsStatus: str | None
|
|
191
201
|
|
|
192
202
|
|
|
193
203
|
class Rollup(TypedDict):
|
|
@@ -390,7 +400,8 @@ def atomic_write(path: Path, data: dict) -> None:
|
|
|
390
400
|
and fsyncs it, then ``os.replace`` swaps it into place. ``os.replace`` is
|
|
391
401
|
atomic on POSIX within a single filesystem, so an interrupted write never
|
|
392
402
|
leaves a partial or corrupt manifest (REQ-ROBUST-03). Concurrent multi-
|
|
393
|
-
session mutation is out of scope (single-writer assumed, PRD REQ-ROBUST-03
|
|
403
|
+
session mutation is out of scope (single-writer assumed, PRD REQ-ROBUST-03;
|
|
404
|
+
decision record: references/decisions/single-writer-threat-model.md, #180).
|
|
394
405
|
|
|
395
406
|
Args:
|
|
396
407
|
path: The destination manifest path (e.g. {epic}/epic-manifest.json).
|
|
@@ -1202,6 +1213,13 @@ def derive_status(feature_dir: Path) -> FeatureStatus:
|
|
|
1202
1213
|
open_count = len(open_reqs)
|
|
1203
1214
|
blocking_count = sum(1 for r in open_reqs if r.get("blocksCurrent") is True)
|
|
1204
1215
|
|
|
1216
|
+
# Docs state for the epic-level doc offer gate (#173). Read directly rather
|
|
1217
|
+
# than folded into `derived`: docs completeness is deliberately invisible to
|
|
1218
|
+
# the orchestration rollup, and conflating them is the bug this field fixes.
|
|
1219
|
+
stages = state.get("stages", {})
|
|
1220
|
+
docs = stages.get("forge-6-docs") if isinstance(stages, dict) else None
|
|
1221
|
+
docs_status = docs.get("status") if isinstance(docs, dict) else None
|
|
1222
|
+
|
|
1205
1223
|
return {
|
|
1206
1224
|
"name": name,
|
|
1207
1225
|
"stage": stage,
|
|
@@ -1210,6 +1228,7 @@ def derive_status(feature_dir: Path) -> FeatureStatus:
|
|
|
1210
1228
|
"unmetDeps": [],
|
|
1211
1229
|
"openEpicChangeRequests": open_count,
|
|
1212
1230
|
"blockingEpicChangeRequests": blocking_count,
|
|
1231
|
+
"docsStatus": docs_status if isinstance(docs_status, str) else None,
|
|
1213
1232
|
}
|
|
1214
1233
|
|
|
1215
1234
|
|
|
@@ -1232,14 +1251,16 @@ def _next_production_stage(state: dict) -> str | None:
|
|
|
1232
1251
|
The epic-side mirror of ``next_stage()`` in forge-session.py, and for the same
|
|
1233
1252
|
reason its docstring gives: "what runs next" is DERIVED from ``stages[].status``,
|
|
1234
1253
|
never read from the stored ``currentStage``. A missing, pending, in-progress or
|
|
1235
|
-
stale stage all count as "not done"
|
|
1254
|
+
stale stage all count as "not done"; ``complete`` and ``skipped`` both count as
|
|
1255
|
+
done (``skipped`` is legal only on forge-6-docs — schema ``docsStageEntry`` —
|
|
1256
|
+
so a deliberately docs-skipped member is never re-offered forge-6-docs, #197).
|
|
1236
1257
|
"""
|
|
1237
1258
|
stages = state.get("stages")
|
|
1238
1259
|
if not isinstance(stages, dict):
|
|
1239
1260
|
return _PRODUCTION_STAGES[0]
|
|
1240
1261
|
for stage in _PRODUCTION_STAGES:
|
|
1241
1262
|
entry = stages.get(stage)
|
|
1242
|
-
if not isinstance(entry, dict) or entry.get("status")
|
|
1263
|
+
if not isinstance(entry, dict) or entry.get("status") not in ("complete", "skipped"):
|
|
1243
1264
|
return stage
|
|
1244
1265
|
return None
|
|
1245
1266
|
|
|
@@ -1607,6 +1628,52 @@ def set_dep(
|
|
|
1607
1628
|
return _bump_and_write(epic_dir, specs_dir, manifest)
|
|
1608
1629
|
|
|
1609
1630
|
|
|
1631
|
+
def set_charter(
|
|
1632
|
+
epic_dir: Path, specs_dir: Path, name: str, charter: str
|
|
1633
|
+
) -> list[Finding]:
|
|
1634
|
+
"""Replace a member feature's charter text (#166).
|
|
1635
|
+
|
|
1636
|
+
The charter is the member field most likely to need revision after creation
|
|
1637
|
+
(an ADR lands, a boundary moves, a member turns out to own more than
|
|
1638
|
+
expected) — and it previously had no mutator, so edit mode had no sanctioned
|
|
1639
|
+
path to rewrite one. Same shape as ``set_dep``: an atomic, re-validated,
|
|
1640
|
+
revision-bumping replacement. EPIC.md prose is NOT touched — the agent
|
|
1641
|
+
re-syncs the mirror afterward (edit-mode Step E5), exactly as for every
|
|
1642
|
+
other mutation.
|
|
1643
|
+
|
|
1644
|
+
Args:
|
|
1645
|
+
epic_dir: The epic subtree directory.
|
|
1646
|
+
specs_dir: The configured specs directory.
|
|
1647
|
+
name: The member feature to edit.
|
|
1648
|
+
charter: The replacement charter text (argparse requires the flag; an
|
|
1649
|
+
empty string is refused below — a charter is required prose, and
|
|
1650
|
+
blanking it would only manufacture a schema-shaped hole).
|
|
1651
|
+
|
|
1652
|
+
Returns:
|
|
1653
|
+
Empty list on success; blocking findings (not-found / empty-charter, or
|
|
1654
|
+
anything re-validation raises) on refusal — manifest left unchanged.
|
|
1655
|
+
|
|
1656
|
+
Raises:
|
|
1657
|
+
UsageError: Unsafe name, corrupt/missing manifest, or write failure.
|
|
1658
|
+
"""
|
|
1659
|
+
if not charter.strip():
|
|
1660
|
+
return [{"code": "empty-charter",
|
|
1661
|
+
"message": "refusing to blank a charter: pass non-empty --charter text",
|
|
1662
|
+
"feature": name}]
|
|
1663
|
+
manifest = load_manifest(epic_dir)
|
|
1664
|
+
by_name = {
|
|
1665
|
+
f["name"]: f
|
|
1666
|
+
for f in manifest.get("features", [])
|
|
1667
|
+
if isinstance(f, dict) and isinstance(f.get("name"), str)
|
|
1668
|
+
}
|
|
1669
|
+
if name not in by_name:
|
|
1670
|
+
return [{"code": "not-found",
|
|
1671
|
+
"message": f"feature {name!r} is not a member of epic {epic_dir.name!r}",
|
|
1672
|
+
"feature": name}]
|
|
1673
|
+
by_name[name]["charter"] = charter
|
|
1674
|
+
return _bump_and_write(epic_dir, specs_dir, manifest)
|
|
1675
|
+
|
|
1676
|
+
|
|
1610
1677
|
def set_status(epic_dir: Path, specs_dir: Path, status: str) -> list[Finding]:
|
|
1611
1678
|
"""Set the epic-level lifecycle status.
|
|
1612
1679
|
|
|
@@ -1919,7 +1986,8 @@ def _dispatch(args: argparse.Namespace, specs_dir: Path) -> int:
|
|
|
1919
1986
|
return 0
|
|
1920
1987
|
|
|
1921
1988
|
# Mutators ---------------------------------------------------------------
|
|
1922
|
-
if cmd in {"add-feature", "remove-feature", "reorder", "set-dep", "set-
|
|
1989
|
+
if cmd in {"add-feature", "remove-feature", "reorder", "set-dep", "set-charter",
|
|
1990
|
+
"set-status"}:
|
|
1923
1991
|
epic_dir = contained_path(specs_dir, args.epic)
|
|
1924
1992
|
if cmd == "add-feature":
|
|
1925
1993
|
findings = add_feature(
|
|
@@ -1934,6 +2002,8 @@ def _dispatch(args: argparse.Namespace, specs_dir: Path) -> int:
|
|
|
1934
2002
|
findings = set_dep(
|
|
1935
2003
|
epic_dir, specs_dir, args.name, _split_list(args.depends_on)
|
|
1936
2004
|
)
|
|
2005
|
+
elif cmd == "set-charter":
|
|
2006
|
+
findings = set_charter(epic_dir, specs_dir, args.name, args.charter)
|
|
1937
2007
|
else: # set-status
|
|
1938
2008
|
findings = set_status(epic_dir, specs_dir, args.status)
|
|
1939
2009
|
if findings:
|
|
@@ -2028,6 +2098,14 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
2028
2098
|
add_specs_dir(p_setdep)
|
|
2029
2099
|
add_json(p_setdep)
|
|
2030
2100
|
|
|
2101
|
+
# set-charter ----------------------------------------------------------- #
|
|
2102
|
+
p_setcharter = sub.add_parser("set-charter", help="Replace a feature's charter")
|
|
2103
|
+
p_setcharter.add_argument("epic")
|
|
2104
|
+
p_setcharter.add_argument("name")
|
|
2105
|
+
p_setcharter.add_argument("--charter", required=True, help="Replacement charter text")
|
|
2106
|
+
add_specs_dir(p_setcharter)
|
|
2107
|
+
add_json(p_setcharter)
|
|
2108
|
+
|
|
2031
2109
|
# set-status ------------------------------------------------------------ #
|
|
2032
2110
|
p_setstatus = sub.add_parser("set-status", help="Set the epic lifecycle status")
|
|
2033
2111
|
p_setstatus.add_argument("epic")
|