diff --git a/.changeset/zesty-voles-roar.md b/.changeset/zesty-voles-roar.md new file mode 100644 index 000000000..853905e50 --- /dev/null +++ b/.changeset/zesty-voles-roar.md @@ -0,0 +1,5 @@ +--- +type: Fixed +pr: 275 +--- +Fixed plan-phase decision coverage gate compatibility with top-level .passed/.message command output. diff --git a/get-shit-done/workflows/plan-phase.md b/get-shit-done/workflows/plan-phase.md index f37ccf75b..a9252a316 100644 --- a/get-shit-done/workflows/plan-phase.md +++ b/get-shit-done/workflows/plan-phase.md @@ -1522,8 +1522,8 @@ if [ "$GATE_CFG" != "false" ]; then # `passed: true` covers both real-pass and skipped cases (gate disabled / no CONTEXT.md / # no trackable decisions). Verify-phase counterpart deliberately omits this exit-1 — that # gate is non-blocking by design (review finding F15). - echo "$GATE_RESULT" | jq -e '.data.passed == true' >/dev/null || { - echo "$GATE_RESULT" | jq -r '.data.message' + echo "$GATE_RESULT" | jq -e '(.passed // .data.passed) == true' >/dev/null || { + echo "$GATE_RESULT" | jq -r '(.message // .data.message // "Decision coverage gate failed.")' exit 1 } fi diff --git a/tests/bug-2492-context-coverage-gate.test.cjs b/tests/bug-2492-context-coverage-gate.test.cjs index c92f5eee1..4e521fd79 100644 --- a/tests/bug-2492-context-coverage-gate.test.cjs +++ b/tests/bug-2492-context-coverage-gate.test.cjs @@ -94,13 +94,26 @@ describe('plan-phase decision-coverage gate (#2492)', () => { assert.ok(gateIdx !== -1); const snippet = md.slice(gateIdx, gateIdx + 800); // Accept either an inline `|| exit 1` or a `|| { ...; exit 1; }` group. - const hasJqGuard = /jq[^\n]*passed\s*==\s*true/.test(snippet); + const hasJqGuard = + /jq[^\n]*\.data\.passed\s*==\s*true/.test(snippet) || + /jq[^\n]*\(\.passed\s*\/\/\s*\.data\.passed\)\s*==\s*true/.test(snippet); const hasExitOne = /\|\|\s*(?:exit\s+1|\{[\s\S]{0,200}?exit\s+1)/.test(snippet); assert.ok( hasJqGuard && hasExitOne, 'plan-phase gate must guard with `jq -e .passed == true || exit 1` (or `|| { ...; exit 1; }`) to actually block', ); }); + + test('plan-phase gate accepts top-level .passed field from CLI output (#275)', () => { + const gateIdx = md.indexOf('check.decision-coverage-plan'); + assert.ok(gateIdx !== -1, 'check.decision-coverage-plan invocation must exist'); + const snippet = md.slice(gateIdx, gateIdx + 800); + assert.ok( + /\.(?:passed)\s*==\s*true\s*\|\|\s*\.data\.passed\s*==\s*true/.test(snippet) || + /\(\.passed\s*\/\/\s*\.data\.passed\)\s*==\s*true/.test(snippet), + 'plan-phase gate must explicitly check top-level .passed with a compatibility fallback to .data.passed', + ); + }); }); describe('verify-phase decision-coverage gate (#2492)', () => {