agentic-sdlc-wizard 1.86.0 → 1.87.0

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.
@@ -13,7 +13,7 @@
13
13
  "name": "sdlc-wizard",
14
14
  "source": ".",
15
15
  "description": "SDLC enforcement for AI agents — TDD, planning, self-review, CI shepherd",
16
- "version": "1.86.0",
16
+ "version": "1.87.0",
17
17
  "author": {
18
18
  "name": "Stefan Ayala"
19
19
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sdlc-wizard",
3
- "version": "1.86.0",
3
+ "version": "1.87.0",
4
4
  "description": "SDLC enforcement for AI agents — TDD, planning, self-review, CI shepherd",
5
5
  "author": {
6
6
  "name": "Stefan Ayala",
package/AI_SETUP_LANES.md CHANGED
@@ -9,13 +9,17 @@ This is **guidance, not a hard rule**. Maintainer override is always allowed.
9
9
  | Role | Model | Effort |
10
10
  |------|-------|--------|
11
11
  | **Advisor** | Fable 5 (via `advisorModel: "fable"`) | `high` (server-side) |
12
- | **Driver** | Sonnet 5 (`claude-sonnet-5`) | `high` default, `/effort xhigh` for hard tasks |
13
- | **Reviewer** | Codex (GPT-5.5) xhigh | — |
14
- | **Escalation** | Opus 4.8 xhigh or Fable 5 review | When stuck or high-stakes |
12
+ | **Driver** | Sonnet 5 (`claude-sonnet-5`) | `medium` default, escalate `high` → `xhigh` for hard tasks |
13
+ | **Reviewer** | Codex (GPT-5.6 Sol) xhigh | — |
14
+ | **Escalation** | Opus 4.8 xhigh takes over as driver (or run a Fable 5 review pass) | When stuck (2 failed attempts / LOW confidence) or high-stakes |
15
15
 
16
- The new standard. Sonnet 5 beats Opus 4.6 on every coding benchmark (SWE-bench Verified 85.2% vs 80.8%, Terminal-Bench 80.4% vs 65.4%) while using ~5x less Max quota per turn. Fable 5 advises at key decision points via native `advisorModel` (v2.1.170+). GPT-5.5 xhigh reviews cross-family. Escalate to Opus 4.8 xhigh for the hardest debugging or architecture decisions — don't run Opus as the daily driver (burns Max limits 2-3x faster).
16
+ The new standard. Sonnet 5 beats Opus 4.6 on every coding benchmark (SWE-bench Verified 85.2% vs 80.8%, Terminal-Bench 80.4% vs 65.4%) and generally uses less Max quota — but the savings are not a fixed ratio: Sonnet 5's newer tokenizer produces ~30% more tokens for the same text than Opus 4.6's (per Anthropic's pricing docs), and community cost reports suggest the advantage narrows at `high`/`xhigh`. No controlled Sonnet-5-vs-Opus-4.6 quota measurement exists — check your own burn with `/usage`. Fable 5 advises at key decision points via native `advisorModel` (v2.1.170+). GPT-5.6 Sol xhigh reviews cross-family. Escalate to Opus 4.8 xhigh for the hardest debugging or architecture decisions — don't run Opus as the daily driver.
17
17
 
18
- **Effort escalation ladder:** Start at `high` (Sonnet 5's default and sweet spot). Raise to `xhigh` when doing hard debugging, multi-file migrations, or long agent runs. `max` is rarely worth it — doubles cost for marginal gains per CodeRabbit testing.
18
+ **Effort escalation ladder:** Start at `medium` — CodeRabbit's testing found it captures most of Sonnet 5's upside at the lowest cost. Raise to `high` when medium struggles, `xhigh` for hard debugging, multi-file migrations, or long agent runs. `max` is rarely worth it — doubles cost for marginal gains per the same CodeRabbit testing.
19
+
20
+ **Two escalation axes — don't conflate them.** The effort ladder above raises reasoning *within* the Sonnet 5 driver. Model escalation is a different move: it *swaps the driver* — after 2 failed attempts, LOW confidence, or on a high-stakes change, Opus 4.8 xhigh takes over as driver (or run a Fable 5 review pass on the diff). Cranking Sonnet's effort past `xhigh` is not the escalation path.
21
+
22
+ **Advisor failure has a fallback, not a shrug.** `advisor()` is a server-side tool and does fail during API incidents. When it errors, spawn a Fable subagent as the fallback reviewer — the same rule the `/sdlc` skill carries ("if down, spawn Fable subagent"). The advisor check is never skipped; only its transport changes.
19
23
 
20
24
  **Requires:** Claude Code v2.1.197+ (Sonnet 5 alias resolution), Fable 5 access for advisor.
21
25
 
@@ -25,7 +29,7 @@ The new standard. Sonnet 5 beats Opus 4.6 on every coding benchmark (SWE-bench V
25
29
  |------|-------|--------|
26
30
  | **Advisor** | Fable 5 (via `advisorModel: "fable"`) | `high` (server-side) |
27
31
  | **Driver** | Opus 4.6 (`claude-opus-4-6`) | `max` |
28
- | **Reviewer** | Codex (GPT-5.5) xhigh | — |
32
+ | **Reviewer** | Codex (GPT-5.6 Sol) xhigh | — |
29
33
 
30
34
  The consistency-first lane. Opus 4.6 is the only model where `max` effort works without overthinking — months of field data, Active through at least Feb 2027, proven predictable. Lower benchmark scores than Sonnet 5 but higher consistency. Choose this when you've tuned prompts to Opus 4.6 behavior and reliability matters more than peak capability.
31
35
 
@@ -37,10 +41,10 @@ The consistency-first lane. Opus 4.6 is the only model where `max` effort works
37
41
  |------|-------|--------|
38
42
  | **Planner** | Opus 4.8 (via Plan Mode — Shift+Tab) | `xhigh` |
39
43
  | **Advisor** | Fable 5 or Opus 4.8 (via `advisorModel`) | — |
40
- | **Driver** | Sonnet 5 (auto execute mode) | `high` |
41
- | **Reviewer** | Codex (GPT-5.5) xhigh | — |
44
+ | **Driver** | Sonnet 5 (auto execute mode) | `medium`, escalate `high` for hard runs |
45
+ | **Reviewer** | Codex (GPT-5.6 Sol) xhigh | — |
42
46
 
43
- Cost-efficient hybrid using CC's native `opusplan` alias. Opus 4.8 reasons during Plan Mode, Sonnet 5 executes. Max-bundled — no API credit drain. Pin `model: "opusplan"` + `advisorModel: "fable"` in project settings. Sonnet 5 now uses 1M context natively (no `[1m]` suffix needed). GPT-5.5 xhigh is the cross-model reviewer.
47
+ Cost-efficient hybrid using CC's native `opusplan` alias. Opus 4.8 reasons during Plan Mode, Sonnet 5 executes. Max-bundled — no API credit drain. Pin `model: "opusplan"` + `advisorModel: "fable"` in project settings. Sonnet 5 now uses 1M context natively (no `[1m]` suffix needed). GPT-5.6 Sol xhigh is the cross-model reviewer.
44
48
 
45
49
  **Note:** Opus 4.6 cannot advise Sonnet 5 (rejected in the advisor pairing table). Use Fable 5 or Opus 4.8 as advisor for this lane.
46
50
 
@@ -56,7 +60,7 @@ The "just do the thing" lane. No TDD enforcement, no cross-model review, no plan
56
60
 
57
61
  ## When to Use Setup A
58
62
 
59
- The default choice for most SDLC work — full discipline (TDD, cross-model review) at a fraction of Setup B's quota cost:
63
+ The default choice for most SDLC work — full discipline (TDD, cross-model review) at generally lower quota cost than Setup B (see Credit-Spend Warning below):
60
64
 
61
65
  - Feature implementation and routine development
62
66
  - Documentation and examples
@@ -116,11 +120,13 @@ Setup D is for work where SDLC discipline overhead exceeds the value:
116
120
 
117
121
  ## Final Review Policy
118
122
 
119
- **Setups A, B, and C end at GPT-5.5 xhigh as the cross-model reviewer.** Claude can't grade its own homework — the reviewer always belongs to a different lab with different blind spots. See [CLAUDE_CODE_SDLC_WIZARD.md → "Cross-Model Review (Codex)"](CLAUDE_CODE_SDLC_WIZARD.md) for the handoff protocol.
123
+ **Setups A, B, and C end at GPT-5.6 Sol xhigh as the cross-model reviewer.** Claude can't grade its own homework — the reviewer always belongs to a different lab with different blind spots. See [CLAUDE_CODE_SDLC_WIZARD.md → "Cross-Model Review (Codex)"](CLAUDE_CODE_SDLC_WIZARD.md) for the handoff protocol.
120
124
 
121
125
  **Setup D has no reviewer** — the blast radius doesn't justify it. If you're unsure whether a task is truly Lite, it probably isn't. Escalate.
122
126
 
123
- If GPT-5.5 isn't available on your OpenAI account, Codex auto-falls back to GPT-5.4 — still keep `model_reasoning_effort="xhigh"`. Lower reasoning misses subtle bugs that the reviewer is the last gate to catch.
127
+ If GPT-5.6 Sol isn't available on your OpenAI account, Codex auto-falls back to Terra — still keep `model_reasoning_effort="xhigh"`. Lower reasoning misses subtle bugs that the reviewer is the last gate to catch.
128
+
129
+ **Escalation for unusually risky PRs:** `xhigh` is the evidence-based default — OpenAI's own migration guidance is to preserve the prior effort baseline, and no published data shows `max` or Pro mode catching meaningfully more real bugs than `xhigh` on ordinary PR review. For a PR you'd genuinely lose sleep over (security-sensitive, high blast radius, touches the installer or a consumer-facing template), escalate the reviewer to `max` or Pro mode — a once-per-PR gate is exactly the kind of low-frequency, high-stakes call site where the extra cost is easiest to justify. Don't make it the default.
124
130
 
125
131
  ## Version Requirement
126
132
 
@@ -140,10 +146,10 @@ If the advisor returns "Advisor unavailable," the server-side harness failed to
140
146
 
141
147
  **Step 1 — restart the session.** Exit and run `claude` (not `--resume`). A fresh process re-initializes the server handshake. This resolves most advisor failures.
142
148
 
143
- **Step 2 — if the API incident persists:**
149
+ **Step 2 — if the API incident persists, swap the transport, not the check:**
144
150
 
145
- - Continue with your driver model and no advisor — `/model sonnet` for Setup A, `/model claude-opus-4-6` for Setup B. Interactive stays on your Max subscription.
146
- - Or proceed without the advisor and let the Codex xhigh PR gate catch issues.
151
+ - Spawn a Fable subagent as the fallback reviewerthe `/sdlc` skill's standing rule ("if down, spawn Fable subagent"). Batch your plan or open questions into one subagent consult at each point where you'd have called `advisor()`. Runs interactively on your Max subscription like any other agent.
152
+ - Keep driving with your lane's model (`/model sonnet` for Setup A, `/model claude-opus-4-6` for Setup B). The subagent replaces the advisor's transport; the Codex xhigh PR gate remains the separate final backstop, not a substitute for the advisor check.
147
153
 
148
154
  **Last resort (scripted/CI only):**
149
155
 
@@ -155,15 +161,15 @@ Whichever path you use, the cross-model PR review gate still applies.
155
161
 
156
162
  ## Credit-Spend Warning
157
163
 
158
- **Setup B (Opus 4.6 max as both planner and driver) burns the 5-hour cap faster than Setup A** — Opus 4.6 max driving implementation is the expensive path; Sonnet 5 uses roughly 5x less quota per turn for comparable benchmark results. If you're hitting the cap mid-session on Setup B:
164
+ **Setup B (Opus 4.6 max as both planner and driver) burns the 5-hour cap faster than Setup A** — Opus 4.6 max driving implementation is the expensive path; Sonnet 5 at `medium`/`high` generally uses less quota for comparable benchmark results (the advantage narrows at `xhigh` — more turns per task plus tokenizer overhead). If you're hitting the cap mid-session on Setup B:
159
165
 
160
- - Drop to Setup A (Sonnet 5) for the remainder of the day — same discipline, far less quota burn
166
+ - Drop to Setup A (Sonnet 5) for the remainder of the day — same discipline, typically lower quota burn (widest advantage at `medium`)
161
167
  - Or drop to Setup D for grunt work that doesn't need deep reasoning
162
- - Or use Sonnet directly for the final mechanical edits, then run the GPT-5.5 reviewer over the whole diff at the end
168
+ - Or use Sonnet directly for the final mechanical edits, then run the GPT-5.6 Sol reviewer over the whole diff at the end
163
169
 
164
170
  **Setup D uses Sonnet** — same model as Setup A's driver, Max-bundled. One less model to manage if you're already on Setup A.
165
171
 
166
- The reviewer (GPT-5.5 xhigh) is billed against your OpenAI account, separately. Watch both bills.
172
+ The reviewer (GPT-5.6 Sol xhigh) is billed against your OpenAI account, separately. Watch both bills.
167
173
 
168
174
  ## Autocompact Thresholds
169
175
 
@@ -201,11 +207,11 @@ Credit allocations: Pro $20/mo, Max 5x $100/mo, Max 20x $200/mo. **No rollover.*
201
207
 
202
208
  ### What this means for the lanes
203
209
 
204
- - **Setup A — Sonnet 5 + Fable advisor:** Sonnet 5's native 1M context — interactive session, Max-bundled, no `[1m]` suffix needed. Fable 5 advisor via `advisorModel: "fable"` — also Max-bundled. GPT-5.5 xhigh reviewer on ChatGPT subscription. Roughly 5x less Max quota consumed per turn than Setup B.
205
- - **Setup B — Opus 4.6 Stability:** Opus 4.6 max driver on Max, 1M context included at standard rates (see above). Fable 5 advisor, Max-bundled. GPT-5.5 xhigh reviewer, separate.
210
+ - **Setup A — Sonnet 5 + Fable advisor:** Sonnet 5's native 1M context — interactive session, Max-bundled, no `[1m]` suffix needed. Fable 5 advisor via `advisorModel: "fable"` — also Max-bundled. GPT-5.6 Sol xhigh reviewer on ChatGPT subscription. Generally lower Max quota consumption than Setup B at the `medium` default (savings shrink at higher effort).
211
+ - **Setup B — Opus 4.6 Stability:** Opus 4.6 max driver on Max, 1M context included at standard rates (see above). Fable 5 advisor, Max-bundled. GPT-5.6 Sol xhigh reviewer, separate.
206
212
  - **Setup C — OpusPlan Hybrid:** **fully Max-bundled.** `opusplan` uses Opus (plan mode) + Sonnet (execute mode), both at their native context windows — no credit drain.
207
213
  - **⚠️ Avoid `sonnet[1m]` as a manual pin outside Setup A/C:** if your provider or gateway doesn't resolve Sonnet 5 to its native 1M automatically, forcing a `[1m]`-suffixed pin on an older Sonnet can draw from your usage credits pool ($3/$15 per Mtok) instead of your Max subscription. The `/model` picker shows this explicitly — watch for "Draws from usage credits."
208
- - **Reviewer (GPT-5.5 xhigh) in all three triads:** billed against your OpenAI account, completely separate from Anthropic.
214
+ - **Reviewer (GPT-5.6 Sol xhigh) in all three triads:** billed against your OpenAI account, completely separate from Anthropic.
209
215
  - **CI loops that use `claude -p` post-June-15:** these now bill against the separate Anthropic credit pool, not your Max subscription. The wizard's CI shepherd loops (E2E scoring, weekly-update jobs) are local-only on the maintainer's machine and stay on Max; consumer-repo CI integrations may need to budget the new credit pool.
210
216
 
211
217
  ### Bottom line
package/CHANGELOG.md CHANGED
@@ -4,6 +4,24 @@ All notable changes to the SDLC Wizard.
4
4
 
5
5
  > **Note:** This changelog is for humans to read. Don't manually apply these changes - just run the wizard ("Check for SDLC wizard updates") and it handles everything automatically.
6
6
 
7
+ ## [1.87.0] - 2026-07-14
8
+
9
+ ### Added
10
+ - **🏆 First external contribution in this repo's history: [@thejesh23](https://github.com/thejesh23)** (#444, PR #445 — merged under his authorship). GitHub Copilot CLI ≥ 1.0.65 tightened `argument-hint` frontmatter validation to string-only and silently dropped all 7 wizard skills from its command menu. Bare brackets (`argument-hint: [task description]`) parse as a YAML flow sequence, not a string — the feedback skill's hint even parsed as an array wrapping a *mapping* — and Claude Code's lenient rendering had hidden it since the fields were introduced. His report pinned the exact breaking version with primary-source links and listed every affected file (it matched our own repo-wide sweep exactly); his fix updated the live skills and the `cowork/` copies together. Out of 300+ merged PRs, contributor #1. Maintainer's words, on the record: *"he deserves it and I am forever grateful."*
11
+ - **#444 regression test** (PR #447): `test_argument_hint_frontmatter_is_string` parses every live + cowork SKILL.md frontmatter with real YAML and fails on any non-string `argument-hint`; also guards the wizard doc's copy-source examples (the frontmatter reference-table cell was #445's one untouched straggler — consumers copy these blocks, so an unquoted example re-inherits the bug into generated repos). Hardened per Codex round-1 finding: the grep uses `argument-hint:[[:space:]]*\[` because an exactly-one-space pattern false-greened on zero/two-space variants (mutation-verified both directions). Anti-vacuity guards prevent the test from passing on zero files or unparsed frontmatter. Cross-vendor SKILL.md compatibility is now tracked as ROADMAP #448.
12
+
13
+ ### Changed
14
+ - **GPT-5.6 Sol replaces GPT-5.5 as the cross-model reviewer** across all live guidance (#439, PR #441): `AI_SETUP_LANES.md`, `README.md`, `CLAUDE_CODE_SDLC_WIZARD.md`, both sdlc SKILL.md copies, `AGENTS.md`, repo `CLAUDE.md`. The unpinned auto-detect design is deliberately preserved (Codex CLI resolves your account's best model — proven live when it picked up Sol with zero config change); fallback chain documented as Sol → Terra. Reviewer effort stays `xhigh` per OpenAI's own migration guidance; Pro/`max` documented as escalation for unusually risky PRs. Historical citations (vending-bench, E2E audit, CHANGELOG) explicitly untouched and regression-guarded — rewriting them would falsify what actually ran.
15
+ - **Sonnet 5's documented default effort is now `medium`** (was `high`), and the "~5x less Max quota" claim is gone (#440, PR #443). Codex traced the 5x figure to commit `ab6fc9c` with zero supporting measurement anywhere; all 8 instances across 6 live-guidance files replaced with qualified language sourced to Anthropic's tokenizer note (Sonnet 5's newer tokenizer produces ~30% more tokens than Opus 4.6's for the same text; community cost reports suggest the advantage narrows at `high`/`xhigh`; no controlled measurement exists — check `/usage`). CodeRabbit — the source the wizard already cited — actually recommends `medium`. Escalation ladder is now `medium` → `high` → `xhigh`; fresh Fable and Codex opinions independently converged on this. `hooks/model-effort-check.sh` floor updated to match so the hook doesn't nag users following the wizard's own default (`medium` now silent; explicit `low` and the settings-only-`max` quirk still warn; worst-case warning output re-fitted under the 500-char cap after Codex caught the cap test had gone vacuous). 4 new mutation-verified doc-consistency tests plus a repo-wide guard banning the unqualified-multiplier phrasing class.
16
+ - **Setup A semantics made explicit** (PR #446, README "Reading Setup A precisely" + `AI_SETUP_LANES.md`): effort escalation happens *inside* the Sonnet 5 driver; model escalation *swaps the driver* to Opus 4.8 xhigh (2 failed attempts / LOW confidence / high-stakes); `advisor()` failure falls back to spawning a Fable subagent — never to skipping the check. The advisor-outage procedure's "continue with no advisor" path (which directly contradicted the new rule two sections above it — Codex round-1 catch) now routes to the subagent fallback: swap the transport, not the check. Section-scoped negative test assertions keep the skip-path from returning.
17
+
18
+ ### Fixed
19
+ - ROADMAP #236 bloat-hunt follow-through (PR #440): hook/test cleanups, ROADMAP archive split.
20
+ - ROADMAP #434 sub-item statuses corrected against git history instead of re-asserted (PR #442).
21
+
22
+ ### Why
23
+ Seven consumer-affecting commits had accumulated on main since v1.86.0 (July 5) with no npm release — discovered when the repo's first external bug report (#444) revealed that `npx agentic-sdlc-wizard@latest init` was still installing skills Copilot CLI silently drops even after the fix was merged and celebrated, with nothing in the process that would ever have prompted a release. Merge-to-main does not publish; only a `v*` tag does. Release-drift detection (own-package npm-vs-main watcher, in the style of `cc-version-drift.yml`) is tracked as ROADMAP #449 so this class of stranding is machine-caught, not memory-caught.
24
+
7
25
  ## [1.86.0] - 2026-07-05
8
26
 
9
27
  ### Fixed
@@ -253,11 +253,11 @@ Claude Code's **effort level** controls how much thinking the model does before
253
253
 
254
254
  | Model | Recommended Effort | Why |
255
255
  |-------|--------------------|-----|
256
- | Sonnet 5 (recommended default) | `high`, escalate to `xhigh` for hard tasks | `xhigh` as a blanket default doubles cost for marginal gains per CodeRabbit testing; `high` is the tested sweet spot |
256
+ | Sonnet 5 (recommended default) | `medium`, escalate to `high`/`xhigh` for hard tasks | CodeRabbit testing: `medium` captures most of the upside at the lowest cost; blanket `xhigh`/`max` defaults add cost for marginal gains |
257
257
  | Opus 4.8 (escalation only) | `xhigh` | `max` triggers excessive reasoning on 4.7/4.8 — documented 40-60x cache-token jump vs `high` (see "Opus 4.6 Stability" tier below) |
258
258
  | Fable 5 (advisor) | `high` (its own designed default) | Adaptive thinking always on; `xhigh`/`max` mainly move the thinking-token budget with small marginal gain for review work |
259
259
  | Opus 4.6 (Stability lane) | `max` | The one model where `max` doesn't overthink — no `xhigh` support at all (only low/medium/high/max) |
260
- | OpenAI/Codex (cross-model reviewer) | `xhigh` (their highest) | Always lower reasoning misses subtle bugs the reviewer exists to catch |
260
+ | OpenAI/Codex (cross-model reviewer) | `xhigh` default, escalate to `max`/Pro for unusually risky PRs | Lower reasoning misses subtle bugs the reviewer exists to catch; see `AI_SETUP_LANES.md`'s Final Review Policy for when to escalate |
261
261
 
262
262
  **Strict effort behavior (Opus 4.7+, carried forward in 4.8):**
263
263
  - **`xhigh` was introduced in 4.7** — sits between `high` and `max`, designed for coding and agentic work (30+ minute tasks with token budgets in the millions)
@@ -341,7 +341,7 @@ CC 2.1.117 expanded the `cleanupPeriodDays` setting to also cover `~/.claude/tas
341
341
  ---
342
342
  name: sdlc
343
343
  description: Full SDLC workflow for implementing features, fixing bugs, refactoring code
344
- argument-hint: [task description]
344
+ argument-hint: "[task description]"
345
345
  ---
346
346
 
347
347
  ## Task
@@ -433,7 +433,7 @@ Skills support these frontmatter fields:
433
433
  | `effort` | Set reasoning effort level | `effort: high` |
434
434
  | `paths` | Restrict skill to specific file patterns | `paths: ["src/**/*.ts", "tests/**"]` |
435
435
  | `context` | Context mode (`fork` = isolated subagent) | `context: fork` |
436
- | `argument-hint` | Hint for `$ARGUMENTS` placeholder | `argument-hint: [task description]` |
436
+ | `argument-hint` | Hint for `$ARGUMENTS` placeholder (quote it — bare brackets parse as a YAML array and break strict loaders like Copilot CLI, #444) | `argument-hint: "[task description]"` |
437
437
  | `disable-model-invocation` | Prevent skill from being auto-invoked by model | `disable-model-invocation: true` |
438
438
 
439
439
  **Key fields explained:**
@@ -526,7 +526,7 @@ See the dedicated subsection under [Tasks System](#tasks-system-v2116) (above, i
526
526
 
527
527
  ### MCP-tool hooks audit (ROADMAP #218, CC 2.1.118)
528
528
 
529
- CC 2.1.118 introduced `type: "mcp_tool"` for hooks — a hook can now directly invoke an MCP tool instead of running a bash script. **Audit (2026-04-26) of the 5 wizard hooks that existed at the time concluded: none migrate, all stay bash.** This subsection documents the per-hook reasoning so future audits don't redo the work; if a future PR migrates a hook to MCP, update this entry with the new rationale rather than deleting it. **Not yet re-audited**: 4 hooks shipped since 2026-04-26 (`goal-confidence-check.sh`, `codex-gate-check.sh`, `token-spike-check.sh`, `codex-review-stop-check.sh`) — the project now registers 9 hooks total (see `.claude/settings.json`), but this table only covers the original 5.
529
+ CC 2.1.118 introduced `type: "mcp_tool"` for hooks — a hook can now directly invoke an MCP tool instead of running a bash script. **Audit (2026-04-26) of the 5 wizard hooks that existed at the time concluded: none migrate, all stay bash.** This subsection documents the per-hook reasoning so future audits don't redo the work; if a future PR migrates a hook to MCP, update this entry with the new rationale rather than deleting it. **Not yet re-audited**: 3 hooks shipped since 2026-04-26 (`codex-gate-check.sh`, `token-spike-check.sh`, `codex-review-stop-check.sh`) — the project now registers 8 hooks total (see `.claude/settings.json`), but this table only covers the original 5.
530
530
 
531
531
  **Decision criteria applied** (any one rules out MCP):
532
532
 
@@ -536,11 +536,11 @@ CC 2.1.118 introduced `type: "mcp_tool"` for hooks — a hook can now directly i
536
536
 
537
537
  **Per-hook decision** (each row applies at least one criterion explicitly):
538
538
 
539
- - **`sdlc-prompt-check.sh`** (UserPromptSubmit, ~132 lines) — emits the SDLC BASELINE text on every prompt; writes effort-bump signals to `~/.cache/sdlc-wizard/effort-signals.log` for self-consumption on next invocation. Decision: **Stay bash.** Portability criterion: same script ships to Codex sibling unchanged. Local-state criterion: signal log is local-only.
540
- - **`instructions-loaded-check.sh`** (~202 lines) — InstructionsLoaded event; validates SDLC files exist, fetches npm `latest` with daily file cache (`~/.cache/sdlc-wizard/npm-latest.json`), emits staleness warnings. Decision: **Stay bash.** Portability criterion: Codex sibling has its own equivalent of session-start validation; bash port is direct. Local-state criterion: cache file is local.
541
- - **`tdd-pretool-check.sh`** (~115 lines) — PreToolUse on Write/Edit/MultiEdit; emits a TDD reminder, and (since #436) **blocks** with `exit 2` when a `src/**` write happens before any test file was touched this session (an edit-ordering proxy for TDD RED, session-scoped via a cache-dir sentinel). Decision: **Stay bash.** Fail-closed gating criterion applies now that this hook blocks: bash `exit 2` fails closed by definition, whereas an `mcp_tool` hook's block decision is lost if the MCP server errors — wrong default for a gate. Portability criterion: still trivially portable.
542
- - **`model-effort-check.sh`** (~80 lines) — SessionStart event; reads `CLAUDE_CODE_EFFORT_LEVEL` env var (falling back to `effortLevel` in the settings cascade), emits nothing when effort is `high`/`xhigh`/`max`, otherwise a loud warning. Decision: **Stay bash.** Portability criterion: env-var read maps 1:1 to any agent runtime. Local-state criterion: not applicable, hook is stateless.
543
- - **`precompact-seam-check.sh`** (~125 lines) — PreCompact event (matcher: `manual`); reads `.reviews/handoff.json` via jq, blocks manual `/compact` with exit 2 + stderr message when status is `PENDING_*` and the linked PR (if any) isn't merged. Decision: **Stay bash.** Fail-closed gating criterion: bash exit 2 fails closed by definition; an MCP `mcp_tool` hook returning `decision: "block"` works on the happy path, but if the MCP server crashes/times out the action proceeds — that flips the safety property from fail-closed to fail-open. For a hook whose entire job is to prevent context loss at bad seams, fail-open is the wrong default.
539
+ - **`sdlc-prompt-check.sh`** (UserPromptSubmit, ~137 lines) — emits the SDLC BASELINE text on every prompt (fires-once-per-session sentinel), plus a setup-wizard redirect when SDLC.md/TESTING.md are missing. Decision: **Stay bash.** Portability criterion: same script ships to Codex sibling unchanged. Local-state criterion: sentinel cache is local-only. **#236(b) 2026-07-06:** the ROADMAP #195 effort-bump signal log described here previously was removed — never fired in ~2 months of live use.
540
+ - **`instructions-loaded-check.sh`** (~291 lines) — InstructionsLoaded event; wizard-version + CC-version staleness nudges (both npm-cached daily), cross-model-review staleness check, autocompact compound-misconfig check, dual-channel-install check. Decision: **Stay bash.** Portability criterion: Codex sibling has its own equivalent of session-start validation; bash port is direct. Local-state criterion: cache files are local. **#236(b) 2026-07-06:** the SDLC.md/TESTING.md missing-file warning previously described here was removed (redundant with `sdlc-prompt-check.sh`'s louder version).
541
+ - **`tdd-pretool-check.sh`** (~129 lines) — PreToolUse on Write/Edit/MultiEdit; emits a TDD reminder, and (since #436) **blocks** with `exit 2` when a `src/**` write (or `SDLC_TDD_SRC_PATTERN`-overridden path, added #236(b) for this repo's own `src/`-less dogfooding) happens before any test file was touched this session (an edit-ordering proxy for TDD RED, session-scoped via a cache-dir sentinel). Decision: **Stay bash.** Fail-closed gating criterion applies now that this hook blocks: bash `exit 2` fails closed by definition, whereas an `mcp_tool` hook's block decision is lost if the MCP server errors — wrong default for a gate. Portability criterion: still trivially portable.
542
+ - **`model-effort-check.sh`** (~87 lines) — SessionStart event; reads `CLAUDE_CODE_EFFORT_LEVEL` env var (falling back to `effortLevel` in the settings cascade), emits nothing when effort is `high`/`xhigh`/`max`/unset, otherwise a loud warning. Decision: **Stay bash.** Portability criterion: env-var read maps 1:1 to any agent runtime. Local-state criterion: not applicable, hook is stateless. **#236(b) 2026-07-06:** unset used to loud-warn too (CC's own default state) — now silent; only an explicit low-effort value or the settings-only-`max` quirk warns.
543
+ - **`precompact-seam-check.sh`** (~101 lines) — PreCompact event (matcher: `manual`); blocks manual `/compact` with exit 2 + stderr message when a git rebase/merge/cherry-pick is in progress. Decision: **Stay bash.** Fail-closed gating criterion: bash exit 2 fails closed by definition; an MCP `mcp_tool` hook returning `decision: "block"` works on the happy path, but if the MCP server crashes/times out the action proceeds — that flips the safety property from fail-closed to fail-open. For a hook whose entire job is to prevent context loss at bad seams, fail-open is the wrong default. **#236(b) 2026-07-06:** this hook used to also block on `.reviews/handoff.json` being `PENDING_*` (mid cross-model-review-round), with 3 self-heal paths mitigating that branch's false-positive rate — removed; every real firing on record was a false positive, never a true positive.
544
544
 
545
545
  **When to revisit this audit:**
546
546
 
@@ -1085,9 +1085,9 @@ This is **Setup C (OpusPlan Hybrid/Saver)** in `AI_SETUP_LANES.md`. CC's native
1085
1085
 
1086
1086
  | Layer | Setup C (OpusPlan) | Setup A (default) | Setup B (Stability) |
1087
1087
  |-------|--------------------|--------------------|----------------------|
1088
- | Planner | Opus 4.8 `xhigh` (Plan Mode) | Sonnet 5 `high`→`xhigh` | Opus 4.6 `max` |
1089
- | Driver | Sonnet 5 `high` (execute mode) | Sonnet 5 `high`→`xhigh` | Opus 4.6 `max` |
1090
- | Reviewer | GPT-5.5 xhigh | GPT-5.5 xhigh | GPT-5.5 xhigh |
1088
+ | Planner | Opus 4.8 `xhigh` (Plan Mode) | Sonnet 5 `medium`→`high`→`xhigh` | Opus 4.6 `max` |
1089
+ | Driver | Sonnet 5 `medium` (execute mode) | Sonnet 5 `medium`→`high`→`xhigh` | Opus 4.6 `max` |
1090
+ | Reviewer | GPT-5.6 Sol xhigh | GPT-5.6 Sol xhigh | GPT-5.6 Sol xhigh |
1091
1091
 
1092
1092
  **How to opt in:**
1093
1093
  ```json
@@ -1110,7 +1110,7 @@ Set effort per-session with `/effort` (planner `xhigh`, driver `high`) rather th
1110
1110
  **Prove-It Gate (#233 acceptance criterion):** mixed-mode ships only if pair-tested on 3+ simple repos shows Sonnet-coder + Opus-reviewer produces ≥ same SDLC scores as full-Opus baseline. The first version of the heuristic ships v1.38.0; pair-test results land in CHANGELOG before recommending mixed-mode as the default for any tier.
1111
1111
 
1112
1112
  **Tradeoffs (be honest):**
1113
- - The Sonnet driver will drop some fine-grained self-review moves compared to an Opus-coder run — it's fast, less deliberate. The Opus planner and GPT-5.5 reviewer catch them, but expect more "fix in round 2" cycles.
1113
+ - The Sonnet driver will drop some fine-grained self-review moves compared to an Opus-coder run — it's fast, less deliberate. The Opus planner and GPT-5.6 Sol reviewer catch them, but expect more "fix in round 2" cycles.
1114
1114
  - Mixed-mode disables auto-mode (same as any pinned model). The pin is per-session — to switch back, remove the `model` line.
1115
1115
 
1116
1116
  ### Latest tier — Opus 4.8 (escalation model, #395)
@@ -2213,7 +2213,7 @@ chmod +x .claude/hooks/sdlc-prompt-check.sh
2213
2213
 
2214
2214
  ## Step 5: Create the TDD Hook
2215
2215
 
2216
- **Illustrative, not exhaustive:** this teaches the PreToolUse/exit-2 blocking mechanic with one hook. The wizard ships **9 production hooks total** — only this one and Step 4's light hook have hand-typed templates in this doc; the other 7 (`codex-gate-check.sh`, `goal-confidence-check.sh`, `instructions-loaded-check.sh`, `model-effort-check.sh`, `precompact-seam-check.sh`, `codex-review-stop-check.sh`, `token-spike-check.sh`) don't, because there's no substitute for the real files. **For the complete, always-in-sync set, run `npx agentic-sdlc-wizard@latest init`** instead of hand-building hooks 3-9 from prose descriptions elsewhere in this doc.
2216
+ **Illustrative, not exhaustive:** this teaches the PreToolUse/exit-2 blocking mechanic with one hook. The wizard ships **8 production hooks total** — only this one and Step 4's light hook have hand-typed templates in this doc; the other 6 (`codex-gate-check.sh`, `instructions-loaded-check.sh`, `model-effort-check.sh`, `precompact-seam-check.sh`, `codex-review-stop-check.sh`, `token-spike-check.sh`) don't, because there's no substitute for the real files. **For the complete, always-in-sync set, run `npx agentic-sdlc-wizard@latest init`** instead of hand-building hooks 3-8 from prose descriptions elsewhere in this doc.
2217
2217
 
2218
2218
  Create `.claude/hooks/tdd-pretool-check.sh`:
2219
2219
 
@@ -2274,7 +2274,7 @@ Create `.claude/skills/sdlc/SKILL.md`:
2274
2274
  ---
2275
2275
  name: sdlc
2276
2276
  description: Full SDLC workflow for implementing features, fixing bugs, refactoring code, testing, releasing, publishing, and deploying. Use this skill when implementing, fixing, refactoring, testing, adding features, building new code, or releasing/publishing/deploying.
2277
- argument-hint: [task description]
2277
+ argument-hint: "[task description]"
2278
2278
  ---
2279
2279
  # SDLC Skill - Full Development Workflow
2280
2280
 
@@ -2385,7 +2385,7 @@ Before presenting approach, STATE your confidence:
2385
2385
  | FAILED 2x | Something's wrong | STOP. ASK USER immediately | **Escalate effort now** — you're burning cycles at lower effort |
2386
2386
  | CONFUSED | Can't diagnose why something is failing | STOP. Describe what you tried, ask for help | **Escalate effort now** — stop spinning |
2387
2387
 
2388
- "Model default" and "escalate" are model-aware, not a blanket `max` — see "Recommended Effort Level" above for the per-model table (Sonnet 5: `high`→`xhigh`; Opus 4.8: `xhigh`; Opus 4.6: `max`; Fable: `high`).
2388
+ "Model default" and "escalate" are model-aware, not a blanket `max` — see "Recommended Effort Level" above for the per-model table (Sonnet 5: `medium`→`high`→`xhigh`; Opus 4.8: `xhigh`; Opus 4.6: `max`; Fable: `high`).
2389
2389
 
2390
2390
  **Dynamic bumping is NOT optional.** "Consider higher effort" is the same as "ignore this" in practice. If your confidence drops or tests fail twice, bump effort BEFORE the next attempt — spinning at low effort is an SDLC failure mode.
2391
2391
 
@@ -3075,7 +3075,7 @@ If deployment fails or post-deploy verification catches issues:
3075
3075
 
3076
3076
  **SDLC.md:**
3077
3077
  ```markdown
3078
- <!-- SDLC Wizard Version: 1.86.0 -->
3078
+ <!-- SDLC Wizard Version: 1.87.0 -->
3079
3079
  <!-- Setup Date: [DATE] -->
3080
3080
  <!-- Completed Steps: step-0.1, step-0.2, step-0.4, step-1, step-2, step-3, step-4, step-5, step-6, step-7, step-8, step-9 -->
3081
3081
  <!-- Git Workflow: [PRs or Solo] -->
@@ -3852,12 +3852,12 @@ Use an independent AI model from a different company as a code reviewer. The aut
3852
3852
 
3853
3853
  **Why this works:** Two AI systems from different companies (e.g., Claude writes, GPT reviews) provide adversarial diversity. They have fundamentally different training, different failure modes, and different strengths. What one misses, the other catches.
3854
3854
 
3855
- **Use the best model at the deepest reasoning.** This is your quality gate — don't economize on it. Always use the latest, most capable model available (**GPT-5.5 if you have access**, otherwise GPT-5.4) at maximum reasoning effort (`xhigh` — this is non-negotiable, lower settings miss subtle errors). Cheaper/faster models miss things. The whole point is catching what the authoring model couldn't.
3855
+ **Use the best model at the deepest reasoning.** This is your quality gate — don't economize on it. Always use the latest, most capable model available (**GPT-5.6 Sol if you have access**, otherwise Terra) at `xhigh` reasoning effort (non-negotiable lower settings miss subtle errors; preserve this baseline rather than downgrading it on a model bump). Cheaper/faster models miss things. The whole point is catching what the authoring model couldn't. For unusually risky PRs, escalating to `max` or Pro mode is defensible — see `AI_SETUP_LANES.md`'s Final Review Policy — but `xhigh` is the default; no published data shows the higher tiers catching meaningfully more real bugs on ordinary PR review.
3856
3856
 
3857
3857
  **Prerequisites:**
3858
3858
  - Codex CLI installed: `npm i -g @openai/codex`
3859
3859
  - OpenAI API key configured: `export OPENAI_API_KEY=...`
3860
- - Codex CLI picks up your OpenAI account's best available model automatically. If you have GPT-5.5 access, `codex exec` uses it; otherwise it falls back to GPT-5.4. No config change needed on your side.
3860
+ - Codex CLI picks up your OpenAI account's best available model automatically. If you have GPT-5.6 Sol access, `codex exec` uses it; otherwise it falls back to Terra. No config change needed on your side.
3861
3861
  - This is a local workflow tool — not required for CI/CD
3862
3862
 
3863
3863
  **The Protocol:**
package/README.md CHANGED
@@ -123,7 +123,7 @@ export OPENAI_API_KEY=sk-...
123
123
  codex --version # confirm ready
124
124
  ```
125
125
 
126
- That's it. Codex picks up your OpenAI account's best available model automatically — **if you have GPT-5.5, it uses GPT-5.5; otherwise GPT-5.4**. No model config needed.
126
+ That's it. Codex picks up your OpenAI account's best available model automatically — **if you have GPT-5.6 Sol, it uses Sol; otherwise it falls back to Terra**. No model config needed.
127
127
 
128
128
  **How to use it:** after Claude's self-review passes, write a one-file mission brief and run:
129
129
 
@@ -142,7 +142,7 @@ codex exec -c 'model_reasoning_effort="xhigh"' -s danger-full-access \
142
142
 
143
143
  The wizard ships a **default recommendation**, not a mandate. You can swap to any Claude model — newer, older, or sibling tier — at any time. `/model` per session, or pin in `.claude/settings.json`.
144
144
 
145
- **Default: Sonnet 5 at `high` effort, escalating to `xhigh`** (Setup A in `AI_SETUP_LANES.md`). Sonnet 5 (launched 2026-06-30) beats Opus 4.6 on every coding benchmark (SWE-bench Verified 85.2% vs 80.8%, Terminal-Bench 2.1 80.4% vs 65.4%) while using ~5x less Max quota per turn. Opus 4.6 remains available as **Setup B — Stability** for proven-consistency workflows; here's why it's no longer the default.
145
+ **Default: Sonnet 5 at `medium` effort, escalating to `high`/`xhigh`** (Setup A in `AI_SETUP_LANES.md`). Sonnet 5 (launched 2026-06-30) beats Opus 4.6 on every coding benchmark (SWE-bench Verified 85.2% vs 80.8%, Terminal-Bench 2.1 80.4% vs 65.4%) while generally using less Max quota — savings vary by effort level and narrow at `high`/`xhigh` (newer tokenizer, more agentic turns per task). Opus 4.6 remains available as **Setup B — Stability** for proven-consistency workflows; here's why it's no longer the default.
146
146
 
147
147
  ### Why Opus 4.6 was the flagship, and why that changed
148
148
 
@@ -156,7 +156,7 @@ Two weeks of in-the-wild data after Opus 4.8's launch (2026-05-28) showed a clea
156
156
  - **[BSWEN effort decision guide](https://docs.bswen.com/blog/2026-04-19-claude-code-effort-level-decision-guide/)** — "Max on Opus causes overthinking on routine stuff. xHigh is the sweet spot for autonomous work"
157
157
  - **r/Claudeopus field reports** — one maintainer's literal A/B: "12 hours with 4.8 zero deliverables; plugged in 4.6, spec written + 133 tests green in one session." Top comment: "4.6 had the best overall balance at max"
158
158
 
159
- That research still stands — it's why **Opus 4.6 remains Setup B (Stability)** rather than being dropped entirely, and why the wizard escalates to Opus **4.8** (not a blanket "latest") only when Sonnet 5 gets stuck. But Sonnet 5's June 30 launch changed the calculus for the *default*: it beats Opus 4.6 on every benchmark above at a fraction of the quota cost, so it's no longer a tradeoff between "reliable but weaker" and "strong but overthinks" — Sonnet 5 doesn't have Opus 4.8's overthinking problem in the first place.
159
+ That research still stands — it's why **Opus 4.6 remains Setup B (Stability)** rather than being dropped entirely, and why the wizard escalates to Opus **4.8** (not a blanket "latest") only when Sonnet 5 gets stuck. But Sonnet 5's June 30 launch changed the calculus for the *default*: it beats Opus 4.6 on every benchmark above at generally lower quota cost, so it's no longer a tradeoff between "reliable but weaker" and "strong but overthinks" — Sonnet 5 doesn't have Opus 4.8's overthinking problem in the first place.
160
160
 
161
161
  4.6 remains Anthropic-supported until **≥ Feb 5, 2027** per the [official deprecation page](https://platform.claude.com/docs/en/about-claude/model-deprecations), so Setup B stays a safe long-term choice if you've tuned a workflow to its behavior specifically.
162
162
 
@@ -172,10 +172,10 @@ That research still stands — it's why **Opus 4.6 remains Setup B (Stability)**
172
172
  Or pin in `.claude/settings.json`:
173
173
 
174
174
  ```json
175
- { "model": "sonnet", "advisorModel": "fable", "effortLevel": "xhigh" }
175
+ { "model": "sonnet", "advisorModel": "fable", "effortLevel": "medium" }
176
176
  ```
177
177
 
178
- **Effort is model-aware, not blanket `max`.** Sonnet 5: `high` default, `/effort xhigh` for hard tasks. Opus 4.8: `xhigh` (its own `max` overthinks). Opus 4.6: `max` (its one `xhigh`-less sweet spot). Set per-session with `/effort`, not a shell-rc or settings env var — persisting effort that way silently overrides a later `/effort` change after you switch models (see `SDLC.md`'s Lessons Learned for a real incident this caused). OpenAI/Codex reviewer: `xhigh` (its highest).
178
+ **Effort is model-aware, not blanket `max`.** Sonnet 5: `medium` default (CodeRabbit-tested), escalate `/effort high` → `xhigh` for hard tasks. Opus 4.8: `xhigh` (its own `max` overthinks). Opus 4.6: `max` (its one `xhigh`-less sweet spot). Set per-session with `/effort`, not a shell-rc or settings env var — persisting effort that way silently overrides a later `/effort` change after you switch models (see `SDLC.md`'s Lessons Learned for a real incident this caused). OpenAI/Codex reviewer: `xhigh` default — escalate to `max`/Pro mode only for unusually risky PRs (see `AI_SETUP_LANES.md`'s Final Review Policy).
179
179
 
180
180
  ### Four Setup Lanes
181
181
 
@@ -183,13 +183,21 @@ The wizard defines four AI coding setups in [`AI_SETUP_LANES.md`](AI_SETUP_LANES
183
183
 
184
184
  | Lane | Advisor | Driver | Reviewer | Escalation |
185
185
  |------|---------|--------|----------|------------|
186
- | **A — Recommended** | Fable 5 (advisorModel) | Sonnet 5, `high`→`xhigh` | GPT-5.5 xhigh | Opus 4.8 xhigh or Fable review |
187
- | **B — Stability** | Fable 5 (advisorModel) | Opus 4.6 max | GPT-5.5 xhigh | None |
188
- | **C — Saver** | Fable 5 or Opus 4.8 (advisorModel) | Opus 4.8 plans, Sonnet 5 executes | GPT-5.5 xhigh | None |
186
+ | **A — Recommended** | Fable 5 (advisorModel) | Sonnet 5, `medium`→`high`→`xhigh` | GPT-5.6 Sol xhigh | Opus 4.8 xhigh or Fable review |
187
+ | **B — Stability** | Fable 5 (advisorModel) | Opus 4.6 max | GPT-5.6 Sol xhigh | None |
188
+ | **C — Saver** | Fable 5 or Opus 4.8 (advisorModel) | Opus 4.8 plans, Sonnet 5 executes | GPT-5.6 Sol xhigh | None |
189
189
  | **D — Lite** | None | Sonnet 5, `medium` | None | None |
190
190
 
191
191
  Setup D's whole point: **the discipline of knowing when NOT to use discipline.** When blast radius is low and you just need fast cheap hands, skip the SDLC overhead.
192
192
 
193
+ ### Reading Setup A precisely
194
+
195
+ Clarified 2026-07-13 after these exact points kept getting re-confused; each rule states its why:
196
+
197
+ - **Effort escalation stays inside the driver.** Sonnet 5 starts at `medium`; `/effort high` when it struggles, `xhigh` for hard debugging or long agent runs. Why `medium` and not `high`: the old "start at `high`" guidance was removed in ROADMAP #440 — it had no measurement behind it, and CodeRabbit's testing (the source this repo already cites) found `medium` captures most of Sonnet 5's upside without paying for the top effort tiers, while community cost reports suggest the quota advantage erodes at `high`/`xhigh`.
198
+ - **Model escalation swaps the driver.** After 2 failed attempts, LOW confidence, or on high-stakes changes, Opus 4.8 xhigh takes over as driver (or run a Fable 5 review pass on the diff). Why a swap and not more effort: the lane's policy treats repeated failure as a sign the *approach* needs different eyes, not deeper reasoning on the same track — so once the effort ladder is exhausted, the next rung is a different model, not a bigger bill.
199
+ - **Advisor failure has a fallback, not a shrug.** Fable 5 advises via `advisorModel: "fable"`; when `advisor()` errors (it's a server-side tool — API incidents happen), spawn a Fable subagent as the fallback reviewer, exactly as the `/sdlc` skill prescribes. Why: the advisor's job is catching wrong approaches *before* they're built, so a transport failure changes how the advice is obtained — not whether the check happens.
200
+
193
201
  **A note on `[1m]` and billing.** Sonnet 5 always runs at its native 1M context — no `[1m]` suffix needed, no separate billing tier. For Opus, the `[1m]` suffix is the 1M-context alias; as of [March 2026](https://claude.com/blog/1m-context-ga), 1M context is GA at standard pricing — **no long-context surcharge, no premium tier, no API-only restriction.** Interactive Claude Code sessions on Max / Team / Enterprise plans include 1M context automatically. (Pro users need "Enable usage credits" turned on once.) The [June 15, 2026 billing split](https://codersera.com/blog/anthropic-june-2026-billing-change-claude-code/) moved *headless* surfaces — `claude -p`, Agent SDK, GitHub Actions, third-party apps — off the Max subscription onto a separate metered credit pool. Interactive Claude Code in your terminal stays on Max. Full details in [`AI_SETUP_LANES.md` § How Billing Works](AI_SETUP_LANES.md#how-billing-works--1m-context-max-plan-and-the-june-15-split).
194
202
 
195
203
  ## How It Works
package/cli/init.js CHANGED
@@ -25,7 +25,6 @@ const FILES = [
25
25
  { src: 'hooks/instructions-loaded-check.sh', dest: '.claude/hooks/instructions-loaded-check.sh', executable: true, base: REPO_ROOT },
26
26
  { src: 'hooks/model-effort-check.sh', dest: '.claude/hooks/model-effort-check.sh', executable: true, base: REPO_ROOT },
27
27
  { src: 'hooks/precompact-seam-check.sh', dest: '.claude/hooks/precompact-seam-check.sh', executable: true, base: REPO_ROOT },
28
- { src: 'hooks/goal-confidence-check.sh', dest: '.claude/hooks/goal-confidence-check.sh', executable: true, base: REPO_ROOT },
29
28
  { src: 'hooks/codex-gate-check.sh', dest: '.claude/hooks/codex-gate-check.sh', executable: true, base: REPO_ROOT },
30
29
  { src: 'hooks/token-spike-check.sh', dest: '.claude/hooks/token-spike-check.sh', executable: true, base: REPO_ROOT },
31
30
  { src: 'hooks/codex-review-stop-check.sh', dest: '.claude/hooks/codex-review-stop-check.sh', executable: true, base: REPO_ROOT },
@@ -7,10 +7,6 @@
7
7
  {
8
8
  "type": "command",
9
9
  "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/sdlc-prompt-check.sh"
10
- },
11
- {
12
- "type": "command",
13
- "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/goal-confidence-check.sh"
14
10
  }
15
11
  ]
16
12
  }
@@ -32,13 +32,37 @@ TOOL_INPUT=$(cat)
32
32
  # still can't run past the field's true (unescaped) closing quote because
33
33
  # neither alternative in the group can match a bare `"`. Scoped to just
34
34
  # this field, so unrelated fields containing the phrase can't false-trigger.
35
+ # #236(b): under `set -e`, a grep with no match exits 1 and kills the whole
36
+ # script with an undefined exit code (a "command" field can be absent, e.g.
37
+ # an old-format payload) — `|| true` makes "no match" a clean, deliberate
38
+ # empty COMMAND_FIELD instead of a crash.
35
39
  COMMAND_FIELD=$(printf '%s' "$TOOL_INPUT" \
36
- | grep -oE '"command"[[:space:]]*:[[:space:]]*"([^"\\]|\\.)*"')
40
+ | grep -oE '"command"[[:space:]]*:[[:space:]]*"([^"\\]|\\.)*"' || true)
37
41
 
38
- case "$COMMAND_FIELD" in
39
- *"git commit"*) ;;
40
- *) exit 0 ;;
41
- esac
42
+ # Codex cross-model review finding (#236(b) round 1, 2026-07-06): a `-c`/`-C`
43
+ # value containing a space inside quotes is a real, valid git invocation
44
+ # (e.g. `git -c user.name="A B" commit`) but broke the structural match below
45
+ # — `\S+` stops at the embedded space, so the flag-value alternative never
46
+ # matches and the whole "git ... commit" pattern silently fails, letting the
47
+ # commit through unreviewed. Fix: strip COMMAND_FIELD down to just the raw
48
+ # value content (COMMAND_VALUE, still JSON-escaped), then collapse every
49
+ # quoted sub-span — both JSON-escaped `\"..\"` and plain `'..'` — to a single
50
+ # placeholder token before the structural match runs, so a quoted value can
51
+ # never look like more than one word to it.
52
+ COMMAND_VALUE=$(printf '%s' "$COMMAND_FIELD" \
53
+ | sed -E 's/^"command"[[:space:]]*:[[:space:]]*"(.*)"$/\1/')
54
+ MASKED_COMMAND=$(printf '%s' "$COMMAND_VALUE" \
55
+ | sed -E -e 's/\\"[^\\]*\\"/Q/g' -e "s/'[^']*'/Q/g")
56
+
57
+ # #236(b): literal substring "git commit" misses git's own global-flag forms
58
+ # — `git -C <dir> commit` and `git -c k=v commit` are valid invocations that
59
+ # never contain that exact two-word substring, and previously sailed through
60
+ # unreviewed. Regex allows any number of -C/-c (with their required value),
61
+ # --long-flag, or single-letter-flag tokens between "git" and "commit".
62
+ if ! printf '%s' "$MASKED_COMMAND" \
63
+ | grep -qE '\bgit(\s+(-C\s+\S+|-c\s+\S+|--\S+|-[A-Za-z]))*\s+commit\b'; then
64
+ exit 0
65
+ fi
42
66
 
43
67
  REVIEW_FILE=".reviews/handoff.json"
44
68
 
@@ -62,6 +62,11 @@ if [ -n "$SESSION_ID" ]; then
62
62
  fi
63
63
  fi
64
64
 
65
- echo "NOTE: uncommitted changes with no REVIEWED/CERTIFIED cross-model review artifact. If this work is heading to a commit, run Codex review before committing." >&2
65
+ # #236(b): on exit 0, stderr is never surfaced (to the user or to Claude)
66
+ # only stdout JSON is. An earlier stderr+exit-0 version of this line was
67
+ # silently discarded since the day this hook shipped (#436).
68
+ cat << 'EOF'
69
+ {"hookSpecificOutput": {"hookEventName": "Stop", "additionalContext": "NOTE: uncommitted changes with no REVIEWED/CERTIFIED cross-model review artifact. If this work is heading to a commit, run Codex review before committing."}}
70
+ EOF
66
71
 
67
72
  exit 0
package/hooks/hooks.json CHANGED
@@ -7,10 +7,6 @@
7
7
  {
8
8
  "type": "command",
9
9
  "command": "${CLAUDE_PLUGIN_ROOT}/hooks/sdlc-prompt-check.sh"
10
- },
11
- {
12
- "type": "command",
13
- "command": "${CLAUDE_PLUGIN_ROOT}/hooks/goal-confidence-check.sh"
14
10
  }
15
11
  ]
16
12
  }
@@ -12,31 +12,19 @@ source "$HOOK_DIR/_find-sdlc-root.sh"
12
12
  dedupe_plugin_or_project "${BASH_SOURCE[0]}" || exit 0
13
13
 
14
14
  # CWD walk-up finds nearest SDLC project (#173: silent exit for non-SDLC dirs)
15
+ # #236(b): the missing-SDLC.md/TESTING.md warning that used to live here was
16
+ # removed — sdlc-prompt-check.sh already fires the same "SETUP NOT COMPLETE"
17
+ # warning, louder and on every prompt (this hook only fires at session
18
+ # start/resume), making this copy pure duplicate context.
15
19
  if find_sdlc_root; then
16
20
  PROJECT_DIR="$SDLC_ROOT"
17
21
  elif find_partial_sdlc_root; then
18
- # Partial setup — one file exists but not both. Warn about missing files
19
22
  PROJECT_DIR="$SDLC_ROOT"
20
23
  else
21
24
  # Not an SDLC project at all — exit silently
22
25
  exit 0
23
26
  fi
24
27
 
25
- MISSING=""
26
-
27
- if [ ! -f "$PROJECT_DIR/SDLC.md" ]; then
28
- MISSING="${MISSING:+${MISSING}, }SDLC.md"
29
- fi
30
-
31
- if [ ! -f "$PROJECT_DIR/TESTING.md" ]; then
32
- MISSING="${MISSING:+${MISSING}, }TESTING.md"
33
- fi
34
-
35
- if [ -n "$MISSING" ]; then
36
- echo "WARNING: Missing SDLC wizard files: ${MISSING}"
37
- echo "Invoke Skill tool, skill=\"setup-wizard\" to generate them."
38
- fi
39
-
40
28
  # Version update check (non-blocking, best-effort).
41
29
  # Fetches npm latest at most once per 24h (ROADMAP #196). Prints a stronger
42
30
  # multi-line nudge when the gap is ≥3 minor versions — the one-liner gets
@@ -258,11 +246,43 @@ fi
258
246
  # Claude Code version check (non-blocking, best-effort)
259
247
  # Gate on CLAUDE_PROJECT_DIR — only Claude Code sets this. Without it, we're
260
248
  # running under Codex/OpenCode where a CC update nudge is misleading (#375).
249
+ # #236(b): was an uncached npm network call on every session start with a
250
+ # bare `!=` comparison (fires in either direction, including when local is
251
+ # actually AHEAD of the cached/published "latest") — the exact bug class
252
+ # already fixed above for the wizard's own version check (#254 Bug 2). Now
253
+ # reuses the same 24h cache + semver_lt direction check.
261
254
  if [ -n "${CLAUDE_PROJECT_DIR:-}" ] && command -v claude > /dev/null 2>&1 && command -v npm > /dev/null 2>&1; then
262
255
  CC_LOCAL=$(claude --version 2>/dev/null | grep -o '[0-9][0-9.]*' | head -1) || true
263
- if [ -n "$CC_LOCAL" ]; then
264
- CC_LATEST=$(npm view @anthropic-ai/claude-code version 2>/dev/null) || true
265
- if [ -n "$CC_LATEST" ] && [ "$CC_LATEST" != "$CC_LOCAL" ]; then
256
+ if [ -n "$CC_LOCAL" ] && [[ "$CC_LOCAL" =~ $SEMVER_RE ]]; then
257
+ CC_CACHE_DIR="${SDLC_WIZARD_CACHE_DIR:-$HOME/.cache/sdlc-wizard}"
258
+ CC_CACHE_FILE="$CC_CACHE_DIR/latest-cc-version"
259
+ CC_LATEST=""
260
+
261
+ if [ -f "$CC_CACHE_FILE" ]; then
262
+ if stat -f %m "$CC_CACHE_FILE" > /dev/null 2>&1; then
263
+ CC_CACHE_MTIME=$(stat -f %m "$CC_CACHE_FILE")
264
+ else
265
+ CC_CACHE_MTIME=$(stat -c %Y "$CC_CACHE_FILE" 2>/dev/null || echo 0)
266
+ fi
267
+ CC_CACHE_AGE=$(( $(date +%s) - CC_CACHE_MTIME ))
268
+ if [ "$CC_CACHE_AGE" -lt 86400 ]; then
269
+ CC_CACHE_CONTENT=$(cat "$CC_CACHE_FILE" 2>/dev/null) || CC_CACHE_CONTENT=""
270
+ if [[ "$CC_CACHE_CONTENT" =~ $SEMVER_RE ]] && ! semver_lt "$CC_CACHE_CONTENT" "$CC_LOCAL"; then
271
+ CC_LATEST="$CC_CACHE_CONTENT"
272
+ fi
273
+ fi
274
+ fi
275
+
276
+ if [ -z "$CC_LATEST" ]; then
277
+ CC_NPM_RESULT=$(npm view @anthropic-ai/claude-code version 2>/dev/null) || true
278
+ if [[ "$CC_NPM_RESULT" =~ $SEMVER_RE ]]; then
279
+ CC_LATEST="$CC_NPM_RESULT"
280
+ mkdir -p "$CC_CACHE_DIR" 2>/dev/null || true
281
+ printf '%s' "$CC_LATEST" > "$CC_CACHE_FILE" 2>/dev/null || true
282
+ fi
283
+ fi
284
+
285
+ if [ -n "$CC_LATEST" ] && semver_lt "$CC_LOCAL" "$CC_LATEST"; then
266
286
  echo "Claude Code update available: ${CC_LOCAL} → ${CC_LATEST} (run: npm install -g @anthropic-ai/claude-code)"
267
287
  fi
268
288
  fi
@@ -1,18 +1,19 @@
1
1
  #!/bin/bash
2
2
  # SessionStart hook — effort/model nudge.
3
3
  #
4
- # Behavior (v1.84.0 update — model-aware floor):
4
+ # Behavior (#440 update — medium joins the floor):
5
5
  # CLAUDE_CODE_EFFORT_LEVEL env var takes precedence over effortLevel in settings.
6
6
  # CC docs: max is session-only in settings.json — only the env var persists it.
7
7
  # This hook cannot detect the active model (SessionStart payload has no model
8
8
  # field, per ROADMAP #180), so it uses a floor that's correct across models:
9
- # `high` is Sonnet 5's and Fable's tested default (escalate to xhigh for hard
10
- # tasks); xhigh is Opus 4.8's floor; max remains the sweet spot on Opus 4.6
11
- # (no xhigh support). Blanket max is WRONG for Sonnet 5/Opus 4.8 (wastes
12
- # tokens for no quality gain see AI_SETUP_LANES.md per-model table).
9
+ # `medium` is Sonnet 5's documented default (CodeRabbit testing: most of the
10
+ # upside at the lowest cost escalate high -> xhigh for hard tasks); `high`
11
+ # is Fable's default; xhigh is Opus 4.8's floor; max remains the sweet spot
12
+ # on Opus 4.6 (no xhigh support). Blanket max is WRONG for Sonnet 5/Opus 4.8
13
+ # (wastes tokens for no quality gain — see AI_SETUP_LANES.md per-model table).
13
14
  #
14
- # effort=high, xhigh, or max -> silent (all acceptable — model-dependent)
15
- # anything else -> LOUD WARNING
15
+ # effort=medium, high, xhigh, or max -> silent (all acceptable — model-dependent)
16
+ # anything else -> LOUD WARNING
16
17
  #
17
18
  # Non-blocking: always exits 0.
18
19
 
@@ -49,32 +50,37 @@ if [ -z "$effort" ]; then
49
50
  done
50
51
  fi
51
52
 
52
- # high/xhigh are always silent (persist fine via settings.json, no CC quirk).
53
- # max is silent EXCEPT when it's settings-only — CC docs: max is session-only
54
- # in settings.json, only the env var actually persists it.
55
- if [ "$effort" = "high" ] || [ "$effort" = "xhigh" ]; then
53
+ # medium/high/xhigh are always silent (persist fine via settings.json, no CC
54
+ # quirk). max is silent EXCEPT when it's settings-only — CC docs: max is
55
+ # session-only in settings.json, only the env var actually persists it.
56
+ if [ "$effort" = "medium" ] || [ "$effort" = "high" ] || [ "$effort" = "xhigh" ]; then
56
57
  exit 0
57
58
  fi
58
59
  if [ "$effort" = "max" ] && [ "$settings_max" -eq 0 ]; then
59
60
  exit 0
60
61
  fi
61
62
 
63
+ # #236(b): unset (no env var, no settings entry) is CC's own current default —
64
+ # not a problem state on its own (e.g. a deliberate Fable-session config).
65
+ # Only warn on an EXPLICITLY set low-effort value or the settings-only-max
66
+ # quirk below (CC silently ignores settings.json's "max" — genuinely
67
+ # non-obvious, worth keeping).
68
+ if [ -z "$effort" ]; then
69
+ exit 0
70
+ fi
71
+
62
72
  if [ "$settings_max" -eq 1 ] && [ -z "${CLAUDE_CODE_EFFORT_LEVEL:-}" ]; then
63
73
  effort_display="max (settings-only — CC ignores this)"
64
- elif [ -z "$effort" ]; then
65
- effort_display="unset"
66
74
  else
67
75
  effort_display="$effort"
68
76
  fi
69
77
 
70
- echo "=============================================================================="
71
- echo " WARNING: effort '$effort_display' — SDLC requires high, xhigh, or max."
72
- echo " Below high = degraded reasoning, shallow TDD, weak self-review."
73
- echo ""
74
- echo " Run: /effort xhigh (or /effort high see AI_SETUP_LANES.md)"
75
- echo " Avoid shell-rc env var persistence — silently overrides model switches."
76
- echo ""
78
+ echo "=============================================================="
79
+ echo " WARNING: effort '$effort_display' — below the SDLC floor (medium)."
80
+ echo " Degraded reasoning, shallow TDD, weak self-review."
81
+ echo " Run: /effort medium (Sonnet 5) or your model's floor — see AI_SETUP_LANES.md"
82
+ echo " Avoid shell-rc env persistence overrides model switches."
77
83
  echo " recommended models: $RECOMMENDED_MODELS"
78
- echo "=============================================================================="
84
+ echo "=============================================================="
79
85
 
80
86
  exit 0
@@ -1,18 +1,22 @@
1
1
  #!/bin/bash
2
- # PreCompact hook - block manual /compact at non-seam boundaries
2
+ # PreCompact hook - block manual /compact mid-git-operation
3
3
  # Fires on manual /compact only (auto-compact is threshold-driven; blocking
4
4
  # it could push past 100% context and lose everything). Matcher: "manual"
5
5
  # in .claude/settings.json.
6
6
  #
7
7
  # Requires Claude Code v2.1.105+ (PreCompact event introduced April 13, 2026).
8
8
  #
9
- # Seam policy: compacting mid-cycle loses evidence the next round needs.
10
- # Block when:
11
- # (1) .reviews/handoff.json status is PENDING_REVIEW or PENDING_RECHECK
12
- # mid-Codex-round, compact after CERTIFIED
13
- # (2) git rebase/merge/cherry-pick in progress
14
- # finish in-progress git operation first
15
- # Allow otherwise.
9
+ # #236(b): the original design also blocked on .reviews/handoff.json being
10
+ # PENDING_REVIEW/PENDING_RECHECK (mid cross-model-review-round). Removed —
11
+ # every real firing on record over ~2.5 months was a false positive (a
12
+ # completed rebase's stale REBASE_HEAD, or an abandoned PENDING handoff),
13
+ # never a true positive, and ~150 of this file's 256 lines were self-heal
14
+ # machinery mitigating that false-positive rate (3 heal paths + dry-run
15
+ # scaffolding). The git-op check below has no such record.
16
+ #
17
+ # Seam policy: compacting mid-git-operation loses evidence the operation
18
+ # needs to finish correctly. Block when a rebase/merge/cherry-pick is in
19
+ # progress; allow otherwise.
16
20
 
17
21
  # Token-bloat fix: when both project + plugin register this hook, plugin yields.
18
22
  # Use parameter expansion (not `dirname`) so the PATH-restricted gh-missing test
@@ -30,164 +34,9 @@ ROOT="${CLAUDE_PROJECT_DIR:-$PWD}"
30
34
 
31
35
  HOLD_REASONS=""
32
36
 
33
- # #240: Dry-run / simulation env vars. Let consumers verify hook behavior
34
- # without mutating real .reviews/handoff.json or .git/ state.
35
- # SDLC_DRY_RUN_HANDOFF_STATUS=<value> overrides handoff.json status
36
- # lookup (skip the file read entirely)
37
- # SDLC_DRY_RUN_GIT_STATE=rebase|merge|cherry-pick — simulates an in-flight
38
- # git operation
39
- # When set, dry-run values short-circuit the real-state checks below. The
40
- # hook still emits the same HOLD/silent decision so consumers can smoke-test
41
- # every code path. No filesystem writes — purely read-only simulation.
42
-
43
- # Check 1: Codex review mid-cycle
44
- # Self-heal paths (ordered by preference):
45
- # (a) #209: handoff has pr_number + gh reports PR MERGED → implicit CERTIFIED (silent)
46
- # (c) #257: handoff has no pr_number BUT every SHA cited in fixes_applied[]
47
- # is in HEAD's ancestry AND .reviews/latest-review.md contains CERTIFIED
48
- # (without "NOT CERTIFIED") → implicit CERTIFIED (silent). Catches the
49
- # solo-developer pattern: write fixes, commit them, run targeted
50
- # recheck, see CERTIFIED in latest-review.md, ship — and forget to
51
- # update handoff.json status. The visible signals (commits landed +
52
- # review file) already say "done" so blocking is high false-positive.
53
- # (b) #229: handoff has no pr_number, no SHA-ancestry heal, but mtime >
54
- # SDLC_HANDOFF_STALE_DAYS days → implicit CERTIFIED with WARN
55
- # (forgotten artifact; blocking forever is worse UX). Default: 14 days.
56
- HANDOFF="$ROOT/.reviews/handoff.json"
57
- # Validate SDLC_HANDOFF_STALE_DAYS as non-negative integer. Anything else
58
- # (empty, "foo", "-3", "10.5") silently falls back to 14 — we don't want a
59
- # typo in the user's env to leak a bash arithmetic error to stderr every
60
- # time the hook runs (caught by Codex P2 review of PR #227).
61
- STALE_DAYS_RAW="${SDLC_HANDOFF_STALE_DAYS:-14}"
62
- case "$STALE_DAYS_RAW" in
63
- ''|*[!0-9]*) STALE_DAYS=14 ;;
64
- *) STALE_DAYS="$STALE_DAYS_RAW" ;;
65
- esac
66
- STALE_WARN=""
67
- # #240: dry-run override skips the real handoff.json read.
68
- if [ -n "${SDLC_DRY_RUN_HANDOFF_STATUS:-}" ]; then
69
- STATUS="$SDLC_DRY_RUN_HANDOFF_STATUS"
70
- case "$STATUS" in
71
- PENDING_REVIEW|PENDING_RECHECK)
72
- HOLD_REASONS="${HOLD_REASONS} - Codex review is ${STATUS}. Round-1 evidence lives in this context — compacting now loses what round-2 needs to re-verify.
73
- Resolve: wait for CERTIFIED (or escalate) before /compact."$'\n'
74
- ;;
75
- esac
76
- elif [ -f "$HANDOFF" ]; then
77
- STATUS=$(grep -o '"status"[[:space:]]*:[[:space:]]*"[^"]*"' "$HANDOFF" 2>/dev/null | head -1 | sed 's/.*"\([^"]*\)"$/\1/')
78
- case "$STATUS" in
79
- PENDING_REVIEW|PENDING_RECHECK)
80
- PR_NUMBER=$(grep -o '"pr_number"[[:space:]]*:[[:space:]]*[0-9][0-9]*' "$HANDOFF" 2>/dev/null | head -1 | grep -o '[0-9][0-9]*$')
81
- HEALED=0
82
- if [ -n "$PR_NUMBER" ]; then
83
- # Path (a): PR-linked self-heal (#209). Applies regardless of mtime —
84
- # an OPEN PR with old mtime is still a live review.
85
- if command -v gh >/dev/null 2>&1; then
86
- PR_STATE=$(gh pr view "$PR_NUMBER" --json state --jq .state 2>/dev/null)
87
- [ "$PR_STATE" = "MERGED" ] && HEALED=1
88
- fi
89
- else
90
- # Path (c) #257: SHA-ancestry self-heal. Look for git SHAs cited
91
- # in fixes_applied[]; if every cited SHA is reachable from HEAD
92
- # AND .reviews/latest-review.md says CERTIFIED, the review IS
93
- # closed, the user just forgot to bump status. Silent heal.
94
- REVIEW_MD="$ROOT/.reviews/latest-review.md"
95
- if [ -f "$REVIEW_MD" ] \
96
- && grep -qE '\bCERTIFIED\b' "$REVIEW_MD" 2>/dev/null \
97
- && ! grep -qE '\bNOT CERTIFIED\b' "$REVIEW_MD" 2>/dev/null; then
98
- # Extract the fixes_applied[] block via bracket-depth
99
- # tracking — naive `/\]/` matching breaks on `]` inside
100
- # string literals (e.g. "[x] FIXED in <sha>" markdown
101
- # checkboxes), which would let phantom SHAs after the
102
- # broken-early bracket leak past path (c) and false-heal.
103
- # Codex P1 round 1.
104
- FIXES_BLOCK=$(awk '
105
- BEGIN { in_block = 0; depth = 0; started = 0 }
106
- /"fixes_applied"/ { in_block = 1 }
107
- in_block {
108
- print
109
- in_string = 0
110
- escaped = 0
111
- for (i = 1; i <= length($0); i++) {
112
- c = substr($0, i, 1)
113
- # Honor JSON backslash escapes: \" inside a
114
- # string is a literal quote, NOT a string
115
- # terminator. Without this, a fixes_applied
116
- # entry containing `\"]` falsely flips the
117
- # in_string flag and exits the array early —
118
- # letting later phantom SHAs leak past path
119
- # (c) and false-heal (Codex round 2 P1).
120
- if (escaped) { escaped = 0; continue }
121
- if (c == "\\") { escaped = 1; continue }
122
- if (c == "\"") { in_string = !in_string; continue }
123
- if (in_string) continue
124
- if (c == "[") { depth++; started = 1 }
125
- else if (c == "]") { depth-- }
126
- }
127
- if (started && depth <= 0) in_block = 0
128
- }
129
- ' "$HANDOFF" 2>/dev/null)
130
- if [ -n "$FIXES_BLOCK" ] && [ -d "$ROOT/.git" ]; then
131
- # Strip UUIDs (8-4-4-4-12 hex pattern) BEFORE extracting
132
- # SHA candidates. UUIDs have a fixed shape; their hex
133
- # segments would otherwise match \b[0-9a-f]{7,40}\b and
134
- # fail the ancestry check, false-blocking certified
135
- # reviews that cite UUIDs in fixes_applied (mission
136
- # UUIDs, Linear/Jira ticket IDs, etc.). Codex P2 round 1.
137
- # POSIX-compatible: no `\b` (BSD sed doesn't support it).
138
- # The hyphenated 8-4-4-4-12 shape is specific enough
139
- # that false-stripping a real SHA is implausible.
140
- CLEANED=$(echo "$FIXES_BLOCK" | sed -E 's/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}//g')
141
- SHAS=$(echo "$CLEANED" | grep -oE '\b[0-9a-f]{7,40}\b' | sort -u)
142
- if [ -n "$SHAS" ]; then
143
- # Every cited SHA must be reachable from HEAD —
144
- # phantom SHAs (e.g. typos, references to other
145
- # repos) correctly fail ancestry and block the heal.
146
- ALL_IN_HEAD=1
147
- for sha in $SHAS; do
148
- if ! git -C "$ROOT" merge-base --is-ancestor "$sha" HEAD 2>/dev/null; then
149
- ALL_IN_HEAD=0
150
- break
151
- fi
152
- done
153
- [ "$ALL_IN_HEAD" -eq 1 ] && HEALED=1
154
- fi
155
- fi
156
- fi
157
- # Path (b): stale-handoff auto-expire (#229). Only when no pr_number
158
- # AND path (c) didn't already heal. We must not short-circuit
159
- # PR-linked reviews.
160
- if [ "$HEALED" -ne 1 ]; then
161
- # Try GNU stat first (Linux: `-c %Y` gives mtime, BSD stat errors out
162
- # so `||` fires). Then BSD stat (macOS: `-f %m` gives mtime). The
163
- # reverse order fails on Linux because `stat -f` on GNU means
164
- # `--file-system` and dumps filesystem info to stdout (non-error).
165
- MTIME=$(stat -c %Y "$HANDOFF" 2>/dev/null || stat -f %m "$HANDOFF" 2>/dev/null)
166
- # Numeric guard: if stat fails both flavors or returns junk, skip
167
- # the stale-check entirely and fall through to HOLD (safe default).
168
- case "$MTIME" in
169
- ''|*[!0-9]*) ;;
170
- *)
171
- NOW=$(date +%s)
172
- AGE_DAYS=$(( (NOW - MTIME) / 86400 ))
173
- if [ "$AGE_DAYS" -ge "$STALE_DAYS" ]; then
174
- HEALED=1
175
- STALE_WARN="WARN: handoff.json is ${STATUS} and ${AGE_DAYS}d old with no pr_number — treating as stale CERTIFIED (override: set SDLC_HANDOFF_STALE_DAYS or close out the review)."
176
- fi
177
- ;;
178
- esac
179
- fi
180
- fi
181
- if [ "$HEALED" -ne 1 ]; then
182
- HOLD_REASONS="${HOLD_REASONS} - Codex review is ${STATUS}. Round-1 evidence lives in this context — compacting now loses what round-2 needs to re-verify.
183
- Resolve: wait for CERTIFIED (or escalate) before /compact."$'\n'
184
- fi
185
- ;;
186
- esac
187
- fi
188
-
189
- # Check 2: in-progress git operation
190
- # #240: dry-run override simulates a git op without needing a real .git/.
37
+ # #240: SDLC_DRY_RUN_GIT_STATE=rebase|merge|cherry-pick simulates an
38
+ # in-flight git operation without needing a real .git/ state, so consumers
39
+ # can smoke-test every code path (read-only, no writes).
191
40
  GITDIR="$ROOT/.git"
192
41
  # Step 1: when dry-run var matches a known scenario, simulate it.
193
42
  # Otherwise (unset, empty, or unknown value) fall through to the real
@@ -241,16 +90,12 @@ fi
241
90
 
242
91
  if [ -n "$HOLD_REASONS" ]; then
243
92
  {
244
- echo "HOLD: manual /compact at a non-seam. Compacting mid-cycle loses evidence the next round needs."
93
+ echo "HOLD: manual /compact mid-git-operation."
245
94
  echo ""
246
95
  echo "$HOLD_REASONS"
247
- echo "Natural seams: commit boundary, Codex CERTIFIED, PR merge, ROADMAP item DONE."
248
96
  echo "Override: resolve the blocker above, or temporarily disable this hook in .claude/settings.json."
249
97
  } >&2
250
98
  exit 2
251
99
  fi
252
100
 
253
- # Stale-handoff unblock: emit a one-line WARN so the user knows the hook
254
- # self-healed over an abandoned PENDING artifact (but still allow /compact).
255
- [ -n "$STALE_WARN" ] && echo "$STALE_WARN" >&2
256
101
  exit 0
@@ -35,19 +35,12 @@ else
35
35
  exit 0
36
36
  fi
37
37
 
38
- # Effort auto-bump (ROADMAP #195). Watches this UserPromptSubmit payload for
39
- # LOW-confidence / FAILED-repeatedly / CONFUSED phrases, logs a timestamped
40
- # signal, and emits a loud '/effort xhigh' nudge when 2 signals land inside
41
- # a 30-minute window. Enforces the SDLC confidence table mid-session so
42
- # Claude stops burning budget at 'high' after confidence drops.
43
- EFFORT_CACHE_DIR="${SDLC_WIZARD_CACHE_DIR:-$HOME/.cache/sdlc-wizard}"
44
- EFFORT_SIGNALS="$EFFORT_CACHE_DIR/effort-signals.log"
45
- PROMPT_TEXT=""
38
+ # #236(b): the ROADMAP #195 effort auto-bump detector that used to live here
39
+ # (phrase-matching low-confidence signals, loud '/effort xhigh' nudge after
40
+ # ≥2 in 30 min) was removed never fired in ~2 months of live use, the
41
+ # largest unproven component in this file. SESSION_ID is still needed below
42
+ # for the BASELINE fires-once sentinel, so stdin is still read for it.
46
43
  SESSION_ID=""
47
- # Read stdin once regardless of jq availability — session_id extraction
48
- # is jq-independent (Codex round 1 P1: BASELINE gate failed when jq was
49
- # missing or broken). Prompt extraction still needs jq because prompt
50
- # content can contain arbitrary multi-line text + escapes.
51
44
  if [ ! -t 0 ]; then
52
45
  STDIN_JSON=$(cat)
53
46
  if [ -n "$STDIN_JSON" ]; then
@@ -59,57 +52,6 @@ if [ ! -t 0 ]; then
59
52
  | grep -o '"session_id"[[:space:]]*:[[:space:]]*"[^"]*"' \
60
53
  | head -1 \
61
54
  | sed 's/.*"\([^"]*\)"$/\1/')
62
- if command -v jq > /dev/null 2>&1; then
63
- PROMPT_TEXT=$(printf '%s' "$STDIN_JSON" | jq -r '.prompt // empty' 2>/dev/null) || PROMPT_TEXT=""
64
- fi
65
- fi
66
- fi
67
- if [ -n "$PROMPT_TEXT" ]; then
68
- LOWER=$(printf '%s' "$PROMPT_TEXT" | tr '[:upper:]' '[:lower:]')
69
- SIGNAL_REASON=""
70
- # Every trigger requires first-person ownership or a structured-label
71
- # form, so educational/quoted mentions ("How do I name a low confidence
72
- # badge?", "What does 'failed again' mean?") don't fire.
73
- case "$LOWER" in
74
- *"i'm stuck"*|*"i am stuck"*|*"im stuck"*|\
75
- *"i'm confused"*|*"i am confused"*|*"im confused"*|\
76
- *"i tried twice"*|*"i've tried twice"*|*"ive tried twice"*|\
77
- *"i can't figure"*|*"i cant figure"*|\
78
- *"i'm not sure why"*|*"i am not sure why"*|*"im not sure why"*|\
79
- *"my confidence is low"*|*"my confidence: low"*|*"confidence: low"*|\
80
- *"it's still failing"*|*"its still failing"*|\
81
- *"it keeps failing"*|*"this keeps failing"*|\
82
- *"it failed again"*|*"this failed again"*|\
83
- *"failed twice"*|*"failed 2x"*)
84
- SIGNAL_REASON="low"
85
- ;;
86
- esac
87
- if [ -n "$SIGNAL_REASON" ]; then
88
- # Group the write so redirection errors (e.g., unwritable HOME,
89
- # cache-dir-is-a-file) land on /dev/null instead of leaking to stderr.
90
- {
91
- if mkdir -p "$EFFORT_CACHE_DIR" && [ -d "$EFFORT_CACHE_DIR" ]; then
92
- # Prune entries older than 1h on every write to cap log size.
93
- if [ -f "$EFFORT_SIGNALS" ]; then
94
- PRUNE_THRESH=$(( $(date +%s) - 3600 ))
95
- awk -v t="$PRUNE_THRESH" '$1+0 >= t' "$EFFORT_SIGNALS" > "${EFFORT_SIGNALS}.tmp" \
96
- && mv "${EFFORT_SIGNALS}.tmp" "$EFFORT_SIGNALS"
97
- fi
98
- printf '%s\t%s\n' "$(date +%s)" "$SIGNAL_REASON" >> "$EFFORT_SIGNALS"
99
- fi
100
- } 2>/dev/null || true
101
- fi
102
- fi
103
- if [ -f "$EFFORT_SIGNALS" ]; then
104
- NOW=$(date +%s)
105
- THRESH=$(( NOW - 1800 ))
106
- RECENT=$(awk -v t="$THRESH" '$1+0 >= t' "$EFFORT_SIGNALS" 2>/dev/null | wc -l | tr -d ' ')
107
- if [ "${RECENT:-0}" -ge 2 ]; then
108
- echo ""
109
- echo "!! EFFORT BUMP REQUIRED: ${RECENT} low-confidence signals in last 30 min !!"
110
- echo " Run /effort xhigh NOW — spinning at 'high' after confidence drops wastes budget."
111
- echo " (Auto-enforcement of the SDLC confidence table. ROADMAP #195.)"
112
- echo ""
113
55
  fi
114
56
  fi
115
57
 
@@ -55,7 +55,22 @@ fi
55
55
  # slash BEFORE "src", so a cwd-relative file_path like "src/app.js" (no
56
56
  # leading slash) never matched and the whole gate silently no-op'd. Second
57
57
  # clause catches the relative form.
58
- if [[ "$FILE_PATH" == *"/src/"* || "$FILE_PATH" == "src/"* ]]; then
58
+ # #236(b): SDLC_TDD_SRC_PATTERN overrides the gated path(s) via env var (set
59
+ # it in the hook's "command" string in .claude/settings.json) instead of
60
+ # editing this shared/distributed script — a "|"-separated list of
61
+ # substrings, e.g. "hooks/|cli/". Falls back to the generic /src/ pattern
62
+ # when unset, so every other install is unaffected.
63
+ SRC_MATCH=0
64
+ if [ -n "${SDLC_TDD_SRC_PATTERN:-}" ]; then
65
+ IFS='|' read -ra _tdd_patterns <<< "$SDLC_TDD_SRC_PATTERN"
66
+ for _p in "${_tdd_patterns[@]}"; do
67
+ [[ "$FILE_PATH" == *"$_p"* ]] && SRC_MATCH=1 && break
68
+ done
69
+ else
70
+ [[ "$FILE_PATH" == *"/src/"* || "$FILE_PATH" == "src/"* ]] && SRC_MATCH=1
71
+ fi
72
+
73
+ if [ "$SRC_MATCH" -eq 1 ]; then
59
74
  # #436 gate: block implementation-first edits when no test file has been
60
75
  # touched yet this session. Degrades to allow without session_id.
61
76
  if [ -n "$SESSION_ID" ]; then
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-sdlc-wizard",
3
- "version": "1.86.0",
3
+ "version": "1.87.0",
4
4
  "description": "SDLC enforcement for Claude Code — hooks, skills, and wizard setup in one command",
5
5
  "bin": {
6
6
  "sdlc-wizard": "cli/bin/sdlc-wizard.js"
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: feedback
3
3
  description: Submit feedback, bug reports, feature requests, or share SDLC patterns you've discovered. Privacy-first — always asks before scanning.
4
- argument-hint: [optional: bug | feature | pattern | improvement]
4
+ argument-hint: "[optional: bug | feature | pattern | improvement]"
5
5
  effort: medium
6
6
  ---
7
7
  # Feedback — Community Contribution Loop
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: sdlc
3
3
  description: Full SDLC workflow for implementing features, fixing bugs, refactoring code, testing, releasing, publishing, and deploying. Use this skill when implementing, fixing, refactoring, testing, adding features, building new code, or releasing/publishing/deploying.
4
- argument-hint: [task description]
4
+ argument-hint: "[task description]"
5
5
  ---
6
6
  # SDLC Skill - Full Development Workflow
7
7
 
@@ -119,7 +119,7 @@ Native `/goal <condition>` (**v2.1.143+**). Haiku evaluator re-checks transcript
119
119
 
120
120
  ## Recommended Model
121
121
 
122
- **Recommended: Sonnet 5 `high`→`xhigh`** — beats Opus 4.6, ~5x less quota. Escalate to **Opus 4.8 `xhigh`** when stuck. **Opus 4.6 `max`** valid for consistency. See `AI_SETUP_LANES.md`.
122
+ **Recommended: Sonnet 5 `medium`→`high`→`xhigh`** — beats Opus 4.6 on benchmarks, generally lower quota (savings narrow at high/xhigh). Escalate to **Opus 4.8 `xhigh`** when stuck. **Opus 4.6 `max`** valid for consistency. See `AI_SETUP_LANES.md`.
123
123
 
124
124
  **Effort is model-aware, not blanket `max`** — `max` overthinks on Sonnet 5/Opus 4.8. Set via `/effort` per session, not a shell-rc env var (overrides post-switch — see SDLC.md). `/model` persists; picker `s` does not.
125
125
 
@@ -137,7 +137,7 @@ The loop goes back to PLANNING, not TDD RED. Run `/code-review`; issues at confi
137
137
 
138
138
  ## Cross-Model Review (REQUIRED for High-Stakes)
139
139
 
140
- **When to run:** high-stakes changes (auth, payments, data), releases/publishes, complex refactors. **When to skip (log justification):** trivial, hotfixes, risk < review cost. **Prerequisites:** Codex CLI + OpenAI API key. **Reviewer:** `gpt-5.5` xhigh — adversarial diversity.
140
+ **When to run:** high-stakes changes (auth, payments, data), releases/publishes, complex refactors. **When to skip (log justification):** trivial, hotfixes, risk < review cost. **Prerequisites:** Codex CLI + OpenAI API key. **Reviewer:** `gpt-5.6-sol` xhigh — adversarial diversity.
141
141
 
142
142
  PROTOCOL is universal across domains; only `review_instructions` and `verification_checklist` change.
143
143
 
@@ -148,8 +148,6 @@ PROTOCOL is universal across domains; only `review_instructions` and `verificati
148
148
 
149
149
  **Convergence:** 2 rounds sweet spot, 3 max, escalate after — except large migrations: judge by finding trend, not count.
150
150
 
151
- **Enforcement:** `hooks/goal-confidence-check.sh` warns when `/goal` skips the 95%-confidence or DLC-binding gates (#360).
152
-
153
151
  **Multi-reviewer:** respond to each independently. **Non-code domains:** add `"audience"`/`"stakes"` keys.
154
152
 
155
153
  ### Release Review Focus
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: setup-wizard
3
3
  description: Setup wizard — scans codebase, builds confidence per data point, only asks what it can't figure out, generates SDLC files. Use for first-time setup or re-running setup.
4
- argument-hint: [optional: regenerate | verify-only]
4
+ argument-hint: "[optional: regenerate | verify-only]"
5
5
  effort: high
6
6
  ---
7
7
  # Setup Wizard - Confidence-Driven Project Configuration
@@ -245,7 +245,7 @@ The output is JSON: `{ tier: "simple" | "complex", score, signals }`. Use the re
245
245
  > How do you want to configure the model for this repo?
246
246
  >
247
247
  > - **[N] No pin (default):** Auto-mode. CC picks model per turn. Simplest, no advisor.
248
- > - **[s] Sonnet 5 + Fable** *(Setup A — recommended if you want a pin):* Pins `model: "sonnet"`, `advisorModel: "fable"`. Native 1M context, no `[1m]` suffix needed. Beats Opus 4.6 on every coding benchmark at ~5x less Max quota per turn. Effort: `high`, escalate to `xhigh` for hard tasks.
248
+ > - **[s] Sonnet 5 + Fable** *(Setup A — recommended if you want a pin):* Pins `model: "sonnet"`, `advisorModel: "fable"`. Native 1M context, no `[1m]` suffix needed. Beats Opus 4.6 on every coding benchmark, generally lower Max quota. Effort: `medium`, escalate `high` `xhigh` for hard tasks.
249
249
  > - **[o] OpusPlan Hybrid** *(Setup C — cost-conscious, still want Opus reasoning):* Pins `model: "opusplan"`. Opus 4.8 plans (Shift+Tab), Sonnet 5 executes. Max-bundled. No API credit drain (#390).
250
250
  > - **[b] Opus 4.6 Stability** *(Setup B — legacy flagship, proven consistency for high-stakes/complex repos):* Pins `model: "claude-opus-4-6"`. Opus 4.6 max everywhere. Max-bundled (auto-upgrades to 1M on Max plans).
251
251
  >
@@ -259,14 +259,14 @@ The output is JSON: `{ tier: "simple" | "complex", score, signals }`. Use the re
259
259
  {
260
260
  "model": "sonnet",
261
261
  "advisorModel": "fable",
262
- "effortLevel": "high",
262
+ "effortLevel": "medium",
263
263
  "env": {
264
264
  "CLAUDE_AUTOCOMPACT_PCT_OVERRIDE": "75"
265
265
  }
266
266
  }
267
267
  ```
268
268
 
269
- Tell the user: "Sonnet 5 + Fable — the wizard's recommended pin (Setup A). Effort defaults to `high`, escalate via `/effort xhigh` for hard tasks. Requires CC v2.1.170+ — run `! claude update` if needed."
269
+ Tell the user: "Sonnet 5 + Fable — the wizard's recommended pin (Setup A). Effort: `medium`, escalate `/effort high` → `xhigh` for hard tasks. Requires CC v2.1.170+ — run `! claude update` if needed."
270
270
 
271
271
  **If the user answers `o` (opusplan):** Edit `.claude/settings.json` and add:
272
272
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: update-wizard
3
3
  description: Smart update for SDLC wizard — shows changelog, compares files, lets you selectively adopt changes while preserving customizations.
4
- argument-hint: [optional: check-only | force-all]
4
+ argument-hint: "[optional: check-only | force-all]"
5
5
  effort: high
6
6
  ---
7
7
  # Update Wizard - Smart SDLC Update
@@ -95,16 +95,15 @@ Parse CHANGELOG entries between the user's installed version and the resolved la
95
95
 
96
96
  ```
97
97
  Installed: 1.42.0
98
- Latest: 1.86.0
98
+ Latest: 1.87.0
99
99
 
100
100
  What changed:
101
+ - [1.87.0] First external contribution (@thejesh23, #444): argument-hint frontmatter quoted so Copilot CLI ≥1.0.65 loads skills, plus regression test; GPT-5.6 Sol reviewer sweep; Sonnet 5 default effort → medium (unbacked 5x quota claim removed, hook floor matched).
101
102
  - [1.86.0] Fix #437: codex-gate-check.sh now blocks stale certifications — a CERTIFIED handoff.json no longer sails through forever; it records commit_sha at cert time and blocks once HEAD moves past it without a re-cert.
102
103
  - [1.85.0] Post-ship retrospective: CI Feedback Loop synced to SKILL.md's stronger version, CERTIFIED≠CI lesson, Policy Migration Inventory checklist, stale round-count correction.
103
104
  - [1.84.0] Hook enforcement fix: cross-model review gate + TDD RED gate now actually block (#436); model-aware effort docs replace blanket max recommendation.
104
105
  - [1.83.0] Model config batch: multi-model hook recommendation (#403), global [1m] pin detection (#391), version race fix (#405), effort config check (#384).
105
106
  - [1.82.0] Usage diagnostics: fix /usage row, Reading Usage Signals guide, advisor fallback procedure, Fable effort guidance, autocompact cross-reference.
106
- - [1.81.0] Native `advisorModel` support: Setup A gets Fable advisor, Setup B gets Opus advisor. Replaces manual subagent spawning. Requires CC v2.1.170+.
107
- - [1.80.0] Flip default: Opus 4.6 max becomes recommended flagship; Opus 4.8 demoted to opt-in `[l] Latest` tier.
108
107
  - [1.75.1] release-workflow fix — Node 22 → 24 (ships npm 11.x), dropped flaky `npm install -g` self-upgrade (hit MODULE_NOT_FOUND on v1.75.0 publish). Explicit npm-version guard.
109
108
  - [1.75.0] npm Trusted Publishing — `release.yml` swapped from `NPM_TOKEN` to OIDC. No more token rotation. Requires one-time publisher config on the npm package page.
110
109
  - [1.74.0] v1.43 salvage: #338 precedence preamble; #235ab `/insights`; codex `< /dev/null` stdin-hang fix; test env-isolation.
@@ -1,82 +0,0 @@
1
- #!/bin/bash
2
- # /goal SDLC discipline gate (ROADMAP #360).
3
- #
4
- # UserPromptSubmit hook. When the user invokes `/goal <condition>`, scan the
5
- # prior assistant text for a HIGH 95% confidence statement AND check the
6
- # condition for a DLC binding (`/sdlc`, `/gdlc`, `/ldlc`, etc.). Emit loud
7
- # warnings on either gap so the SDLC-discipline gap surfaces BEFORE the goal
8
- # evaluator starts rubber-stamping flailing as progress.
9
- #
10
- # PR #355 (v1.77.0) added the guidance text in skills/sdlc/SKILL.md. This
11
- # hook is the enforcement layer per #360. Non-blocking soft nudge — same
12
- # pattern as model-effort-check.sh.
13
-
14
- HOOK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
15
- source "$HOOK_DIR/_find-sdlc-root.sh"
16
-
17
- # Plugin + project copies both register this hook → plugin yields (#236).
18
- dedupe_plugin_or_project "${BASH_SOURCE[0]}" || exit 0
19
-
20
- # Must be invoked via hook (stdin JSON), not interactively.
21
- [ -t 0 ] && exit 0
22
- STDIN_JSON=$(cat)
23
- [ -z "$STDIN_JSON" ] && exit 0
24
- command -v jq > /dev/null 2>&1 || exit 0
25
-
26
- PROMPT=$(printf '%s' "$STDIN_JSON" | jq -r '.prompt // empty' 2>/dev/null) || exit 0
27
- [ -z "$PROMPT" ] && exit 0
28
-
29
- # Only act on `/goal <condition>` invocations. `/goal` alone (status) and
30
- # `/goal clear` (reset) must stay silent — those aren't discipline events.
31
- case "$PROMPT" in
32
- "/goal") exit 0 ;;
33
- "/goal "[[:space:]]*) exit 0 ;;
34
- "/goal clear") exit 0 ;;
35
- "/goal clear "*) exit 0 ;;
36
- "/goal "*) ;;
37
- *) exit 0 ;;
38
- esac
39
-
40
- CONDITION="${PROMPT#/goal }"
41
-
42
- # === Confidence gate ===
43
- # Read transcript_path, slurp JSONL, find last assistant message with text
44
- # content, scan for HIGH-95% confidence pattern. Silent on missing/unreadable
45
- # transcript — better to under-warn than crash a soft nudge.
46
- TRANSCRIPT_PATH=$(printf '%s' "$STDIN_JSON" | jq -r '.transcript_path // empty' 2>/dev/null) || TRANSCRIPT_PATH=""
47
- HAS_CONFIDENCE=0
48
- if [ -n "$TRANSCRIPT_PATH" ] && [ -r "$TRANSCRIPT_PATH" ]; then
49
- LAST_ASSISTANT_TEXT=$(jq -rs '
50
- [.[] | select(.type == "assistant")]
51
- | last
52
- | if . == null then ""
53
- else (.message.content // []) | map(select(.type == "text") | .text) | join("\n")
54
- end
55
- ' "$TRANSCRIPT_PATH" 2>/dev/null) || LAST_ASSISTANT_TEXT=""
56
- if printf '%s' "$LAST_ASSISTANT_TEXT" | grep -qiE 'HIGH \(?95%|confidence:?[[:space:]]+HIGH|HIGH[[:space:]]+95%|95%[[:space:]]+confidence'; then
57
- HAS_CONFIDENCE=1
58
- fi
59
- fi
60
-
61
- if [ "$HAS_CONFIDENCE" -eq 0 ]; then
62
- echo ""
63
- echo "!! /GOAL CONFIDENCE GATE: prior turn did not state HIGH 95% confidence !!"
64
- echo " The /goal Haiku evaluator rubber-stamps flailing as progress below 95%."
65
- echo " Recommendation: /goal clear → do research → state HIGH 95% confidence → re-issue /goal."
66
- echo " (Source: skills/sdlc/SKILL.md Long-Running Goals section, ROADMAP #360.)"
67
- echo ""
68
- fi
69
-
70
- # === DLC binding gate ===
71
- # Condition MUST name a DLC (`/sdlc`, `/gdlc`, `/ldlc`, etc.) so the
72
- # evaluator anchors on "doing it right" not just "doing it".
73
- if ! printf '%s' "$CONDITION" | grep -qiE '/[a-z]+dlc'; then
74
- echo ""
75
- echo "!! /GOAL DLC-BINDING GATE: condition does not name a DLC (/sdlc, /gdlc, /ldlc) !!"
76
- echo " The evaluator needs a discipline anchor to judge 'doing it right' vs flailing."
77
- echo " Recommendation: rewrite condition to include 'following /sdlc' (or /gdlc/etc)."
78
- echo " (Source: skills/sdlc/SKILL.md Long-Running Goals section, ROADMAP #360.)"
79
- echo ""
80
- fi
81
-
82
- exit 0