Skip to content

feat(reviewer): C1 cross-family council for guardrail PRs (COUNCIL_VERDICT.md) - #469

Merged
ProtocolWarden merged 1 commit into
mainfrom
feat/c1-reviewer-council
Jul 14, 2026
Merged

feat(reviewer): C1 cross-family council for guardrail PRs (COUNCIL_VERDICT.md)#469
ProtocolWarden merged 1 commit into
mainfrom
feat/c1-reviewer-council

Conversation

@ProtocolWarden

Copy link
Copy Markdown
Owner

What

Council spec (docs/design/COUNCIL_VERDICT.md) Phase 2 / C1 — keyless change control for guardrail surfaces, the adjudicated-review substitute for the operator's signing key.

A PR whose diff touches any reviewer.council.guardrail_paths glob is adjudicated by a K=3 cross-family panel instead of the single self-review:

  • Members: claude/sonnet (correctness lens), claude/opus (security-capability lens), codex/gpt-5 (convergence-operational lens) — diversity from independent training + focus, not sampling noise.
  • Quorum: unanimous LGTM merges. Any CONCERN feeds the existing self-heal fix ladder unchanged. An unmet quorum (a family cooled) parks fail-closed, reusing the fix(reviewer): auto-expire backend-unavailable parks after cooldown #446 auto-resume path.
  • Record: state/council/<repo>-<pr>.json + one attributed PR comment; reviewer-verdict status set only on quorum.
  • Verdict is still code-computed per member (INJ boundary intact) — an injected diff can flip a re-checkable enum but cannot author the verdict.

guardrail_paths ships EMPTY ⇒ feature OFF (fail-open to today's single review) so this rollout PR can't deadlock on the gate it introduces. Populating the §G1 set is a deliberate follow-up PR (which then rides through the council itself).

How

  • Pure logic in verdict.py (aggregate_council, lens fragments, _COUNCIL_PANEL, last_json_object codex-stdout fallback) — covered by the tests/unit 85% gate. _run_council in main.py stays thin.
  • _run_direct_review generalized to _run_member_review(*, backend, model), kept as a byte-identical alias for the single path (same claude --model haiku -p --effort low argv; only the model varies per seat). Member argv mirrors worker_backend_probe._probe_command.
  • Per-member model-aware cooldown (_member_on_cooldown) — sonnet vs opus are both claude_code, so the backend-grained selector can't distinguish them.
  • Both single + council paths share a new _dispatch_verdict_outcome tail.

F14 mitigations (deadlock avoidance)

  • Park-cap: a council park outlasting max_council_park_hours escalates a distinct council_unavailable_capped reason to the operator instead of re-parking forever.
  • Degraded quorum: min_council_members lets the panel proceed with unanimity among available families.
  • Narrow self-fix exemption: only the reviewer's own review/ fix branches fall back to single review. Fleet goal/ PRs touching guardrails DO get the council — that is the control's primary threat (fleet quietly merges a guardrail change on a single LGTM). Widening this is an explicit operator trust-model decision, flagged in-code.

Doc

HARNESS_TRUST_HARDENING.md §0.1 no longer overclaims the council as live — it now states the engine shipped under C1 but guardrail_paths is empty so the gate isn't live yet.

Tests

166 reviewer tests (tests/test_pr_review_watcher.py, +16) incl. fork/unanimous-merge/concern-ladder/cooldown-park/per-family-dispatch/state+comment and all three F14 mitigations; 29 verdict.py unit tests. tests/unit full suite 8468 pass at 85.95% (gate 85%). ruff clean.

Follow-ups (not this PR)

  • Populate guardrail_paths with the §G1 set (the council's first live case).
  • Live-validate the codex member writes a schema-conformant verdict (the last_json_object stdout fallback de-risks this; mirrors open D1-pt2).
  • C3 (EVAL cross-family panel) reuses this plumbing.

Council spec Phase 2 (C1). Depends conceptually on C2 (ContextLifecycle #43, keyless launch-time anchor).

🤖 Generated with Claude Code

…RDICT.md)

A PR touching any reviewer.council.guardrail_paths glob is adjudicated by a K=3
cross-family panel (claude/sonnet + claude/opus + codex, distinct lenses) with
unanimous LGTM to merge; any CONCERN feeds the existing self-heal fix ladder and
an unmet quorum parks fail-closed (reusing #446 auto-resume). guardrail_paths
ships EMPTY (feature OFF, fail-open) so the rollout PR does not deadlock on its
own gate; populating it is a deliberate follow-up.

Pure logic (aggregate_council, lenses, codex-stdout fallback) in verdict.py;
_run_council thin in main.py. _run_direct_review generalized to
_run_member_review(*, backend, model), byte-identical for the single path.
Per-member model-aware cooldown; shared _dispatch_verdict_outcome tail; verdict
still code-computed per member (INJ boundary intact). F14: park-cap operator
escalation, degraded quorum, and a NARROW self-fix exemption (only review/ fix
branches — fleet goal/ guardrail PRs DO get the council). Doc truth-up in
HARNESS_TRUST_HARDENING. 166 reviewer + 29 verdict tests; tests/unit 85.95%.

Council spec COUNCIL_VERDICT.md Phase 2 (C1).

Co-Authored-By: Claude Opus 4.8 (1M context) <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