Canonical invariant 5 states a mechanism where it means a purpose — restate it (blocked on #455) #458

Closed
opened 2026-09-10 13:02:52 +02:00 by ltms · 2 comments
Owner

What is wrong

Invariant 5 of the canonical CLAUDE.md block says:

Never drive the terminal multiplexer directly (no herdr CLI, no socket). The bridge owns
policy; the multiplexer owns PTYs. Going around the bridge bypasses every rule above.

The rule is written as a ban on a mechanism: do not touch the herdr CLI, do not open the
socket. What the rule is actually for is a ban on a control plane: do not move a fleet session,
a pane or a peer by any route that skips the bridge's policy checks.

Those two readings pick out the same actions in every project except one — this one. In this repo
the multiplexer is the subject under test. AgentControlContractTest, HerdrContractTest,
PaneLocatorContractTest and WorkspacePlacementContractTest all open the herdr socket on
purpose, because a contract test against a fake proves nothing (see #454, and fleetd #449 where
the fake and the real herdr disagreed for weeks with a green suite).

So a worker assigned to herdr code reads invariant 5 and finds that the only action which can
finish its task is banned. #455 covers that, and #455 is the fix that ships first.

The placement test that finds this class of bug

fleet01 gave the reusable test, and it is worth writing down:

Does the rule's violation set differ by project?

  • If the same action is a violation everywhere, the rule belongs in the canonical block.
  • If the action is a violation in most projects and required in one, the rule is stated at the
    wrong level. Restate it by purpose, and the difference disappears.

A rule stated as a mechanism becomes unsatisfiable wherever the mechanism is the subject. A
rule stated as a purpose stays correct in both places.

Scope

Restate invariant 5 so it bans the control plane, not the tool. Something in this direction — the
exact words are the reviewer's call, not a fixed requirement:

Never move a fleet session, pane or peer except through the bridge. The bridge owns policy;
the multiplexer owns PTYs. Any route that changes fleet state without passing the bridge's
checks bypasses every rule above — the herdr CLI and its socket are the usual such route.

Then:

  1. Update the same block in wiki/7-Use-Cases.md so the two stay byte-identical. CLAUDE.md
    carries the check script for this; run it.
  2. Update every other project that carries the block.
  3. Re-read #455's addendum afterwards. If the restated invariant makes that addendum redundant,
    say so in #455 rather than deleting it silently.

Why this is a separate ticket, and not part of #455

fleet01's sequencing, and I agree with it:

Bundling them means the risky one rides in on the safe one's justification.

#455 is an addendum in this repo only. It cannot break another project. This ticket edits the
canonical block, which every project that mounts the bridge obeys, so it needs its own review
and its own propagation pass. Do not start this until #455 has shipped.

Acceptance criteria

  • Invariant 5 names no tool as the thing that is banned. It may still name the herdr CLI and
    socket as examples.
  • A worker assigned to herdr contract code can name one legal action that finishes its task.
    (That is the pre-send check: if you cannot name one, the rule is still unsatisfiable.)
  • The CLAUDE.md / wiki/7-Use-Cases.md sync script in CLAUDE.md prints in sync: True.
  • The ticket says which other projects were updated, or that none carry the block.
## What is wrong Invariant 5 of the canonical `CLAUDE.md` block says: > **Never drive the terminal multiplexer directly** (no `herdr` CLI, no socket). The bridge owns > policy; the multiplexer owns PTYs. Going around the bridge bypasses every rule above. The rule is written as a **ban on a mechanism**: do not touch the `herdr` CLI, do not open the socket. What the rule is actually for is a **ban on a control plane**: do not move a fleet session, a pane or a peer by any route that skips the bridge's policy checks. Those two readings pick out the same actions in every project except one — this one. In this repo the multiplexer *is* the subject under test. `AgentControlContractTest`, `HerdrContractTest`, `PaneLocatorContractTest` and `WorkspacePlacementContractTest` all open the herdr socket on purpose, because a contract test against a fake proves nothing (see #454, and fleetd #449 where the fake and the real herdr disagreed for weeks with a green suite). So a worker assigned to herdr code reads invariant 5 and finds that the only action which can finish its task is banned. #455 covers that, and #455 is the fix that ships first. ## The placement test that finds this class of bug fleet01 gave the reusable test, and it is worth writing down: **Does the rule's violation set differ by project?** - If the same action is a violation everywhere, the rule belongs in the canonical block. - If the action is a violation in most projects and required in one, the rule is stated at the wrong level. Restate it by purpose, and the difference disappears. A rule stated as a **mechanism** becomes unsatisfiable wherever the mechanism is the subject. A rule stated as a **purpose** stays correct in both places. ## Scope Restate invariant 5 so it bans the control plane, not the tool. Something in this direction — the exact words are the reviewer's call, not a fixed requirement: > **Never move a fleet session, pane or peer except through the bridge.** The bridge owns policy; > the multiplexer owns PTYs. Any route that changes fleet state without passing the bridge's > checks bypasses every rule above — the `herdr` CLI and its socket are the usual such route. Then: 1. Update the same block in `wiki/7-Use-Cases.md` so the two stay byte-identical. `CLAUDE.md` carries the check script for this; run it. 2. Update every other project that carries the block. 3. Re-read #455's addendum afterwards. If the restated invariant makes that addendum redundant, say so in #455 rather than deleting it silently. ## Why this is a separate ticket, and not part of #455 fleet01's sequencing, and I agree with it: > Bundling them means the risky one rides in on the safe one's justification. #455 is an addendum in this repo only. It cannot break another project. This ticket edits the canonical block, which every project that mounts the bridge obeys, so it needs its own review and its own propagation pass. **Do not start this until #455 has shipped.** ## Acceptance criteria - Invariant 5 names no tool as the thing that is banned. It may still name the `herdr` CLI and socket as examples. - A worker assigned to herdr contract code can name one legal action that finishes its task. (That is the pre-send check: if you cannot name one, the rule is still unsatisfiable.) - The `CLAUDE.md` / `wiki/7-Use-Cases.md` sync script in `CLAUDE.md` prints `in sync: True`. - The ticket says which other projects were updated, or that none carry the block.
Author
Owner

Unblocked: #455 shipped in 9d1306d, and its lead-only note landed in 5f1b260.

Before delegating this I have to correct my own acceptance criteria. Three of the four cannot be satisfied by a worker, and #455 is exactly where I learned that — my brief there required the sync script and the worker could not run it. Measured in three live worker worktrees: git submodule status prints a leading - and wiki/ holds 0 entries, so the script dies with FileNotFoundError: wiki/7-Use-Cases.md. The primary's own clone prints a leading + and the file is there.

So the split is:

The worker's unit — restate invariant 5 in CLAUDE.md only.

  • Invariant 5 names no tool as the thing banned. It may name the herdr CLI and socket as examples.
  • The restatement stays inside the canonical block and changes nothing else in it. Byte count of the block before and after, and the diff, go in the report.
  • A worker assigned to herdr contract code can name one legal action that finishes its task. The report must name that action explicitly — that is the check, and if it cannot be named the rule is still unsatisfiable.
  • The report must say whether #455's addendum is now redundant. It must not delete it.

Mine, not the worker's:

  • wiki/7-Use-Cases.md. It is a submodule with its own remote, uninitialized in a worktree.
  • The sync script printing in sync: True. Only runnable in the main clone. I run it before merging.
  • Every other project that carries the block. Outside the worktree, and the implementer skill refuses paths outside it.

A brief that asks a worker for any of those three is asking it to invent a pass. Noted in CLAUDE.md's addendum in 5f1b260.

Unblocked: #455 shipped in `9d1306d`, and its lead-only note landed in `5f1b260`. Before delegating this I have to correct my own acceptance criteria. Three of the four cannot be satisfied by a worker, and #455 is exactly where I learned that — my brief there required the sync script and the worker could not run it. Measured in three live worker worktrees: `git submodule status` prints a leading `-` and `wiki/` holds 0 entries, so the script dies with `FileNotFoundError: wiki/7-Use-Cases.md`. The primary's own clone prints a leading `+` and the file is there. So the split is: **The worker's unit — restate invariant 5 in `CLAUDE.md` only.** - Invariant 5 names no tool as the thing banned. It may name the `herdr` CLI and socket as examples. - The restatement stays inside the canonical block and changes nothing else in it. Byte count of the block before and after, and the diff, go in the report. - A worker assigned to herdr contract code can name one legal action that finishes its task. The report must name that action explicitly — that is the check, and if it cannot be named the rule is still unsatisfiable. - The report must say whether #455's addendum is now redundant. It must not delete it. **Mine, not the worker's:** - `wiki/7-Use-Cases.md`. It is a submodule with its own remote, uninitialized in a worktree. - The sync script printing `in sync: True`. Only runnable in the main clone. I run it before merging. - Every other project that carries the block. Outside the worktree, and the `implementer` skill refuses paths outside it. A brief that asks a worker for any of those three is asking it to invent a pass. Noted in `CLAUDE.md`'s addendum in `5f1b260`.
Author
Owner

Merged as eccd054 (PR #465). One file, one hunk.

Invariant 5 now reads:

  1. Never move a fleet session, pane or peer except through the bridge. The bridge owns policy; the multiplexer owns PTYs. Any route that changes fleet state without the bridge's checks bypasses every rule above — the herdr CLI and its socket are the usual example.

What I verified myself

Rebuilt the merge in my own worktree. Base f5e02fe, branch tip 29e7a06.

  • One hunk, one file. A line-by-line diff of the canonical block against origin/main shows exactly 5 changed lines, all of them invariant 5. Nothing else in the block moved.
  • The addendum is untouched. Herdr socket tests (measured 2026-09-10) and Only the lead can run that check each appear once on both sides.
  • Block size: origin/main 17467 chars / 17626 bytes; the merge 17557 chars / 17718 bytes. The worker's figures were bytes and were right. I am naming both units because len(str) in python counts characters and this block is full of em dashes — a mistake I have made before and want the record to be unambiguous about.
  • mvn -B clean test: Tests run: 1583, Failures: 0, Errors: 0, Skipped: 0, BUILD SUCCESS, rc=0.

The three things I reserved, because a worktree cannot do them

  • wiki/7-Use-Cases.md updated to match, in the wiki repo's own commit fa326b4.
  • The sync script run in this clone: in sync: True. Before the wiki edit it was False, as expected — so the check was actually reading both files and would have caught a mismatch.
  • Other projects carrying the block: none. Measured: 29 CLAUDE.md files under the operator's project roots (~/LTMS, ~/Sources, ~/Temporaries, ~/.claude). 18 carry the canonical heading, and 17 of those are this repo's own .bridged-worktrees/* checkouts, which inherit the file from git. The only real copy is LTMS/claude-bridge/CLAUDE.md, which is this file. So there is nothing to propagate to. LTMS/claude-teams has a CLAUDE.md but does not carry the block — that is the one to check first if the block is ever adopted elsewhere.

The worker's criterion-2 answer, which is the check that mattered

A worker assigned to AgentControlContractTest can open the herdr socket from inside that test, against a throwaway workspace the test creates and tears down. Under the new wording that is legal on its own terms — it moves no real fleet session, pane or peer — without needing the addendum's carve-out. Under the old wording ("no herdr CLI, no socket", full stop) the same action read as banned. That is the unsatisfiability this ticket existed to remove, and it is removed.

Criterion 4 — the addendum note stays

The worker's view, and mine after reading it: the restated invariant removes the unsatisfiability, which was the sharp problem, but the note still does two things the invariant cannot do on its own. It names the exact four files the carve-out covers, so a worker does not have to re-derive whether its test "really" moves fleet state. And it records why (fleetd #449, where a fake and the real herdr disagreed for weeks under a green suite), which is what makes the carve-out legible rather than merely asserted.

A rule that is satisfiable is not the same as a rule a worker can apply without re-deriving it. Recording this on #455 as well.

Thanks to the fleet01 lead for the placement test this ticket is built on: does the rule's violation set differ by project? It is now the thing to run on any canonical-block edit.

Merged as `eccd054` (PR #465). One file, one hunk. Invariant 5 now reads: > 5. **Never move a fleet session, pane or peer except through the bridge.** The bridge owns policy; the multiplexer owns PTYs. Any route that changes fleet state without the bridge's checks bypasses every rule above — the `herdr` CLI and its socket are the usual example. ## What I verified myself Rebuilt the merge in my own worktree. Base `f5e02fe`, branch tip `29e7a06`. - **One hunk, one file.** A line-by-line diff of the canonical block against `origin/main` shows exactly 5 changed lines, all of them invariant 5. Nothing else in the block moved. - **The addendum is untouched.** `Herdr socket tests (measured 2026-09-10)` and `Only the lead can run that check` each appear once on both sides. - **Block size:** `origin/main` 17467 chars / 17626 bytes; the merge 17557 chars / 17718 bytes. The worker's figures were bytes and were right. I am naming both units because `len(str)` in python counts characters and this block is full of em dashes — a mistake I have made before and want the record to be unambiguous about. - `mvn -B clean test`: `Tests run: 1583, Failures: 0, Errors: 0, Skipped: 0`, `BUILD SUCCESS`, rc=0. ## The three things I reserved, because a worktree cannot do them - **`wiki/7-Use-Cases.md` updated** to match, in the wiki repo's own commit `fa326b4`. - **The sync script run in this clone: `in sync: True`.** Before the wiki edit it was `False`, as expected — so the check was actually reading both files and would have caught a mismatch. - **Other projects carrying the block: none.** Measured: 29 `CLAUDE.md` files under the operator's project roots (`~/LTMS`, `~/Sources`, `~/Temporaries`, `~/.claude`). 18 carry the canonical heading, and 17 of those are this repo's own `.bridged-worktrees/*` checkouts, which inherit the file from git. The only real copy is `LTMS/claude-bridge/CLAUDE.md`, which is this file. So there is nothing to propagate to. `LTMS/claude-teams` has a `CLAUDE.md` but does not carry the block — that is the one to check first if the block is ever adopted elsewhere. ## The worker's criterion-2 answer, which is the check that mattered A worker assigned to `AgentControlContractTest` can open the herdr socket from inside that test, against a throwaway workspace the test creates and tears down. Under the new wording that is legal on its own terms — it moves no real fleet session, pane or peer — **without needing the addendum's carve-out**. Under the old wording ("no `herdr` CLI, no socket", full stop) the same action read as banned. That is the unsatisfiability this ticket existed to remove, and it is removed. ## Criterion 4 — the addendum note stays The worker's view, and mine after reading it: the restated invariant removes the unsatisfiability, which was the sharp problem, but the note still does two things the invariant cannot do on its own. It names the exact four files the carve-out covers, so a worker does not have to re-derive whether its test "really" moves fleet state. And it records why (fleetd #449, where a fake and the real herdr disagreed for weeks under a green suite), which is what makes the carve-out legible rather than merely asserted. **A rule that is satisfiable is not the same as a rule a worker can apply without re-deriving it.** Recording this on #455 as well. Thanks to the fleet01 lead for the placement test this ticket is built on: *does the rule's violation set differ by project?* It is now the thing to run on any canonical-block edit.
ltms closed this issue 2026-09-10 13:59:23 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: fleet/fleetd#458