diff --git a/src/resources/extensions/gsd/bootstrap/write-gate.ts b/src/resources/extensions/gsd/bootstrap/write-gate.ts index 3ea924ddc..b8e6cf8e5 100644 --- a/src/resources/extensions/gsd/bootstrap/write-gate.ts +++ b/src/resources/extensions/gsd/bootstrap/write-gate.ts @@ -50,10 +50,6 @@ let pendingGateId: string | null = null; * These appear in discuss.md (depth/requirements/roadmap). */ const GATE_QUESTION_PATTERNS = [ - "layer1_scope_gate", - "layer2_architecture_gate", - "layer3_error_gate", - "layer4_quality_gate", "depth_verification", ] as const; diff --git a/src/resources/extensions/gsd/templates/context.md b/src/resources/extensions/gsd/templates/context.md index 3e19bb788..0111e7c83 100644 --- a/src/resources/extensions/gsd/templates/context.md +++ b/src/resources/extensions/gsd/templates/context.md @@ -38,6 +38,28 @@ To call this milestone complete, we must prove: - {{one real end-to-end scenario}} - {{what cannot be simulated if this milestone is to be considered truly done}} +## Architectural Decisions + +### {{decisionTitle}} + +**Decision:** {{decisionStatement}} + +**Rationale:** {{rationale}} + +**Alternatives Considered:** +- {{alternative}} — {{whyNotChosen}} + +--- + +> Add additional decisions as separate `### Decision Title` blocks following the same structure above. +> See `.gsd/DECISIONS.md` for the full append-only register of all project decisions. + +## Error Handling Strategy + +{{errorHandlingStrategy}} + +> Describe the approach for handling failures, edge cases, and error propagation. Include retry policies, fallback behaviors, and user-facing error messages where relevant. + ## Risks and Unknowns - {{riskOrUnknown}} — {{whyItMatters}} @@ -47,8 +69,6 @@ To call this milestone complete, we must prove: - `{{fileOrModule}}` — {{howItRelates}} - `{{fileOrModule}}` — {{howItRelates}} -> See `.gsd/DECISIONS.md` for all architectural and pattern decisions — it is an append-only register; read it during planning, append to it during execution. - ## Relevant Requirements - {{requirementId}} — {{howThisMilestoneAdvancesIt}} @@ -71,6 +91,18 @@ To call this milestone complete, we must prove: - {{systemOrService}} — {{howThisMilestoneInteractsWithIt}} +## Testing Requirements + +{{testingRequirements}} + +> Specify test types (unit, integration, e2e), coverage expectations, and specific test scenarios that must pass. + +## Acceptance Criteria + +{{acceptanceCriteria}} + +> Per-slice acceptance criteria gathered during discussion. Each slice should have clear, testable criteria. + ## Open Questions - {{question}} — {{currentThinking}} diff --git a/src/resources/extensions/gsd/tests/write-gate.test.ts b/src/resources/extensions/gsd/tests/write-gate.test.ts index 48c0c5524..04b2c4603 100644 --- a/src/resources/extensions/gsd/tests/write-gate.test.ts +++ b/src/resources/extensions/gsd/tests/write-gate.test.ts @@ -230,16 +230,13 @@ import { // ─── Scenario 19: isGateQuestionId recognizes all gate patterns ── test('write-gate: isGateQuestionId recognizes all gate patterns', () => { - assert.strictEqual(isGateQuestionId('layer1_scope_gate'), true); - assert.strictEqual(isGateQuestionId('layer2_architecture_gate'), true); - assert.strictEqual(isGateQuestionId('layer3_error_gate'), true); - assert.strictEqual(isGateQuestionId('layer4_quality_gate'), true); assert.strictEqual(isGateQuestionId('depth_verification'), true); assert.strictEqual(isGateQuestionId('depth_verification_M002'), true); - assert.strictEqual(isGateQuestionId('my_layer1_scope_gate_question'), true); + assert.strictEqual(isGateQuestionId('depth_verification_confirm'), true); // Non-gate question IDs assert.strictEqual(isGateQuestionId('project_intent'), false); assert.strictEqual(isGateQuestionId('feature_priority'), false); + assert.strictEqual(isGateQuestionId('layer1_scope_gate'), false); assert.strictEqual(isGateQuestionId(''), false); }); @@ -249,14 +246,14 @@ test('write-gate: pending gate lifecycle (set, get, clear)', () => { clearDiscussionFlowState(); assert.strictEqual(getPendingGate(), null, 'starts null'); - setPendingGate('layer1_scope_gate'); - assert.strictEqual(getPendingGate(), 'layer1_scope_gate', 'set correctly'); + setPendingGate('depth_verification'); + assert.strictEqual(getPendingGate(), 'depth_verification', 'set correctly'); clearPendingGate(); assert.strictEqual(getPendingGate(), null, 'cleared correctly'); // clearDiscussionFlowState also clears pending gate - setPendingGate('layer2_architecture_gate'); + setPendingGate('depth_verification_M002'); clearDiscussionFlowState(); assert.strictEqual(getPendingGate(), null, 'clearDiscussionFlowState clears pending gate'); }); @@ -265,12 +262,12 @@ test('write-gate: pending gate lifecycle (set, get, clear)', () => { test('write-gate: shouldBlockPendingGate blocks write/edit during pending gate', () => { clearDiscussionFlowState(); - setPendingGate('layer1_scope_gate'); + setPendingGate('depth_verification'); // write should be blocked during discussion const writeResult = shouldBlockPendingGate('write', 'M001', false); assert.strictEqual(writeResult.block, true, 'write should be blocked'); - assert.ok(writeResult.reason!.includes('layer1_scope_gate'), 'reason mentions the gate'); + assert.ok(writeResult.reason!.includes('depth_verification'), 'reason mentions the gate'); // edit should be blocked const editResult = shouldBlockPendingGate('edit', 'M001', false); @@ -287,7 +284,7 @@ test('write-gate: shouldBlockPendingGate blocks write/edit during pending gate', test('write-gate: shouldBlockPendingGate allows read-only and ask_user_questions during pending gate', () => { clearDiscussionFlowState(); - setPendingGate('layer1_scope_gate'); + setPendingGate('depth_verification'); // ask_user_questions is always safe (model needs to re-ask) assert.strictEqual(shouldBlockPendingGate('ask_user_questions', 'M001').block, false); @@ -304,7 +301,7 @@ test('write-gate: shouldBlockPendingGate allows read-only and ask_user_questions test('write-gate: shouldBlockPendingGate blocks outside discussion when a gate is pending', () => { clearDiscussionFlowState(); - setPendingGate('layer1_scope_gate'); + setPendingGate('depth_verification'); // No milestoneId and no queue phase — still block because the gate is pending const result = shouldBlockPendingGate('write', null, false); @@ -330,7 +327,7 @@ test('write-gate: shouldBlockPendingGate blocks in queue mode when gate is pendi test('write-gate: shouldBlockPendingGateBash allows read-only commands during pending gate', () => { clearDiscussionFlowState(); - setPendingGate('layer2_architecture_gate'); + setPendingGate('depth_verification'); assert.strictEqual(shouldBlockPendingGateBash('cat file.txt', 'M001').block, false); assert.strictEqual(shouldBlockPendingGateBash('git log --oneline', 'M001').block, false); @@ -344,11 +341,11 @@ test('write-gate: shouldBlockPendingGateBash allows read-only commands during pe test('write-gate: shouldBlockPendingGateBash blocks mutating commands during pending gate', () => { clearDiscussionFlowState(); - setPendingGate('layer2_architecture_gate'); + setPendingGate('depth_verification'); const result = shouldBlockPendingGateBash('npm run build', 'M001'); assert.strictEqual(result.block, true, 'mutating bash should be blocked'); - assert.ok(result.reason!.includes('layer2_architecture_gate')); + assert.ok(result.reason!.includes('depth_verification')); clearDiscussionFlowState(); }); @@ -365,7 +362,7 @@ test('write-gate: no pending gate means no blocking', () => { // ─── Scenario 28: resetWriteGateState clears pending gate ── test('write-gate: resetWriteGateState clears pending gate', () => { - setPendingGate('layer3_error_gate'); + setPendingGate('depth_verification'); resetWriteGateState(); assert.strictEqual(getPendingGate(), null); });