Skip to content

fix(effectors): the panel's residue gets owners — arming lever, ratchet tooth, declared gap - #1738

Merged
4444J99 merged 1 commit into
mainfrom
fix/outbound-arming-lever
Jul 31, 2026
Merged

fix(effectors): the panel's residue gets owners — arming lever, ratchet tooth, declared gap#1738
4444J99 merged 1 commit into
mainfrom
fix/outbound-arming-lever

Conversation

@4444J99

@4444J99 4444J99 commented Jul 31, 2026

Copy link
Copy Markdown
Owner

Closeout of the OUTBOUND-EFFECTORS panel (#1727, #1729, #1735). Three residue items, each landing
in a git-tracked owner rather than being recited at the operator.


1. The arming atom was unfiled

The gate ships built-and-tested but unarmed, because .claude/settings.json is the
self-modification boundary. That is a his-hand atom, and it existed only in
docs/runbooks/outbound-preflight-arming.md and in session context.

L-OUTBOUND-PREFLIGHT-ARM now sits in his-hand-levers.json with the exact paste, its verify
commands, and issue #1736.

The interesting part: scripts/no-tasks-on-me.sh was exiting 0 the entire time it was
missing. That predicate proves every lever in the registry is owned and traceable — it
structurally cannot see an atom nobody filed. A green registry predicate is not evidence the
registry is complete. Which is this panel's own doctrine ("the artifact describes reality; go query
reality") applied to the panel. The naming series made the gap visible where the predicate could
not: L-FABLE-GUARD-ARM, L-CLOSEOUT-OBSERVE-ARM, L-GITVS-DEMOTE-ARM all exist for exactly this
class, and mine was absent from it.

2. SMTP_MODULES gains aiosmtplib — before anything imports it

A ratchet only works if the tooth is cut before the load arrives. Adding the name the day someone
reaches for it means class C is silent for exactly the commit that opens the hole. aiosmtplib is a
drop-in async smtplib and would have imported cleanly past a two-name allowlist.

3. The MTA/CLI transport gap is now declared, and deliberately not guessed shut

sendmail, msmtp, mutt, curl smtp[s]:// match nothing in mail.send.

Measured, not assumed: a grep of the whole estate finds zero occurrences of any of them.
Ratchet gap, not a live hole — nothing is escaping through it today.

It stays open because a match: regex is evaluated against every command an agent runs, and the
naive form is actively harmful:

\bsendmail\b   also matches   grep -rn sendmail .

Fail-closed inside the match, no extractable recipient → DENIED. A gate that refuses to let you
read about email is the noisy-gate failure the class-C docstring warns about, one step from being
reclassified as advisory. Closing it needs separator-anchored patterns plus fixtures proving the
read forms still pass — the test is the deliverable, the regex is the easy half. Owner: #1737.


The asymmetry between 2 and 3 is the actual finding. An AST import check can be widened ahead of
first use for free — no false-positive surface. A command regex cannot. Same intent, opposite safe
direction, and conflating them is how a gate becomes advisory.

#1737 also owns the two remaining /verify observations: the summary line reports baseline
length rather than the count that reproduces, and --update cannot distinguish recording a fix
from silencing a new sender.

Verification

Scoped push gate, all 7 implicated gates PASS. Baseline unchanged at 24 — the aiosmtplib
addition matches nothing today, which is the point.

  syntax-changed              PASS
  diff-hygiene                PASS
  direct-main-writer-contract PASS   32 classified surfaces, no unclassified write seam
  check-params                PASS   812 declared, no new hardcodes
  check-runner-coverage       PASS   no new findings (2 baselined)
  check-root-manifest         PASS   64 sanctioned, 0 grandfathered fat
  check-effectors             PASS   effectors: no new findings (24 baselined)
Scoped verification passed

bash scripts/tests/outbound-preflight-guard.test.sh   → all checks passed (hermetic, no network)
bash scripts/no-tasks-on-me.sh                        → nothing hangs on me (67 levers, 0 dangling)
python3 scripts/credential-wall.py --check            → all 27 secret atoms registered

Not website-sensitive (no deploy-trigger path).

🤖 Generated with Claude Code

https://claude.ai/code/session_01WMdtji1ydxXmsyARdvmCkd

…et tooth, declared gap

Three closeout items, all residue of the OUTBOUND-EFFECTORS panel itself
(#1727, #1729, #1735). None of them is recited at the operator: each lands in
a git-tracked owner.

1. THE ARMING ATOM WAS UNFILED. The gate ships built-and-tested but unarmed,
   because .claude/settings.json is the self-modification boundary. That is a
   his-hand atom and it existed only in a runbook and in session context — so
   L-OUTBOUND-PREFLIGHT-ARM now sits in his-hand-levers.json with its exact
   paste, its verify commands, and issue #1736. Note that no-tasks-on-me.sh was
   exiting 0 the whole time it was missing: that predicate proves every lever IN
   the registry is owned and traceable, and structurally cannot see an atom
   nobody filed. A green registry predicate is not evidence the registry is
   complete — which is this panel's own doctrine, applied to the panel.

2. SMTP_MODULES gains aiosmtplib, before anything imports it. A ratchet only
   works if the tooth is cut before the load arrives; adding the name the day
   someone reaches for it means class C is silent for exactly the commit that
   opens the hole. An AST import check has no false-positive surface, so a name
   nothing imports costs nothing.

3. THE MTA/CLI TRANSPORT GAP IS NOW DECLARED, NOT SILENT — and deliberately not
   guessed shut. sendmail/msmtp/mutt/curl smtp:// match nothing in mail.send.
   Measured, not assumed: a grep of the whole estate finds ZERO occurrences of
   any of them, so this is a ratchet gap and nothing is escaping today. It stays
   open because a `match:` regex is evaluated against EVERY command an agent
   runs, and the naive form is actively harmful — `\bsendmail\b` also matches
   `grep -rn sendmail .`, which, fail-closed inside the match with no extractable
   recipient, would be DENIED. A gate that refuses to let you read about email is
   the noisy-gate failure the class-C docstring warns about. Closing it needs
   separator-anchored patterns plus fixtures proving the read forms still pass;
   the test is the deliverable, the regex is the easy half. Owner: #1737.

The asymmetry between 2 and 3 is the actual finding: an AST check can be widened
ahead of first use for free, a command regex cannot. Same intent, opposite safe
direction, and conflating them is how a gate becomes advisory.

#1737 also owns the two remaining /verify observations: the summary line reports
baseline LENGTH rather than the count that reproduces, and `--update` cannot
distinguish recording a fix from silencing a new sender.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WMdtji1ydxXmsyARdvmCkd
@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@4444J99, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 48 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: ce006591-52fe-4621-bd7a-f4e328838902

📥 Commits

Reviewing files that changed from the base of the PR and between 5345967 and da0e3b5.

📒 Files selected for processing (3)
  • his-hand-levers.json
  • institutio/governance/outbound-effectors.yaml
  • scripts/check-effectors.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

Multi-agent review roll call
@codex review

(CodeRabbit and Claude review automatically. Reviewers: post substantive findings only. Authors/agents: address every thread, push fixes to this branch, reply and resolve, then re-request review.)

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@4444J99
4444J99 added this pull request to the merge queue Jul 31, 2026
Merged via the queue into main with commit 28ef280 Jul 31, 2026
14 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: da0e3b5d76

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread his-hand-levers.json
"steps": [
"Paste the snippet from docs/runbooks/outbound-preflight-arming.md § The one edit",
"bash scripts/tests/outbound-preflight-guard.test.sh # expect 13/13, hermetic, no network",
"Done when a matched command with no receipt is refused: printf '%s' '{\"tool_name\":\"Bash\",\"tool_input\":{\"command\":\"scripts/mail-send --to someone@example.com\"}}' | python3 scripts/hooks/outbound-preflight-guard.py # must print permissionDecision: deny"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Verify that the outbound hook was actually armed

When the operator follows this lever, the final command invokes outbound-preflight-guard.py directly, so it produces the same denial even if .claude/settings.json was never edited. The lever can therefore satisfy its stated “Done when” predicate and be closed while ordinary Claude Bash commands still bypass the guard, leaving the outbound safety gate unenforced; make the predicate inspect the installed hook entry or exercise hook dispatch through the configured runtime.

AGENTS.md reference: AGENTS.md:L191-L194

Useful? React with 👍 / 👎.

Comment thread his-hand-levers.json
"unlocks": "the gate goes from built-and-tested to ENFORCING. An outbound email or public GitHub comment with no fresh digest-bound receipt is DENIED, not reminded about. This is the consequence half of the 2026-07-31 escape: ten prose rules were written for the act-on-an-artifact-instead-of-reality class and all ten were followed by a recurrence, because a checklist the model self-certifies is a mirror. This one is os.stat() plus a SHA-256 compare — not a question the model gets to answer about itself.",
"source_task": "closeout 2026-07-31 (OUTBOUND-EFFECTORS, the fifth VIGILIA panel — PRs #1727, #1729, #1735)",
"steps": [
"Paste the snippet from docs/runbooks/outbound-preflight-arming.md § The one edit",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Persist the armed hook in git

When the operator performs this paste, .claude/settings.json—a tracked file—is left as an uncommitted local edit, but the lever contains no subsequent commit/PR/merge step and even says the surrounding merge work is already done. The guard will therefore remain absent from fresh or isolated worktrees created from main, allowing their outbound Bash actions to bypass it, and the activation can be lost with the local checkout; require a durable commit and remote receipt before closing the lever.

AGENTS.md reference: AGENTS.md:L160-L165

Useful? React with 👍 / 👎.

@4444J99
4444J99 deleted the fix/outbound-arming-lever branch August 5, 2026 13:54
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