Repository navigation
feat: harvest 4 — the kit as applied: settings liveness, the hook stdin/exit contract, the exercised fork detector, and the rest of #58 - #59
Merged
Conversation
… found Design spec for landing, in the kit, every finding on issue #58 that carries a proven fix: the two target-project syncs of e92e9c4 (you-are-hear #42/PR #43, echosphere ECH-40/PR #37) and their post-merge repairs (echosphere PR #38, you-are-hear PR #82 and 39ed311). Seven clusters H1–H7, decisions D30–D40 settled with the operator 2026-09-21, one PR with atomic commits per item. Preceded by a 64-agent read of the sources (seven sonnet readers, two opus verifiers per plan-changing fact, one opus critic): 28 facts verified, 21 confirmed, 3 refuted, 4 contested and adjudicated by direct reads of the kit tree and the installed Claude Code 2.1.278 bundle. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Fifteen tasks in the spec's commit order (H4 runner and repairs first, then H1–H3 hooks and settings, H5 harness, H6 records, H7 templates), each ending in the verification block run through its new runner. Six planning decisions recorded for the PR body (D-P-1..6): the extraction rails live in a runner script; the advisory-exemplar arm is kit-tree-only with a project-side ADVISORY_WIRED declaration; the fixture probes the two decision sites the kit ships; review-sweep adopts finish-ab's reindex idiom; the review template already carries checks: read in the job block and lacks it in additional_permissions; the base ref is fetched by a step, not a checkout change. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…uarded .mcp.json.example, diagnostics kept, kit CI The block gains a runner (.claude/workflows/tests/run-verification-block.sh) carrying the two rails it cannot carry itself — an empty extraction is red, and an exit 0 without the done sentinel is red — both proven by mutation. The advisory-exemplar arm asserts "unregistered" on the kit tree only; a target declares ADVISORY_WIRED at the top of its project sub-block and that arm asserts each named hook registered exactly once and each unnamed one zero times (proven undeclared / declared / double-registered on a synthetic target). The .mcp.json.example operand is included only where the file exists; the launch-root dry-runs keep the hook's stderr and print it on failure. The kit's own CI runs the block through the runner on every PR (.github/workflows/verify.yml, no path filter). Closes #58 items 5 and 11 and the second-application items 1, 6 and 7. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… to the hook headers and the block asserts the invariant A hook-shaped object at the top level of settings.json is a fatal settings diagnostic on Claude Code 2.1.270–2.1.278, after which the parser returns no settings at all: every guard, enabledMcpjsonServers and enabledPlugins go inert, silently, with the verification block green. The kit shipped both advisory exemplars in exactly that shape. Both keys are deleted; each advisory hook's header carries the registration stanza as a `Register:` block; the registry comment says why no exemplar object may live in the file and names both memory scopes on the STOP tier; § Hook authoring's bullet states the invariant with its evidence; the block asserts no top-level key besides `hooks` holds a matcher/hooks object (proven red by mutation). Closes #58's settings-liveness finding (2026-09-13 comment) and the second-application item 5. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… pipe whose reader can exit first; Depends: in the header shape § Hook authoring states the two halves once, with who pays for the masking (a piping caller under pipefail — the block's dry-runs and the fixture, not the harness's registered call), the here-string rule and the measured bypasses (you-are-hear #81); the header shape gains a Depends: line; verify- by-payload names the fixture as the durable home. Closes #58 item 4's text half and the 2026-09-07 comment's Depends: request. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…never on a pipe whose reader can exit first Eight hooks move `input="$(cat)"` to the first statement after `set -uo pipefail`, above the dependency check and every early exit (the knowledge-backend gate reads its payload into a variable instead of `cat > /dev/null`). The two decision sites that piped `printf | grep -Eq` decide on here-strings with byte-identical patterns: measured before the change, a >250 KB multi-line `git commit -F -` body on main was ALLOWED (exit 0 — a HARD-DENY silently bypassed); after it, denied (exit 2). The detector's own site lands with its rewrite in the next commit. Closes #58 item 4's hook half (you-are-hear #81 → PR #82, the bypass measured 2026-09-18). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…e that reads every hook The Stop-tier detector takes the body two real applications proved: the prune list is the project's own ignore rules (git ls-files --ignored | check-ignore) with the three safety rules — never prune a path that could be or contain the hunted tree, escape glob metacharacters before -path, keep check-ignore so a collapsed ancestor is walked — find's stderr kept behind a writability probe, `./.claude-pr` (a hosted review action's staging copy) pruned unconditionally, a Depends: line, the residual named in the header, and a BLOCKED remediation that says a tooling path is not a fork and nothing is moved or deleted. § .gitignore anchoring names `/.claude-pr/` among the harness transients. Proven in a throwaway tree: the real fork denied and named alone, an ignored build tree and the staging copy pruned, the second stop warns and proceeds, a clean tree passes. hook-contract-fixture.sh asserts, over every .claude/hooks/*.sh, that the drain is the first statement and that no hook decides on a pipeline whose reader can exit first (a tripwire over known spellings), plus one over-buffer probe per decision site (the main-branch deny, the PR-state ask, the detector's second stop). Both structural checks proven red by mutation. The block runs it. Landed as one commit with the detector: the fixture reads every hook, so neither is green without the other. Closes #58 items 1, 2 and 4 (the fixture half), the 2026-09-07 comment's new defect and its item-2 correction. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…for the top tier, a zero-line transcript, null minutes and --json without a path Cache hits and refreshes on the top tier are 0.025x base input, not the 0.1x the reader applied to every tier (platform.claude.com/docs/en/build- with-claude/prompt-caching § Pricing, read 2026-09-07), so every top-tier figure it produced overstated the cache-read component 4x. CACHE_READ maps the tier to its multiplier with 0.1x as the default; the fixture gains a top-tier transcript asserted at $10.25 (proven red at $11.00 when the map is emptied), a transcript with zero parseable lines, a single-event transcript whose minutes are null, and the --json-without-a-path exit. Closes #58 item 6 and the smaller-items test gaps. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…egrades on a throwing roster read, reindexes retries by index; the harness stops swallowing its own exceptions A domain reviewer's path hint is a directory prefix: `src/schema` no longer claims `src/schema-extra/x` (a path equal to the hint still matches). The roster read — the one agent() call outside a parallel() thunk — takes `.catch(() => null)`, so a throw (a budget ceiling) degrades into the existing "roster read failed" branch with its gate line instead of ending the run with nothing. The retry pass reindexes by index list, the idiom finish-ab.js already uses. The stub harness's parallel() no longer swallows exceptions from its own mocks; three scenarios cover the boundary (both directions), the throwing roster, and three converging reporters under the least-loaded-owner bound. Both fixes proven red by mutation. Closes #58 items 7, 8 and 10 (the review-sweep half) and smaller item 6's idiom. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…h, guards hallucinations at both sites, reads effort once; harness scenarios for unattributed flags `arm` labels are checked distinct beside `anon` (otherFile() picks the other arm by label, so two arms labelled A threw inside the prompt builder after paying for the dispatch); both `hallucinations` dereferences take `?? []`, since a well-formed ranking can arrive without that field; `j.effort ?? "high"` is evaluated once. The stub harness's parallel() no longer swallows exceptions from its own mocks; three scenarios cover the label check (no dispatch first), the missing field (zero flags, no crash) and stray entries naming no arm (counted as unattributed, for neither arm, and logged). Both fixes proven red by mutation. Closes #58 item 9, item 10's finish-ab half, and the smaller items' unattributedFlags gap. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…lates emit The executor accepted three title forms while § Title-prefix scheme defines a fourth and the meta template emits it, so a tooling meta-issue failed the first precondition by construction. Step 1 now admits `[<slug>:meta] …` (with `<slug>` a workstream slug or the cascade/tooling lane's tag) and states the two routes a meta takes to the executor; the frame-inheritance line names a directly roughed-in meta beside the intake lanes. Applied identically to the bundled template; the pair is byte-parallel. Closes #58 smaller item 1. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…elation list states no count and defines Promotes:; the reviewer cites corrections by the register's id form Two real indexes contradicted the kit's pinned status-cell separator in two different ways, and adr-new would have written a third form into either. The row-writing step now reads the existing rows and matches their cell and separator; the starter index (and the kit's own, byte-identical) says a project's index sets its own form. § Refines vs Supersedes vs Extends lets the list be the count and defines the Promotes: slot it fills. The ADR reviewer cites a recorded correction by the register's own id form, not an assumed C- number. Closes #58's 2026-09-07 separator item and the second- application items 1 and 3. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…t row, stamped-state callouts, the cwd disagreement named, pubspec.lock and a *.lock fallback arm The framing procedure's "See rough-in's the rough-in skill's" citation reads "See the rough-in skill's"; the spec template spells the measurement variant marker one way; the Quick-reference row that called a frame's pre-flight table append-only is retired (framing writes it, rough-in reads it, nothing appends — the mutation row names only ## Rough-in events); the logging and testing callouts describe the mechanism so they read true before and after stamping, and name the inline-tests stack; the bootstrap rows say so. The launch-root guard's Timing paragraph carries both readings of the payload cwd and names the disagreement as its re-verify trigger. The lock-file guard gains a pubspec.lock arm and a *.lock fallback with a generic remediation (proven: pubspec.lock 2, flake.lock 2, notes.md 0). Closes #58 item 3, smaller items 2–4, and the second-application items 2 and 4. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…le; § Syncing the kit — three-way merge-file, the file-by-file table first Scaffold's Cascade metadata table gains a Kit commit row (the base of the next sync). The reference half gains § Syncing the kit: merge-file against the recorded install sha (47 of 48 customized files auto-resolved on a real application), the file-by-file table as the reusable artifact, and the two traps — a re-homed project sub-block must split its retired-vocabulary literals, and a fix a project needs ahead of the kit is filed upstream and carried as a named exception. The contract carries the pointer heading. Closes #58's second-application item 10. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…e base ref fetched, the prompt degrades explicitly on an oversized diff; the knowledge-backend matcher widened to the live tool set The review template already carried `checks: read` in the job block but not in the action's `additional_permissions` (the app token the action exchanges its OIDC token for), so `gh pr checks` still failed `Resource not accessible by integration` and the review took the PR body's claim of a green gate at face value; the mention template lacked both. Both now name it twice, with the statuses-read measurement rule. A step fetches the base ref after the head-sha checkout so the reviewer's first diff resolves instead of burning turns on refused fetches; the prompt says what to do when the diff exceeds the turn cap — review the authored set, post the summary first, name what was not read. The knowledge-backend ask-gate matcher covers the live Notion tool set (upload-skill, spawn-session, send-message-to-session, stop-session beside the six verbs), dated; the rule paragraph names the set once. Closes #58 addendum items 11 and 12. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… dict (#58 smaller item 6) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…d objects, matching the loader's depth The check read only each top-level key's immediate value; the loader's fatal diagnostic reads a matcher or a non-empty hooks at depth <= 3 (D30), so a stanza wrapped one level deeper voided the file with the block green. The scan is now recursive under every non-hooks key. Red on a nested stanza, on a flat one and on a depth-3 matcher; silent on an empty hooks array, a string value and the clean tree (review sweep, silent-failure dimension). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…the three carry every header line § Hook authoring says the three hooks authored with it carry every line; with Depends: added to the shape this harvest, only the detector did. Each new line restates what the hook's own fail-open branches already print (review sweep, comment-accuracy dimension). The earlier six keep their unlabelled fail-open sentences under the section's bring-up-when-next-edited clause. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… contract admits, in both copies Task 10 (D35) widened the contract's title precondition and left the procedure restating three forms with a halt on anything else — one half of the pair instructing a stop on exactly the title the other half admits. The bundled template and its commands/ copy change together (review sweep, kit-conformance dimension). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…tions and what the positive arm can show As written, Step 8's recipe tripped the kit sub-block's registry-naming check before the arm and expected a green project sub-block a copied kit tree cannot reach. Rewritten from a live run: name the hook in the mutation table first, read the positive arm as the message's absence, and add the double-registration direction (review sweep, test-coverage dimension). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…rade path, and the lock-file arms The three ignore-driven prune rules, the staging-copy prune and the scratch-file degrade path had no fixture: each removed shipped green (measured — every mutation exits 0 with empty stderr on a tree whose ignore rules name a directory literally called *). One first-stop probe against a tree that discriminates all of them, plus the degrade path under an unwritable TMPDIR; and the lock-file hook's named pubspec.lock arm, its *.lock fallback and a passing non-lock edit (review sweep, test-coverage dimension, two findings). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… with mixed retry outcomes One failure at index 0 cannot tell results[i] from results[k]; two can. The review-sweep scenario pins the retried finding to its own dimension and the still-failing one to failedDimensions; the finish-ab scenario pins the retried verdict to its own judge and the panel at three. Both harnesses red under a judged[k]/results[k] misindex (review sweep, test-coverage dimension). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
j4th
marked this pull request as ready for review
September 22, 2026 02:51
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #58
Closes #33
Summary
Harvest 4: every finding on #58 with a proven fix, landed in the kit so the next sync of any target is a merge against a kit that has already absorbed what applying it taught. The two syncs of
e92e9c4(you-are-hear #42 → PR #43; echosphere ECH-40 → PR #37) were mechanical where the kit intended; what they found afterwards was not lint: a hook-shaped object at the top level ofsettings.jsonmakes the harness discard the whole settings file (read from the 2.1.278 bundle: the diagnostic is fatal and the parser returns no settings — hooks,enabledMcpjsonServersandenabledPluginsall inert, silently, block green), every hook checked its dependency before draining stdin and three sites decided onprintf | grep -q(a >64 KiB commit body bypassed the main-branch deny outright), and the Stop-tier fork detector blocked a hosted review's own hand-off on the action's staging copy.Design:
docs/superpowers/specs/2026-09-21-cascade-kit-harvest-4-design.md(D30–D40, clusters H1–H7). Plan:docs/superpowers/plans/2026-09-21-harvest-4-applied-defects.md. One commit per task; the verification block green after every commit through its new runner.What lands, by cluster
run-verification-block.shwith two fail-loud rails (empty extraction is red; exit 0 without the done sentinel is red), the advisory-exemplar arm kit-tree-only with a project-sideADVISORY_WIREDdeclaration, the.mcp.json.exampleoperand guarded, the launch-root dry-runs keep the hook's stderr, and the kit's own CI (verify.yml, no path filter) runs the block on every PR._example_PostToolUse_*objects deleted; the registration stanza lives in each advisory hook'sRegister:header; the registry comment names the invariant and both memory scopes; § Hook authoring states it with its evidence; the block asserts no top-level key besideshooksholds a hook-shaped object — flat or nested, since the loader reads amatcheror a non-emptyhooksat depth ≤ 3.Depends:in the header shape, carried by all three hooks authored with the section; drain-first in every hook and here-strings at the three decision sites;hook-contract-fixture.sh(two structural checks over every hook plus over-buffer probes on the main-branch deny, the PR-state ask and the detector's second stop), run by the block.find's stderr behind a writability probe,./.claude-prpruned unconditionally, a tooling path named as not-a-fork, the residual in the header; § .gitignore anchoring names/.claude-pr/; a first-stop fixture probe on a tree that discriminates every prune rule, the staging-copy prune and the degrade path.agent-cost.pyper-tier cache reads (0.025× on the top tier) with new fixture rows, and its totals summed without the throwaway dict;review-sweep.jsboundary-safe hint match,.catchon the roster read, index-list retry reindex;finish-ab.jsdistinct arm labels,hallucinations ?? []at both sites, effort read once; both stub harnesses stop swallowing their own exceptions; nine new harness scenarios, two of them the mixed-outcome retry case that tellsifromk./finishStep 1 admits[<slug>:meta]in the contract and in the procedure pair;adr-newwrites the index row in the index's own form, states no count, definesPromotes:; the ADR reviewer cites by the register's id form; the duplicated citation, the marker spelling, the pre-flight Quick-reference row, the stamped-state callouts, thecwddisagreement named in the guard header,pubspec.lockand a*.lockfallback arm (both now fixture-probed, fc8237a); the Kit commit row and § Syncing the kit.checks: readtwice in both review-workflow templates, the base ref fetched after the head-sha checkout, an explicit degrade clause for a diff past the turn cap; the knowledge-backend matcher widened to the live tool set, dated.Review gate
/simplify— not run: kit content (bash, markdown, small JS/Python); the sweep's code-review and comment-accuracy dimensions cover the same ground on this diff.pr-review-toolkit:review-pr— not run as a skill: the kit is reviewed by its own dogfooded sweep (below), which dispatches the same dimension set as ad-hoc agents.Six sonnet finders (code-review, silent-failure, comment-accuracy, test-coverage, kit-conformance, port-fidelity) at effort medium with a high-effort retry; opus verifiers at high, refute-by-default; ten deduplicated findings, eight verified, two returned unverified by the bound.
Triage
Confirmed → Apply (5 of 5), each its own commit with the block green after it:
cbk-conventions-reference.md:621— the hook-shape invariant read only depth 1; D30 states depth ≤ 3. Recursive scan (d5eba3a); red on a nested stanza, a flat one and a depth-3matcher; silent on an emptyhooksarray, a string value and the clean tree.cbk-conventions-reference.md:396—Depends:joined the header shape but only the detector carried it, contradicting "the three hooks authored with this section carry every line". The two other 2026-09-06 hooks get the line (b7ca5a0); each restates what its fail-open branches already print. Surfaced, not applied: the six earlier hooks keep their unlabelled fail-open sentences under the section's bring-up-when-next-edited clause; whether this harvest's drain-move edit counts as that edit is the operator's call (the verifier read it as a documentation expansion).plans/…harvest-4…md:211— the ADVISORY_WIRED mutation recipe tripped an earlier kit check and expected a green project sub-block a kit copy cannot reach. Rewritten from a live run with both preconditions and the double-registration direction (04a791e).detect-forked-agent-memory.sh:89— the three prune rules, the staging-copy prune and the degrade path had no fixture; every one removed shipped green. One first-stop probe on a tree with a directory literally named*discriminates all of them (fc8237a); measured red under each of five mutations.finish-procedure.md:33(both copies) — the procedure restated three title forms with a halt on anything else while the contract admits[<slug>:meta]. Both copies widened, pair byte-parallel (c2745e3).Unverified (the verify bound) → Apply on the caller's own reproduction (2 of 2):
protect-lock-files.sh:71— thepubspec.lockarm and the*.lockfallback had no automated probe. Three probes in the fixture (fc8237a); red whenpubspec.lockleaves the named list and when the fallback arm is renamed.review-sweep-accounting.mjs:184— the reindex was exercised with one failure at index 0, wherei = k. Two-failure mixed-outcome scenarios in both harnesses (86b58d7); the review-sweep one is red underresults[k]. finish-ab's existing single-failure scenario already sat at index 1 and caughtjudged[k]on its own; the new one adds the mixed case.Refuted → Reject (3 of 3):
Depends:is neither enforced nor applied to seven hooks" — the section states, in a line this harvest did not touch, thatTier:is the one block-asserted line and adoption is incremental; the narrow self-contradiction is item 2._comment_hooksoverclaims the header contract" — the comment delegates the shape to § Hook authoring and never mentionsDepends:.One process note: the silent-failure finder mutated the kit's
.claude/settings.jsonin place for its probe and restored it (the tree was clean at triage); its verifier worked on a copy. The sweep's finder prompts do not say "probe on a copy"; worth a line in the next harness pass.Verification
ADVISORY_WIREDarm red when undeclared, passing when declared, red when double-registered (synthetic target, recipe in the plan); the hook-shape invariant red on an injected object, flat and nested; the over-buffer commit-body probe exit 0 before the here-string swap and exit 2 after; the fixture's two structural checks red on a removed drain and a re-introduced pipe; the detector probe red under each prune rule removed, the staging-copy prune removed and the degrade path exiting clean; the lock-file probes red under a droppedpubspec.lockarm and a renamed fallback;agent-costred at $11.00 with the per-tier map emptied; review-sweep red on the reverted boundary match, on the dropped.catchand on aresults[k]misindex; finish-ab red on the dropped label check, crashing on the droppedhallucinationsguard, red on ajudged[k]misindex.docs/adr/; everySKILL.mdunder 500 lines; no_example_key insettings.json; sanitization grep clean (no target-project identifier; the two public run names only beside their issue citations).--max-turns.🤖 Generated with Claude Code