docs: lead decision 91, row 68 build log, pin and coder grant brief (#1561)

Decision 91 amends 89: the bus pins ~/.local/bin/claude through
MOSAIC_CLAUDE_BIN, so the package upgrade is no longer needed for the
first PM launch. The brief covers two Rocko rows: tests for row 68's
surviving mutants, and dropping the coder's dead task.reassign grant.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-11 16:47:15 -05:00
co-authored by Claude Opus 5.5
parent 4100fa68c0
commit 32aa572788
3 changed files with 145 additions and 0 deletions
+23
View File
@@ -1919,3 +1919,26 @@ which stay with him. Each item names who decided it and what happened.
reviewer who isn't assigned can't comment on the task through the
bus. If slice 1 acceptance needs that, it is a new verb or a
change to `task.update.assigned`, decided then.
91. **The bus pins the user's Claude Code binary; this amends 89
(2026-10-11).** Decision 89 left the bus on `/usr/bin/claude` and made
the fix Jason's package upgrade. Row 68 (#1561, 11dae0c7) took the
other path: `bus-service.sh install --claude PATH` writes
`Environment=MOSAIC_CLAUDE_BIN=PATH` into the unit, and the claude
adapter runs that binary when it is set.
- Installed 2026-10-11T21:42:39Z with
`--claude /home/jwoltje/.local/bin/claude` (a symlink, now to
2.1.296). The unit's only change was that line and its comments;
`daemon-reload` only, no restart.
- Probe at 21:43:03Z, the adapter under `env -i` with the unit's PATH
and claude-opus-5-5: the pinned binary answered "OK", rc 0;
`/usr/bin/claude` still gets "2.1.280 or newer is required", rc 1.
- Jason's sudo upgrade is no longer needed for the first PM launch.
The pacman package stays installed and untouched. The running bus
(PID 1242258, up since 13:19:28 CDT) keeps its old environment until
Mos's watched Q18 `--pm` restart; Sage doesn't restart it.
- The tradeoff: the symlink follows the user's auto-updates, so a bad
Claude Code release reaches the bus at its next restart without a
review. Decision 89 valued the root-owned package for that reason.
No version floor check runs at start; one would catch a
downgrade, not a bad upgrade. Re-pinning to a versioned path is one
`install --claude` away if a release breaks it.
@@ -0,0 +1,114 @@
# Follow-ups after row 68 and lead decision 90 (2026-10-11)
Status: written by Sage, lead. It follows `docs/plans/BRIEF-TEMPLATE.md`.
Two rows, both small, both Rocko's.
## Claude pin tests: a directory pin, a symlink default, a pin with a space
### Problem
Row 68 (#1561, commit 11dae0c7) pins the bus's Claude Code binary with
`MOSAIC_CLAUDE_BIN`. Filbert (comment 27349) and Dewey (comment 27350)
approved it and named mutants no test kills:
- `bs-no-f`, `ad-no-f`, `bs-x-only` and `ad-x-only`. The `[ -f … ]` check
in `scripts/bus-service.sh` (`claude_line`) and in
`adapters/claude/adapter.sh` can go and every test still passes. A
directory is `-x`, so the unit would carry a directory pin, and the
adapter would fail at exec (exit 126, "Is a directory") instead of
exiting 2 with its own message.
- `bs-resolve-default`. Resolving the default `command -v claude` with
`readlink -f` passes, because the test's `claude` on `PATH` is a plain
file. On Jason's host `~/.local/bin/claude` is a symlink, and the pin is
meant to keep the symlink so updates follow.
- `ad-unquoted-run`. The adapter runs `"$CLAUDE"`. Unquoted, a pin with a
space breaks. `bus-service.sh` refuses a space, but the adapter takes a
hand-set pin. Nothing in the adapter checks the pin's characters.
`bs-status-no-env` and `bs-sed-unanchored` stay untested; both reviewers
asked for no test.
### Owner and reviewer
Owner: Rocko. Reviewer: Filbert. Rocko has no Gitea token; Sage runs the
review request as jarvis.
### Files owned
- `packages/cli/tests/host.test.mjs`
- `packages/harness/tests/claude-session.test.mjs`
- `agents/rocko/work/queue-<row>/`
### What ships
- A `render --claude DIR` test and a default test where the `claude` on
`PATH` is a directory: both refuse with "not an executable file" and
print nothing on stdout.
- A default test where the `claude` on `PATH` is a symlink to an
executable: the unit's `MOSAIC_CLAUDE_BIN` is the symlink path, not its
target.
- An adapter test with `MOSAIC_CLAUDE_BIN` a directory (exits 2 before
anything runs) and one with a stand-in under a directory whose name has
a space (runs).
- The packet reruns the six named mutants against the candidate and lists
each killed.
### Out of scope
Any change to `bus-service.sh`, `adapter.sh`, the launcher or the seat
session code. If a test shows the code is wrong, stop and tell Sage.
### Gate
Filbert approves on the row's issue naming the candidate manifest. The
cli and harness node suites and every `scripts/test-*.sh` green on Sage's
gate rerun.
## Coder role: drop the task.reassign grant the broker always refuses
### Problem
`roles/coder.json` lists `task.reassign` under `crossRole`. The task verbs
refuse every pm-only verb to any other role (`packages/tasks/src/verbs.mjs`,
`PM_VERBS`, `field-writer`), so a coder's resolved decision to reassign
always ends in `field-writer`. Lead decision 90 kept assignee pm-only and
named this a dead grant for its own row. A grant that can never succeed
misleads anyone reading the role file and wastes a decision round.
### Owner and reviewer
Owner: Rocko. Reviewer: Dewey. Sage runs the review request as jarvis.
### Files owned
- `roles/coder.json`, the `crossRole` list only
- any test that lists the coder's grants, and a bus test for the
classification
- `agents/rocko/work/queue-<row>/`
### What ships
- `task.reassign` removed from the coder's `crossRole`; `task.scope.change`
stays.
- A test that the broker now classes a coder's `task.reassign` as
`gated`, not `cross-role` (`packages/bus/src/broker.mjs`,
`#classification`: an action in neither list is gated). The verb
still refuses with `field-writer` if it ever runs.
- The packet lists every place that read the old grant (role resolution,
tests, docs), with what each now says. It also says plainly what a
coder's `task.reassign` does end to end after the change. A gated
request asks a human for a decision that can only end in
`field-writer`. Refusing it before any decision opens is a broker
change and would be its own row. The packet names it; it doesn't make it.
### Out of scope
Any other role's grants, the `PM_VERBS` set, `broker.mjs` and the slice 1
field table.
Who may reassign doesn't change; only the grant that never worked goes.
### Gate
Dewey approves on the row's issue naming the candidate manifest. The
tasks, bus, business and harness node suites and every `scripts/test-*.sh` green
on Sage's gate rerun.