feat(hooks): PreCompact seam gate — block mid-cycle manual /compact (#208) - #205
Conversation
…208) Compacting mid-Codex-review loses the round-1 evidence and certify conditions that round-2 needs to re-verify. Compacting mid-rebase strands the operation without context. The % threshold is the trigger; the decision is whether we're on a seam. Natural seams: commit boundary, Codex CERTIFIED, PR merge, ROADMAP DONE. hooks/precompact-seam-check.sh reads .reviews/handoff.json and blocks (exit 2 + HOLD stderr) when status is PENDING_REVIEW / PENDING_RECHECK. Also blocks on in-flight git rebase/merge/cherry-pick. Wired to matcher: "manual" only — auto-compact must NOT be blocked (could push past 100% context and lose everything). Requires Claude Code v2.1.105+ (PreCompact event introduced 2026-04-13). Independently confirmed by PR #195's auto-update analysis which explicitly called out PreCompact as a candidate for TDD/plan-context preservation. Files: - hooks/precompact-seam-check.sh (new) — 64 lines, < 1KB worst-case stderr - hooks/hooks.json — PreCompact event added (plugin parity) - .claude/settings.json — wizard's own project dogfoods the hook - cli/templates/settings.json — new installs get the hook registered - cli/init.js — CLI distributes precompact-seam-check.sh as 9th file - CLAUDE_CODE_SDLC_WIZARD.md — 'Compact at Seams, Not Thresholds' section + hooks-table row - SDLC.md — hooks table + tree entry - ROADMAP.md — #208 marked DONE Tests (9 new in tests/test-hooks.sh, 105/105 hook suite passing): - precompact_hook_exists - precompact_silent_without_handoff_or_git_op - precompact_silent_when_handoff_certified - precompact_blocks_on_pending_review (rc=2, stderr contains HOLD) - precompact_blocks_on_pending_recheck - precompact_blocks_on_git_rebase_in_progress - precompact_blocks_on_git_merge_in_progress - precompact_blocks_on_cherry_pick_in_progress - precompact_size_cap (stacked worst-case < 1000 chars) Negative control: 50-line echo bloat injected into the hook trips size_cap (4793 chars >= 1000). Hook count tests in test-cli.sh / test-plugin.sh updated from 4 -> 5 to match new event.
E2E Quick Check (Tier 1) ✅Fast quality gate - single comparison per commit.
Result: No change in SDLC compliance (stable)
Criteria Breakdown
Historical ContextThis scenario avg: 8.0 (2 runs) Add Tier 1: 1x run each. SDP adjusts for external model conditions. |
|
Claude finished @BaseInfinity's task in 3m 27s —— View job PR Code ReviewSummaryAdds a Recommendation: APPROVEFindingsP0 — Critical (must fix before merge)None. Verified the top risk from the handoff's All three registrations correctly scope to P1 — Must Fix (should fix before merge)None. All 105/105 hook tests pass locally on the checkout; matcher parity verified; grep-based status parsing behaves correctly on tight and whitespace-padded JSON in the tests. P2 — Suggestions (nice to have)
Strengths
E2E Coverage NoteThis PR changes SDLC enforcement behavior (new hook). Existing hook tests ( Files Reviewed
|
|
Posted the re-review. Summary: Recommendation: APPROVE This was a sync-trigger re-review after commit
|
- Add test_precompact_blocks_on_git_rebase_apply_in_progress (P1 #1 fix): distinct fixture for .git/rebase-apply/ which is a separate code path from rebase-merge. Hook suite 105 → 106 tests. - Update CLI/plugin tests to enumerate precompact-seam-check.sh + model-effort-check.sh (P1 #2 fix): test_creates_all_files now expects 11 files instead of 10; test_hooks_executable checks 5 instead of 3; test_plugin_hook_scripts_exist/executable and test_cli_installs_hooks_from_plugin_source iterate the full 5-hook list. Future shipped hooks can't silently miss coverage. - Doc alignment (P2 #3 fix): (a) CLAUDE_CODE_SDLC_WIZARD.md gets a 'What's NOT checked' paragraph on the TodoWrite limitation, (b) SDLC.md tree adds _find-sdlc-root.sh with helper annotation so ls hooks/*.sh (6) matches doc, (c) ROADMAP.md #208 replaces the specific 4793-char negative-control number with a reproducible range explanation (~1200 short / ~4800 long, both ≥ 1000). All tests green: 106/106 hooks, 70/70 CLI, 25/25 plugin.
…hook # Conflicts: # tests/e2e/score-history.jsonl
|
Claude finished @BaseInfinity's task in 3m 27s —— View job PR Code Review (re-review after
|
| # | Finding | Fix | Evidence |
|---|---|---|---|
| 1 (P1) | rebase-apply branch untested |
test_precompact_blocks_on_git_rebase_apply_in_progress added |
tests/test-hooks.sh:297–312 — distinct fixture .git/rebase-apply/head-name, asserts rc=2 + stderr matches /rebase/i. Real test, not a tautology. |
| 2 (P1) | CLI/plugin tests didn't assert precompact hook ships | Enumeration expanded to full 5-hook list | tests/test-cli.sh:76–118 now expects 11 files + 5 executables; tests/test-plugin.sh:218, 231, 289 iterate the full sdlc-prompt-check.sh tdd-pretool-check.sh instructions-loaded-check.sh model-effort-check.sh precompact-seam-check.sh list. A new hook shipped without touching these loops would now fail CI. |
| 3 (P2) | Docs drift (TodoWrite limitation, SDLC tree, negative-control magic number) | (a) "What's NOT checked" paragraph in CLAUDE_CODE_SDLC_WIZARD.md:861; (b) _find-sdlc-root.sh added to SDLC.md:79 tree with "Shared helper" annotation so ls hooks/*.sh (6) matches doc; (c) ROADMAP.md:245 replaced 4793 with reproducible range ~1200 short / ~4800 long, both ≥ 1000. |
All three confirmed in the tree. |
Findings
P0 — Critical (must fix before merge)
None. Matcher parity re‑verified on this sync:
.claude/settings.json (HEAD): "matcher": "manual",
cli/templates/settings.json:47: "matcher": "manual",
hooks/hooks.json:48: "matcher": "manual",
The top failure-mode risk the handoff flagged — a wildcard matcher that would silently gate auto‑compact and risk pushing past 100% context — is not present.
P1 — Must Fix (should fix before merge)
None. 106/106 hook tests pass locally (including the new test_precompact_blocks_on_git_rebase_apply_in_progress). Test count increment in ROADMAP.md:245 ("10 quality tests") accurately reflects the hook‑specific test count (1 exists + 2 silent + 6 block + 1 size‑cap = 10). Version floor still consistent across the hook header, CLAUDE_CODE_SDLC_WIZARD.md:859/1868, and SDLC.md:45/84.
P2 — Suggestions (nice to have, carried over from prior review, still unaddressed — non-blocking)
hooks/precompact-seam-check.sh:17—INPUT=$(cat)is still assigned and never read. Either drop the var ([ ! -t 0 ] && cat >/dev/null || true) or add a one‑line comment noting the discard is intentional. Not a correctness issue — the TTY guard is doing the real work.hooks/precompact-seam-check.sh:1— still noset -eand still no explanatory comment, whileCLAUDE.md:53code style says to use it and the siblinginstructions-loaded-check.sh:5has the exact pattern of a one‑line "no set -e because …" comment. This hook has a legitimate reason (it deliberately exits 2 on blockers, which would be fine underset -eanyway — but a partial failure in the grep pipeline underset -o pipefailcould behave surprisingly). A one‑line comment would match the repo's "document the exception" convention.hooks/precompact-seam-check.sh:38—[ -d "$GITDIR" ]still silently skips when.gitis a file (worktree / submodule). The preflight's known‑limitations section calls this out, so it's a documented trade-off, not a bug. If you want to close the gap cheaply:[ -e "$GITDIR" ]and resolve viagit -C "$ROOT" rev-parse --git-dir.
Strengths (unchanged from prior review, all still hold)
- Three-way matcher parity to
"manual"— the feat: add auto-update system for Claude Code releases #1 P0 the handoff flagged. - Auto‑compact deliberately excluded with rationale documented in the hook header,
CLAUDE_CODE_SDLC_WIZARD.md,SDLC.md, andROADMAP.md. - Exit 2 to stderr via
{ … } >&2— correct CC block signal. - No tautological tests — every precompact test has a real fixture + real invocation + real assertion. The size-cap test would actually fail under a 50‑line bloat injection (verified in round 1).
- Three‑way version‑floor consistency (
v2.1.105+) across hook, wizard, SDLC. - Grep-based
statusparsinggrep -o '"status"[[:space:]]*:[[:space:]]*"[^"]*"'is robust to{"status":"…"},{ "status" : "…" }, and both work correctly under the test fixtures. - New enumeration loops in CLI/plugin tests now catch drift if a future PR ships a hook in
cli/init.jsbut forgets to add it to the loops — a nice generalization beyond just precompact coverage. - Honest preflight known-limitations section explicitly calling out: TodoWrite unobservability, worktree/submodule
.git-as-file case, and the fact that thematcher: "manual"registration is CC's responsibility to honor.
E2E Coverage Note
Unchanged from prior review: no E2E scenario exists for PreCompact, which is correct — E2E only fires on live /compact invocations the harness doesn't trigger. Unit + distribution coverage (106 hook + CLI/plugin enumeration) is the right level.
Files Reviewed (this cycle)
hooks/precompact-seam-check.shhooks/hooks.json.claude/settings.json(HEAD; note local working-tree edit exists but is not part of this PR)cli/templates/settings.jsontests/test-hooks.sh(newrebase-applytest)tests/test-cli.sh(expandedtest_creates_all_files,test_hooks_executable)tests/test-plugin.sh(expanded 3-hook loops → 5)CLAUDE_CODE_SDLC_WIZARD.md(new "What's NOT checked" para)SDLC.md(tree adds_find-sdlc-root.sh)ROADMAP.md(reproducible neg-control magnitude).reviews/handoff.json,.reviews/response.json,.reviews/preflight-precompact-seam-001.md
- Fetch latest branch state and identify new commits since last review
- Re-check hook script + matcher parity (3 files)
- Re-run hook test suite locally (106/106 pass)
- Verify
CODE_REVIEW_EXCEPTIONS.mdfor documented exemptions (none apply) - Check if previous P2s were addressed (carried forward, non-blocking)
- Post updated review
· branchfeat/precompact-seam-hook
Bug hit live 2026-04-19 after PR #205 merged — `.reviews/handoff.json` stayed at PENDING_RECHECK, every subsequent /compact got blocked by the user's own stale review artifact. Ships to consumers via CLI + plugin, so every adopter of the handoff protocol who forgets to flip status after merge will hit the same wall. Fix: when status is PENDING_REVIEW/PENDING_RECHECK, parse optional pr_number from handoff. If present AND gh is available, query `gh pr view <pr_number> --json state` — MERGED unblocks (implicit CERTIFIED). Missing pr_number, missing gh, offline, or any error falls through to existing block (safe default). 4 new tests with mocked gh binary: merged unblocks, open blocks, no pr_number blocks, gh-errors blocks. Hook suite 106 → 110. Codex xhigh design review ran before implementation (verdict: RECOMMENDED_ALTERNATIVE: 2, priority 9/10). Branch-awareness alternative rejected — false-unblocks trunk-based workflows.
#206) * feat(hooks): self-healing PreCompact on merged-PR stale handoff (#209) Bug hit live 2026-04-19 after PR #205 merged — `.reviews/handoff.json` stayed at PENDING_RECHECK, every subsequent /compact got blocked by the user's own stale review artifact. Ships to consumers via CLI + plugin, so every adopter of the handoff protocol who forgets to flip status after merge will hit the same wall. Fix: when status is PENDING_REVIEW/PENDING_RECHECK, parse optional pr_number from handoff. If present AND gh is available, query `gh pr view <pr_number> --json state` — MERGED unblocks (implicit CERTIFIED). Missing pr_number, missing gh, offline, or any error falls through to existing block (safe default). 4 new tests with mocked gh binary: merged unblocks, open blocks, no pr_number blocks, gh-errors blocks. Hook suite 106 → 110. Codex xhigh design review ran before implementation (verdict: RECOMMENDED_ALTERNATIVE: 2, priority 9/10). Branch-awareness alternative rejected — false-unblocks trunk-based workflows. * chore: record E2E score [skip ci] * test(hooks): add zero-stderr + gh-missing assertions (PR #206 Codex R1) * chore: record E2E score [skip ci] * docs(sdlc,ci): require Codex xhigh audit on CI logs in shepherd loop * chore: record E2E score [skip ci] * docs(roadmap): file #210 Node24 false-green + #211 tier1 11/10 (Codex CI-log audit on #206) * chore: record E2E score [skip ci] * docs(roadmap): add #212 local-Max E2E shepherd (zero-API alt) * docs(sdlc): run Codex audit on Tier 1 AND Tier 2 CI logs separately * docs(roadmap): #213 CLI template env-block gap — adaptive thinking + autocompact vars documented but not shipped * docs(roadmap): #214 Prove-It A/B for adaptive thinking; gate #213 on result * docs(roadmap): #215 Tier 2 persist step is dead code (Codex Tier 2 audit on #206) --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
…252) ROADMAP #205 phase (a): setup wizard scans for AGENTS.md (cross-tool agent-instructions standard, CC #6235) and surfaces a 3-way decision (dual-maintain default / merge / skip) when found. Phase (a) scope is detection + decision recording ONLY: - No wizard-side merge or symlink behavior - Option B = "record intent, copy by hand"; phase (b) adds the copy helper - Choice recorded as one-line SDLC.md comment for user reference; /update-wizard does NOT yet parse it (phase d) Codex round 1: 6/10 NOT CERTIFIED. 3 P1 findings: - F-001: SDLC.md metadata persistence claim was false (no actual wiring). Weakened to user-reference comment only. - F-002: Option B wording said "copy CLAUDE.md content" which is merge behavior contradicting "detection-only" scope. Reworded to manual-intent-recording only. - F-003: Test 5 false-greened on broad "cross-tool" matches elsewhere in wizard. Scoped to extracted AGENTS.md subsection. Round 2: 10/10 CERTIFIED. Mutation re-verified. 7 quality tests in tests/test-agents-md-interop.sh.
* docs(handoff): document pr_number self-heal opt-in (#209, v1.42.2) ROADMAP #209 closure. The precompact-seam-check.sh hook self-heals on PENDING_* handoffs whose linked PR has merged: when handoff has pr_number and `gh pr view N --json state` returns MERGED, hook treats handoff as implicit CERTIFIED and unblocks /compact silently. Self-heal logic shipped earlier alongside #229 (stale-expire fallback) but was undocumented in the handoff template schemas, leaving the path effectively dead code on fresh installs (consumers had no way to discover the opt-in). Documented pr_number in all 3 handoff templates: - skills/sdlc/SKILL.md (Step 1: Mission-First Handoff) + key-fields prose - CLAUDE_CODE_SDLC_WIZARD.md (Round 1: Initial Review) - CLAUDE_CODE_SDLC_WIZARD.md (cross-model review section) New regression test test_handoff_template_documents_pr_number in tests/test-hooks.sh enforces template/doc parity going forward — a future schema edit that drops pr_number will fail this test. Together with #229 (mtime auto-expire) closes the "stuck PENDING handoff blocks /compact forever" footgun from both directions: PR-linked reviews self-heal on merge (instant), unlinked reviews auto-expire on mtime (14d default). Hit live in this repo 2026-04-19 (PR #205) and 2026-04-26 (PR #253) where handoffs lacked pr_number and fell through to the stale-expire fallback. Tests: 130 hook tests passing (1 new), 10 adjacent test files green. * fix(handoff-test): round-2 — coverage + prose + count (#255) Codex round-1 review (6/10 NOT CERTIFIED) found 3 issues: 1. P1: test_handoff_template_documents_pr_number false-greened on single-schema deletion. Required ANY occurrence per file, but wizard has 2 schemas — removing pr_number from one left the other intact and test passed. Fix: count handoff schemas via `"status": "PENDING_REVIEW"` marker (response.json uses PENDING_RECHECK so no collision). Assert pr_number occurrence count >= handoff count per file. Mutation re-verified: deleting pr_number from any of the 3 schemas now flips test to FAIL with skill-coverage(0/1) or wizard-coverage(1/2). Discovered separate grep -c quirk: `|| echo 0` after grep -c with no matches produces '0\n0' (grep -c always prints a number AND exits 1; || appends another 0). Switched to `|| true` + `${var:-0}` defaults — preserves count, discards failing exit, set -e safe. 2. P2: cross-model schema had pr_number field but no nearby prose explanation. Round 1 schema's inline explanation wasn't mirrored. Fix: added paragraph at CLAUDE_CODE_SDLC_WIZARD.md:3709 explaining when to set pr_number, what precompact-seam-check.sh does with it, when to omit. 3. P2: CHANGELOG overstated hook test count (130 vs actual 129). Fix: corrected to "129 hook tests, 1 new". All 3 mutation paths verified catching: - skill schema delete → FAIL skill-coverage(0/1) - wizard cross-model delete → FAIL wizard-coverage(1/2) - wizard Round 1 delete → FAIL wizard-coverage(1/2) Adjacent regression: 10 test files green (test-hooks 129/0 + 9 others).
#289) Three items quietly shipped pre-2026-04-29 but never had ROADMAP marked done: - #232 (`/update-wizard` CLI freshness mimicking `claude update`): shipped v1.40.0. skills/update/SKILL.md Step 1.5 detects installed CLI version (npm ls -g + npx cache, semver-aware), compares to registry.npmjs.org, surfaces 3 upgrade options (refresh cache / one-shot init --force / skip), honors check-only precedence. 8 tests in test-update-skill-cli-version.sh. - #205 phases (a)+(c) (AGENTS.md interop): shipped v1.42.0. setup skill Step 4.5 detects AGENTS.md and offers dual-maintain / merge / skip. Phases (b) auto-generate-AGENTS.md and (d) drift-test remain deferred ("agent-agnostic SDLC is on the back burner"). - #90 (Distribution Channels): duplicate entry — already marked DONE at line 196 of ROADMAP. Removed the duplicate at line 239. No code changes — ROADMAP-only.
…208) (#205) * feat(hooks): PreCompact seam gate — block mid-cycle manual /compact (#208) Compacting mid-Codex-review loses the round-1 evidence and certify conditions that round-2 needs to re-verify. Compacting mid-rebase strands the operation without context. The % threshold is the trigger; the decision is whether we're on a seam. Natural seams: commit boundary, Codex CERTIFIED, PR merge, ROADMAP DONE. hooks/precompact-seam-check.sh reads .reviews/handoff.json and blocks (exit 2 + HOLD stderr) when status is PENDING_REVIEW / PENDING_RECHECK. Also blocks on in-flight git rebase/merge/cherry-pick. Wired to matcher: "manual" only — auto-compact must NOT be blocked (could push past 100% context and lose everything). Requires Claude Code v2.1.105+ (PreCompact event introduced 2026-04-13). Independently confirmed by PR #195's auto-update analysis which explicitly called out PreCompact as a candidate for TDD/plan-context preservation. Files: - hooks/precompact-seam-check.sh (new) — 64 lines, < 1KB worst-case stderr - hooks/hooks.json — PreCompact event added (plugin parity) - .claude/settings.json — wizard's own project dogfoods the hook - cli/templates/settings.json — new installs get the hook registered - cli/init.js — CLI distributes precompact-seam-check.sh as 9th file - CLAUDE_CODE_SDLC_WIZARD.md — 'Compact at Seams, Not Thresholds' section + hooks-table row - SDLC.md — hooks table + tree entry - ROADMAP.md — #208 marked DONE Tests (9 new in tests/test-hooks.sh, 105/105 hook suite passing): - precompact_hook_exists - precompact_silent_without_handoff_or_git_op - precompact_silent_when_handoff_certified - precompact_blocks_on_pending_review (rc=2, stderr contains HOLD) - precompact_blocks_on_pending_recheck - precompact_blocks_on_git_rebase_in_progress - precompact_blocks_on_git_merge_in_progress - precompact_blocks_on_cherry_pick_in_progress - precompact_size_cap (stacked worst-case < 1000 chars) Negative control: 50-line echo bloat injected into the hook trips size_cap (4793 chars >= 1000). Hook count tests in test-cli.sh / test-plugin.sh updated from 4 -> 5 to match new event. * docs(reviews): handoff + preflight for PR #205 precompact-seam (#208) * chore: record E2E score [skip ci] * test(hooks): address Codex round 1 findings on PreCompact seam gate - Add test_precompact_blocks_on_git_rebase_apply_in_progress (P1 #1 fix): distinct fixture for .git/rebase-apply/ which is a separate code path from rebase-merge. Hook suite 105 → 106 tests. - Update CLI/plugin tests to enumerate precompact-seam-check.sh + model-effort-check.sh (P1 #2 fix): test_creates_all_files now expects 11 files instead of 10; test_hooks_executable checks 5 instead of 3; test_plugin_hook_scripts_exist/executable and test_cli_installs_hooks_from_plugin_source iterate the full 5-hook list. Future shipped hooks can't silently miss coverage. - Doc alignment (P2 #3 fix): (a) CLAUDE_CODE_SDLC_WIZARD.md gets a 'What's NOT checked' paragraph on the TodoWrite limitation, (b) SDLC.md tree adds _find-sdlc-root.sh with helper annotation so ls hooks/*.sh (6) matches doc, (c) ROADMAP.md #208 replaces the specific 4793-char negative-control number with a reproducible range explanation (~1200 short / ~4800 long, both ≥ 1000). All tests green: 106/106 hooks, 70/70 CLI, 25/25 plugin. * chore: record E2E score [skip ci] --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
#206) * feat(hooks): self-healing PreCompact on merged-PR stale handoff (#209) Bug hit live 2026-04-19 after PR #205 merged — `.reviews/handoff.json` stayed at PENDING_RECHECK, every subsequent /compact got blocked by the user's own stale review artifact. Ships to consumers via CLI + plugin, so every adopter of the handoff protocol who forgets to flip status after merge will hit the same wall. Fix: when status is PENDING_REVIEW/PENDING_RECHECK, parse optional pr_number from handoff. If present AND gh is available, query `gh pr view <pr_number> --json state` — MERGED unblocks (implicit CERTIFIED). Missing pr_number, missing gh, offline, or any error falls through to existing block (safe default). 4 new tests with mocked gh binary: merged unblocks, open blocks, no pr_number blocks, gh-errors blocks. Hook suite 106 → 110. Codex xhigh design review ran before implementation (verdict: RECOMMENDED_ALTERNATIVE: 2, priority 9/10). Branch-awareness alternative rejected — false-unblocks trunk-based workflows. * chore: record E2E score [skip ci] * test(hooks): add zero-stderr + gh-missing assertions (PR #206 Codex R1) * chore: record E2E score [skip ci] * docs(sdlc,ci): require Codex xhigh audit on CI logs in shepherd loop * chore: record E2E score [skip ci] * docs(roadmap): file #210 Node24 false-green + #211 tier1 11/10 (Codex CI-log audit on #206) * chore: record E2E score [skip ci] * docs(roadmap): add #212 local-Max E2E shepherd (zero-API alt) * docs(sdlc): run Codex audit on Tier 1 AND Tier 2 CI logs separately * docs(roadmap): #213 CLI template env-block gap — adaptive thinking + autocompact vars documented but not shipped * docs(roadmap): #214 Prove-It A/B for adaptive thinking; gate #213 on result * docs(roadmap): #215 Tier 2 persist step is dead code (Codex Tier 2 audit on #206) --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Bug hit live 2026-04-19 after PR #205 merged — `.reviews/handoff.json` stayed at PENDING_RECHECK, every subsequent /compact got blocked by the user's own stale review artifact. Ships to consumers via CLI + plugin, so every adopter of the handoff protocol who forgets to flip status after merge will hit the same wall. Fix: when status is PENDING_REVIEW/PENDING_RECHECK, parse optional pr_number from handoff. If present AND gh is available, query `gh pr view <pr_number> --json state` — MERGED unblocks (implicit CERTIFIED). Missing pr_number, missing gh, offline, or any error falls through to existing block (safe default). 4 new tests with mocked gh binary: merged unblocks, open blocks, no pr_number blocks, gh-errors blocks. Hook suite 106 → 110. Codex xhigh design review ran before implementation (verdict: RECOMMENDED_ALTERNATIVE: 2, priority 9/10). Branch-awareness alternative rejected — false-unblocks trunk-based workflows.
…252) ROADMAP #205 phase (a): setup wizard scans for AGENTS.md (cross-tool agent-instructions standard, CC #6235) and surfaces a 3-way decision (dual-maintain default / merge / skip) when found. Phase (a) scope is detection + decision recording ONLY: - No wizard-side merge or symlink behavior - Option B = "record intent, copy by hand"; phase (b) adds the copy helper - Choice recorded as one-line SDLC.md comment for user reference; /update-wizard does NOT yet parse it (phase d) Codex round 1: 6/10 NOT CERTIFIED. 3 P1 findings: - F-001: SDLC.md metadata persistence claim was false (no actual wiring). Weakened to user-reference comment only. - F-002: Option B wording said "copy CLAUDE.md content" which is merge behavior contradicting "detection-only" scope. Reworded to manual-intent-recording only. - F-003: Test 5 false-greened on broad "cross-tool" matches elsewhere in wizard. Scoped to extracted AGENTS.md subsection. Round 2: 10/10 CERTIFIED. Mutation re-verified. 7 quality tests in tests/test-agents-md-interop.sh.
* docs(handoff): document pr_number self-heal opt-in (#209, v1.42.2) ROADMAP #209 closure. The precompact-seam-check.sh hook self-heals on PENDING_* handoffs whose linked PR has merged: when handoff has pr_number and `gh pr view N --json state` returns MERGED, hook treats handoff as implicit CERTIFIED and unblocks /compact silently. Self-heal logic shipped earlier alongside #229 (stale-expire fallback) but was undocumented in the handoff template schemas, leaving the path effectively dead code on fresh installs (consumers had no way to discover the opt-in). Documented pr_number in all 3 handoff templates: - skills/sdlc/SKILL.md (Step 1: Mission-First Handoff) + key-fields prose - CLAUDE_CODE_SDLC_WIZARD.md (Round 1: Initial Review) - CLAUDE_CODE_SDLC_WIZARD.md (cross-model review section) New regression test test_handoff_template_documents_pr_number in tests/test-hooks.sh enforces template/doc parity going forward — a future schema edit that drops pr_number will fail this test. Together with #229 (mtime auto-expire) closes the "stuck PENDING handoff blocks /compact forever" footgun from both directions: PR-linked reviews self-heal on merge (instant), unlinked reviews auto-expire on mtime (14d default). Hit live in this repo 2026-04-19 (PR #205) and 2026-04-26 (PR #253) where handoffs lacked pr_number and fell through to the stale-expire fallback. Tests: 130 hook tests passing (1 new), 10 adjacent test files green. * fix(handoff-test): round-2 — coverage + prose + count (#255) Codex round-1 review (6/10 NOT CERTIFIED) found 3 issues: 1. P1: test_handoff_template_documents_pr_number false-greened on single-schema deletion. Required ANY occurrence per file, but wizard has 2 schemas — removing pr_number from one left the other intact and test passed. Fix: count handoff schemas via `"status": "PENDING_REVIEW"` marker (response.json uses PENDING_RECHECK so no collision). Assert pr_number occurrence count >= handoff count per file. Mutation re-verified: deleting pr_number from any of the 3 schemas now flips test to FAIL with skill-coverage(0/1) or wizard-coverage(1/2). Discovered separate grep -c quirk: `|| echo 0` after grep -c with no matches produces '0\n0' (grep -c always prints a number AND exits 1; || appends another 0). Switched to `|| true` + `${var:-0}` defaults — preserves count, discards failing exit, set -e safe. 2. P2: cross-model schema had pr_number field but no nearby prose explanation. Round 1 schema's inline explanation wasn't mirrored. Fix: added paragraph at CLAUDE_CODE_SDLC_WIZARD.md:3709 explaining when to set pr_number, what precompact-seam-check.sh does with it, when to omit. 3. P2: CHANGELOG overstated hook test count (130 vs actual 129). Fix: corrected to "129 hook tests, 1 new". All 3 mutation paths verified catching: - skill schema delete → FAIL skill-coverage(0/1) - wizard cross-model delete → FAIL wizard-coverage(1/2) - wizard Round 1 delete → FAIL wizard-coverage(1/2) Adjacent regression: 10 test files green (test-hooks 129/0 + 9 others).
#289) Three items quietly shipped pre-2026-04-29 but never had ROADMAP marked done: - #232 (`/update-wizard` CLI freshness mimicking `claude update`): shipped v1.40.0. skills/update/SKILL.md Step 1.5 detects installed CLI version (npm ls -g + npx cache, semver-aware), compares to registry.npmjs.org, surfaces 3 upgrade options (refresh cache / one-shot init --force / skip), honors check-only precedence. 8 tests in test-update-skill-cli-version.sh. - #205 phases (a)+(c) (AGENTS.md interop): shipped v1.42.0. setup skill Step 4.5 detects AGENTS.md and offers dual-maintain / merge / skip. Phases (b) auto-generate-AGENTS.md and (d) drift-test remain deferred ("agent-agnostic SDLC is on the back burner"). - #90 (Distribution Channels): duplicate entry — already marked DONE at line 196 of ROADMAP. Removed the duplicate at line 239. No code changes — ROADMAP-only.
Summary
Closes ROADMAP #208.
Adds
hooks/precompact-seam-check.sh— a PreCompact hook that blocks manual/compactwhen we're mid-cycle. Three classes of seam violation:.reviews/handoff.jsonstatus isPENDING_REVIEW/PENDING_RECHECK— compacting now loses round-1 evidence the next recheck needs.git/rebase-merge,.git/rebase-apply).git/MERGE_HEAD,.git/CHERRY_PICK_HEAD)On any of these, hook exits 2 with a
HOLDmessage on stderr. Auto-compact is not gated (matcher:"manual") — blocking auto could push past 100% context and lose everything.Requires Claude Code v2.1.105+ (PreCompact event introduced 2026-04-13). PR #195's analysis independently called out PreCompact as a candidate for context preservation.
Why
User raised 2026-04-19: "25-30% remaining ≈ 70% used is fine — but compacting between discrete units (end of a cycle, after a commit) rather than mid-unit" matters more than the exact threshold. Threshold stays the trigger; the hook adds the seam-awareness we were missing.
Natural seams documented in
CLAUDE_CODE_SDLC_WIZARD.md"Compact at Seams, Not Thresholds" section: commit boundary, CodexCERTIFIED, PR merge, ROADMAP item DONE.Test plan
test_precompact_size_capat 4793 chars >= 1000