Skip to content

feat(hook): opt-in review gate wiring for hook stop (Y-18 Slice 3)#148

Merged
takashi-matsuyama merged 1 commit into
mainfrom
feat/review-gate-enforcement
Jun 30, 2026
Merged

feat(hook): opt-in review gate wiring for hook stop (Y-18 Slice 3)#148
takashi-matsuyama merged 1 commit into
mainfrom
feat/review-gate-enforcement

Conversation

@takashi-matsuyama

Copy link
Copy Markdown
Member

What

Slice 3 (final) of basou review enforcement ([Y-18]): the CLI wiring that renders the review-gate verdict computed in Slice 2. Slices 1 (review record verb + review_recorded event, #146) and 2 (review-gate detection in evaluateStopHook, #147) already merged.

This makes the gate user-facing for the first time — as an opt-in, advisory-first tier.

Behavior

  • basou hook stop --require-review — off by default. When set, a session that shipped substantive code (git push / git merge / gh pr create|merge after enough file edits) without recording a review (basou review record) gets a reminder, composed into the same Stop envelope as the capture reminder.
  • A Stop hook emits one response, so --block is a single switch governing the whole envelope's blocking-ness (advisory by default; --block makes it decision:block).
  • Byte-identical default: without --require-review the review verdict is ignored entirely, so capture-only output is unchanged from main.
  • Independent tiers: a captured-but-unreviewed shipped session still emits the review reminder on its own.
  • core buildStopHookCommand gains requireReview (--require-review, ordered after --block, before --min-edits; existing registered commands round-trip unchanged).
  • hook install --require-review registers that form; hook status reports active gates (capture vs capture + review) via a new describeHookMode.

Scope / staging

Advisory-first is intentional (the Y-18 staged release: verb → detection → enforcement). --require-review defaults to advisory; blocking requires --block on top. Detection patterns landed in Slice 2 and are unchanged here.

Adversarial review (codex, review-only, FIXED CONSTRAINTS injected)

Clean on all design/correctness dimensions: byte-identity (verified the parts[] composition reduces to the old capture-only path when the flag is absent), envelope composition (capture-only / review-only / both), loop guard, flag ordering / byte-stability, and install/uninstall/status. Nothing blocked. It raised 2 test-gap findings (no production change) — the review-only emission path (MEDIUM) and the capture+review → capture downgrade (LOW) — both are covered by tests added in this PR.

Verification

  • build / typecheck / lint (0 errors) — green
  • tests: core 1261 + sdk 18 + cli 905 (hook suite 42, incl. the 2 gap tests) — all pass
  • coverage ratchet gate — pass (exit 0)
  • built-CLI smoke: default (capture-only, no review) / --require-review (composed) / --require-review --block (decision:block) / install --require-review + status (reports capture + review) / downgrade — all OK

🤖 Generated with Claude Code

Wire the review-gate verdict (computed in Slice 2, #147) into the
`basou hook stop` CLI as an opt-in tier. Slices 1 (review record verb,
#146) and 2 (review-gate detection, #147) already merged.

- `hook stop --require-review`: off by default. When set, a session that
  shipped substantive code (git push / merge / gh pr create|merge) without
  recording a review composes a review reminder into the SAME Stop envelope
  as the capture reminder. A Stop hook emits one response, so --block is a
  single switch governing the whole envelope's blocking-ness; advisory by
  default. Without --require-review the review verdict is ignored entirely,
  so the capture-only output stays byte-identical.
- core buildStopHookCommand gains requireReview (--require-review, ordered
  after --block, before --min-edits; existing commands round-trip unchanged).
- hook install --require-review registers that form; hook status reports the
  active gates (capture vs capture + review) via describeHookMode.

The capture and review tiers are independent: a captured-but-unreviewed
shipped session still emits the review reminder on its own. Advisory-first
staging is intentional; blocking requires --block on top.

Adversarial review (codex, review-only): clean on byte-identity, envelope
composition, loop guard, flag ordering, and install/status; the two
test-gap findings it raised (review-only emission path; capture+review ->
capture downgrade) are both covered here. Nothing was blocked.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@takashi-matsuyama takashi-matsuyama merged commit c303a45 into main Jun 30, 2026
7 checks passed
@takashi-matsuyama takashi-matsuyama deleted the feat/review-gate-enforcement branch June 30, 2026 10:14
takashi-matsuyama added a commit that referenced this pull request Jun 30, 2026
Bump packages/{basou,core,cli,sdk} to 0.30.0 and finalize the CHANGELOG
section. Bundles two already-merged themes:

- Codex adapter (#149/#150): the Codex context channel (basou refresh
  renders orientation into ~/.codex/AGENTS.md) and the basou run codex
  launcher (pre-spawn re-render + shell_environment_policy.inherit=all +
  codex-adapter source kind).
- Y-18 review enforcement (#146/#147/#148): basou review record, the
  review-gate verdict in evaluateStopHook, and the opt-in
  hook stop --require-review gate.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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