From 5b7089ea143eaddabd1fdfece00a5496c8ba9f2f Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Thu, 22 Oct 2026 22:32:58 -0500 Subject: [PATCH] duckworth: row 294 round 1 approve (static) on 0b3f9c9d, plugins exception accepted, C1-C2 (duckworth-0249) --- .../duckworth/work/row294/ROUND1-ca710eabd.md | 99 +++++++++++++++++++ docs/SESSIONS.md | 1 + 2 files changed, 100 insertions(+) create mode 100644 agents/duckworth/work/row294/ROUND1-ca710eabd.md diff --git a/agents/duckworth/work/row294/ROUND1-ca710eabd.md b/agents/duckworth/work/row294/ROUND1-ca710eabd.md new file mode 100644 index 000000000..296e48462 --- /dev/null +++ b/agents/duckworth/work/row294/ROUND1-ca710eabd.md @@ -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. diff --git a/docs/SESSIONS.md b/docs/SESSIONS.md index 3bfcebd04..26290caa9 100644 --- a/docs/SESSIONS.md +++ b/docs/SESSIONS.md @@ -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) |