duckworth: row 294 round 1 approve (static) on 0b3f9c9d, plugins exception accepted, C1-C2 (duckworth-0249)

This commit is contained in:
jason.woltje committed 2026-10-22 22:32:58 -05:00
1 parent 3ec813bbc7
commit 5b7089ea14
2 files changed
+100

No files matched your search

@@ -0,0 +1,99 @@
# Row 294 (FED R6, #1800) round 1: static review, owner-transport ruling (duckworth-0249)
Reviewer: Duckworth. Builder: Launchpad. Requests: launchpad-0054 (cc Sage), sage-3166. Request
comment 30993, rev 3422. Rulings read: sage-3142, sage-3153, sage-3157, mos-1394.
Candidate: the 17-path manifest from 9450774cb, digest
0b3f9c9de7438a66fa0aee4e813a05d7a85fbb650f451d015a1ea041ca2794f3. Branch launchpad/row294 at
ca710eabd. Base 253346e3c.
Brief: docs/plans/2026-10-23_mvp-readiness-rows.md, "Brief: FED R6".
Method: git reads only. No node, no tests.
## Verdict: APPROVE (static), with C1 and C2
The code meets every brief item. The tests and mutants the brief requires are present. The
owner-transport exception is not owner authority used for the user (ruling below).
## Manifest and chain
- ca710eabd:agents/launchpad/work/queue-294/MANIFEST.sha256 hashes to the digest. It has 17 lines,
and all 17 blobs match 9450774cb.
- The path list equals `git diff --name-only 253346e3c 9450774cb` less the queue-294 packet.
- 9450774cb..ca710eabd adds only MANIFEST.md and MANIFEST.sha256.
- 253346e3c is an ancestor of origin/refactor b23783f39 (fetched 03:30Z). No manifest path and no
path under packages/ changed between them.
## Ruling: the `plugins` call over the owner transport (C6, mos-1394, sage-3157)
Accepted. This is the Console reading its own channel gate, not the owner acting for the user.
- chat.mjs sends the owner exactly `plugins` with `{}`. No session, request or prior-call value is
in the argument. G9 pins this, and M10 (session sub added) and M11 (last args carried) test it.
- createChannelCaller (plugins/src/channel.mjs) uses the answer only to decide server-side whether
the webui channel module loads. The answer itself is never put in a response, and G9 checks the
owner marker is absent from every body.
- Every verb that acts on data (projects, threads, messages) goes over the user transport, where the
broker decides it against the user's grant. M8 tests that.
- What the user can learn: one bit, whether the channel is enabled, via channel-disabled. An error
code from the owner transport (for example a bus that is down) can also reach the user as a code
string. Neither is owner data or owner authority. See N2.
If Mos reads it differently, this ruling is the part to send back. Nothing else in the verdict
depends on it except G9.
## Brief items
| Brief item | Where | Test |
|---|---|---|
| granted-user sign-in via R1's loader, ungranted refused | webui/src/access.mjs, sso.mjs callback | G1, G2 |
| per-session user-cli transport, never human-cli | user-bus.mjs (strips MOSAIC_BUS_CLI_NONCE, sets MOSAIC_BUS_USER_NONCE, runs USER_CLI) | G8 |
| grant re-read every request, 401 when revoked | sso.mjs session(): `users.check`, fails closed when `users` is null | G3 (4 revoke kinds) |
| owner controls hidden, bus refusal stands alone | serve.mjs userRoute, USER_FILES | G4 (gate), G5 (bus) |
| row 193 notice word for word | public/user.html `#user-notice` | G6 |
| hub label and peer links | federation.js (textContent, http(s) only) | G7 |
| accessContextFor peers from system.federation.peers | cli/src/access.mjs | F8 peer test, B1 |
- Liveness in consoleAccess is the same test as broker #userGrants (`covers` at viewer, first
project and instance). The two agree on who is live.
- accessFor (cli/src/config.mjs) boots the owner's bus with a bad file and warns once with the path
and a code, never the contents. B3 pins three cases including a symlink, and checks the
`secret-marker` text is absent.
## Mutants
The kill reasoning holds for M2-M11:
- M2: G3's `counts.user` unchanged and the user-revoked line. The broker would also answer 401, so
the log line and transport count carry the kill, not the status.
- M3: G6. M4: F8 `ctx.peers` and B1 `context.peers`. M5: G2. M6: G8. M7: B1 `config.access.file`.
- M8, M10, M11: G9. M9: B3 warnings deepEqual.
M1 does not behave as the table says (C1).
## Conditions
- **C1. M1's kill record.** BUILD.md:247 says that under M1 "G5 and G4's 'refused, nothing written'
stay green". G4 (granted-user.test.mjs:236-244) asserts per route inside the loop. Under M1 its
first route, GET /api/bus/inbox, reaches the user bus and answers 403 `access-refused`, so :239
fails and :242-244 never run. G4 can't show "nothing written" under M1. The brief's "bus refusal
stands alone" therefore rests on G5. The M1 record names G4's first failure (:239, actual
`access-refused` on GET /api/bus/inbox) and shows G5 green in the same run. Fix the BUILD.md:247
wording in the record or the runs note.
- **C2. The gate.** The run plan in BUILD.md "Run limits" runs on Sage's CLEAR before any landing.
## Notes (non-blocking)
- **N1. C2b has no HTTP-level test.** The swap of every bus option to the user transport (C2b) is
what keeps a human transport out of a user session. A mutant that swaps only the chat options
survives, because the userRoute gate blocks the other routes first. G5 tests consoleBus over the
user transport directly, not the per-request swap in serve.mjs. Suggest an M12 (serve.mjs keeps
the owner's `send` for a user session), killed by a G4-style check on `env.counts.owner` with the
gate stubbed, or a direct test that a user session's options carry no owner caller besides
`plugins`. Not brief-required.
- **N2. What leaks through the exception.** channel-disabled tells a user whether the webui channel
is on, and an owner-transport failure code can reach the user's response. Both are acceptable. If a
later row wants none, the chat could map any owner-side failure to one fixed code.
- **N3. accessFor labels.** Any non-BusinessError at loadAccess gets `access-unreadable`. That
covers an fs error, as intended, and also a plain programming error. The context-warn path also
prints `e.message` from the business-file load, which names the business file rather than the
access file. Neither leaks access-file contents.
- **N4. user-bus.mjs is a copy** of about 40 lines from bus.mjs (C7). The follow-up to fold it back
at the next channel-proof re-pin should become a queue row, so it isn't lost in BUILD.md.
+1
View File
@@ -1549,3 +1549,4 @@ are never rewritten or removed; corrections are new entries.
2026-10-22T23:55Z | Duckworth (Opus 5.5) | rows 270/271 r4 rebase delta review (ac44d0de9, 2b964a082) | APPROVE both, C1-C2 carried (duckworth-0235) |
2026-10-23T01:57Z | Duckworth (Opus 5.5) | row 270 queue round 3 on 49cee846e (manifest f4174458) | APPROVE, C2 met (duckworth-0243) |
2026-10-23T02:52Z | Duckworth (Opus 5.5) | row 292 (#1797) round 1 static on 3fd8f42f6 (manifest 2fa7ae17, replaces f8b9c2f73) | APPROVE (static), C1 met, kill rules checked, C2 carried (duckworth-0246) |
2026-10-23T03:32Z | Duckworth (Opus 5.5) | row 294 (FED R6, #1800) round 1 static review on manifest 0b3f9c9d (ca710eabd) | APPROVE (static), owner-transport plugins call ruled acceptable, C1 M1 kill record, C2 gate, N1-N4 (duckworth-0249) |