Skip to content

fix: hooks audit (receipts, gate, APEX, lessons, release gate) — 0.1.114 - #125

Merged
brunoazoulay merged 9 commits into
mainfrom
fix/hooks-audit-2026-11-06
Nov 10, 2026
Merged

brunoazoulay merged 9 commits into
mainfrom
fix/hooks-audit-2026-11-06

Conversation

@brunoazoulay

Copy link
Copy Markdown
Collaborator

Summary

Hooks audit fixes, released as 0.1.114 (version bump + CHANGELOG in a separate commit).

  • A1 receipts (Claude Code): capture Bash verification receipts from real Claude Code PostToolUse payloads, which carry no exit_code (exit 0 implied only for a single simple, direct, foreground runner command; stdout counts still decide pass/fail).
  • A1 gate: verification receipt gate keyed on the project dir (CLAUDE_PROJECT_DIR wins over cwd), edit-time aware (verifiedAt from duration_ms, per-file edit stamps, scratchpad excluded from the receipt gate only).
  • A1 xcodebuild: xcodebuild test recognised as a verification receipt (action-position match, Executed N tests, with M failures, ** TEST FAILED ** floors to failure).
  • A2-A4 APEX: project type detected from the project root (TypeScript → typescript-expert); no instructions for absent tools (no TaskUpdate, auto-commit, fake Task feat(tracking): session-state layer + freshnessGate #1, "create task.json yourself"); task completion reminds of a WIP commit via the commit agent.
  • A5 lessons: newest lessons injected whole, cut per whole bullet.
  • F1 release gate: merge/tag/release commands ask for confirmation when the sniper or challenger report is missing or older than the last code edit.

Test plan

  • Full suite: 3487 pass / 0 fail / 1 skip, 0 pass→fail vs the frozen baseline
  • bunx tsc --noEmit clean
  • sniper pass, challenger CONFIRMED
  • CI green

Intentionally changed tests

  • apex-instruction-preamble: 2 assertions
  • inject-context
  • test/fixtures/inform-matrix.golden.json: 4 cells
  • lesson-compact: inputs re-dated to the new newest-first order, expectations unchanged

Known

  • ~27 duplicate receipts per Bash call from the plugin hook fan-out; per-tool_use_id dedupe parked, out of scope.

Not verified in real conditions

  • SubagentStart / SubagentStop paths.
  • Matcher "Task" for the Agent tool.

Breaking changes

None

- Match `test` only in xcodebuild's action position, so `build`,
  `-showBuildSettings` and `build-for-testing` are never taken as a test run.
- Read counts from `Executed N tests, with M failures`.
- `** TEST FAILED **` floors the result to a failure even without counts.
- Add a ReDoS regression test for the action-position regex.
- Sort lessons by their [timestamp], newest first; the oldest are the
  ones compressed.
- Fit the injection per whole bullet inside the lessons path only
  (new fit-lessons.ts); capFragment is untouched.
- lesson-compact.test.ts: inputs re-dated to the new order,
  expectations unchanged.
…aware

- verifiedAt derived from the run's duration_ms: a code file edited after the
  newest green run started is unverified; absent duration_ms keeps the 85fa53a
  TTL rule.
- Per-file edit stamps (editedAt) in session changes; session scratchpad files
  are excluded only from the receipt gate, version-bump modules never stamped.
- One project-dir resolver (CLAUDE_PROJECT_DIR wins over cwd) for every
  state-dir site via projectStateDir.
…or absent tools

- CLAUDE.md project type detected from the project root; a TypeScript project
  maps to the typescript type and typescript-expert, with dependency-key
  parsing of package.json.
- splitTarget for APEX target steps.
- No more instructions for absent tools: no TaskUpdate, no auto-commit, no
  fake Task #1, no "create task.json yourself".
- Task completion now reminds of a WIP commit via the commit agent.
…llenger reports

- Detect release commands (merge, tag, release) outside data heredocs.
- Record sniper/challenger SubagentStop reports per project; a release command
  asks for confirmation when either report is missing or older than the last
  code edit.
Real Claude Code PostToolUse Bash payloads carry no exit_code, so no
receipt was ever captured live (85fa53a too) and the receipt gate could
never be satisfied.

Exit 0 is now implied ONLY for host claude-code + PostToolUse +
interrupted===false + not background (no backgroundTaskId,
run_in_background absent/false) + a single simple command (no
pipe/list/subshell/redirect except bounded fd-dup) + a DIRECT runner
(no npm/pnpm/yarn script launcher; pnpm only via `exec` with
unambiguous options). Counts parsed from stdout still decide pass/fail.
Everything else keeps the 85fa53a behaviour (no receipt).

Known cost: `bun test | tail -5`, `pnpm -w|-F x|--parallel exec ...`
stay receipt-less as before.
@brunoazoulay
brunoazoulay merged commit 6c1041f into main Nov 10, 2026
1 check passed
@brunoazoulay
brunoazoulay deleted the fix/hooks-audit-2026-11-06 branch November 10, 2026 02:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant