docs: Rocko channel design, cut-over and own log lines (sage-0766/0769)

This commit is contained in:
2026-10-18 11:46:45 -05:00
parent 5370251458
commit c202d57a1f
4 changed files with 325 additions and 0 deletions
+2
View File
@@ -5003,3 +5003,5 @@ Before: usage_records skipped Store timestamp verification; Claude project-direc
Before: managed project/thread verbs had no Console conversation area. After: fixed human-transport chat adapter/HTTP routes, named project/thread forms, isolated conversations/drafts, explicit Resume, paging and signed-in sends. sage-0724 keeps channels out of scope. Rebuilt on row124 landing70504d23a, preserving usage hunks. Gate: webui177 + bus threads14 + CLI parity11 =202 passed; 9 named-navigation and 20 strengthened HTTP checks reran as subsets. 64/64 mutants killed; first array-guard survivor led to missing project/thread response assertions, now killed with source unchanged. Existing navigation expectations updated with named items per sage-0747. Packet agents/rocko/work/queue-129/r1/, candidate cfbadbd49902f5f3740392fec9218279adc2a661cfb28341fba02790f327232b, packet c674fb259c377cb3b60aaa42fd348e9da7b722ae3aa9e8fb182f99cbfa7dfe02. All15 staged/working/reconstructed hashes and118 packet entries verified; scan clear, process sweep empty. In-review1767-1768; expected no-token exit1. Slot returned, no Docker/live action; Filbert review and Sage/Mos gates remain.
2026-10-18 16:42:30 UTC | Rocko | row 164 #1661 design stage | Before: no channel kind; row 129 in review. After: agents/rocko/work/queue-164/DESIGN.md answers all five brief questions with file:line evidence, proposes interface v1 dispatch and a core management recovery path independent of channel switches, inventories proof reads/callers and unchanged byte baselines, and names cut-over and parity-fixture decisions for Sage/Mos. Design only; no claim, product code, tests or live action.
2026-10-18 16:46:44 UTC | Rocko | row 164 design revision | DESIGN.md and pre-build BUILD.md record Sage/Mos conditions and human-only enablement right after activate, followed by CLI thread and Console chat smoke. Loader inspection found no one-call matched snapshot API; propose synchronous snapshot(kind), no dispatch lock. Existing chat-http owns status/message mapping; propose its local change instead of serve.mjs. No product edits or test runs.
+30
View File
@@ -0,0 +1,30 @@
# Row 164 — pre-build notes
Design accepted by Sage and Mos, with sage-0766 / sage-0769 conditions.
Row 129 round 2 comes first; row 164 remains unclaimed until row 129 is done.
No product code or tests yet. DESIGN.md records the pending snapshot API and
local chat-http mapping scope choices for Sage.
## Cut-over — human action only
Per sage-0769 / mos-0768, in the Mos-run re-pin window that takes row 164 live:
1. Mos runs the approved activation. No development seat activates anything.
2. Right after activate, Jason uses the existing proved human management path:
`mosaic plugins --business BUSINESS --json`, then
`mosaic plugins set --business BUSINESS --file PATCH`, with the freshly read
revision and `plugins.channel` set to `["cli", "webui"]` in the patch.
3. Smoke CLI thread listing (`mosaic threads --business BUSINESS`) and Console
chat with the approved human access. Confirm both are usable.
No agent runs step 2 or edits the live organization file. Until the explicit
enablement, absent-key-off refusals name `mosaic plugins` and
`mosaic plugins set` with the channel list as the recovery. If either channel
is later disabled, that same independent core management path restores it.
## Fixture exception
In thread-cli.test.mjs and chat.test.mjs, additions only: organization read
adapter or plugins response, plus a separate record of management reads. Every
existing assertion, payload and expected result stays byte-identical. The build
packet will list each exact hunk for Dewey's line-by-line review.
+292
View File
@@ -0,0 +1,292 @@
# Row 164 / #1661 — channel kind design
Design only, Rocko, 2026-10-18. Brief: `docs/plans/2026-10-18_channel-kind.md`,
commit `c682d5f7a`, pinned blob `c20a2a19b99b`; Sage sage-0758.
Sage and Mos accepted the original design with sage-0766 conditions (sage-0769,
mos-0768). The snapshot getter and chat-http placement proposed below still need
Sage's scope choice. Row 164 is unclaimed:
`queue next rocko` says to wait for row 129. No tests or live reads/actions run.
Evidence below is from canonical HEAD `c682d5f7a`, except the explicitly marked
row-129 candidate. That candidate is frozen in
`agents/rocko/work/queue-129/r1/build.patch`, candidate manifest SHA-256
`cfbadbd49902f5f3740392fec9218279adc2a661cfb28341fba02790f327232b`.
Its line references were read in `/mnt/storage/src/mosaic-stack-rocko-129-r1/`.
Recheck them against the landed row-129 tree before implementation.
## 1. Interface, switch and call sites
Recommend registry entry `channel`, `interfaceVersion: 1`, `switch: "list"`,
required function export `dispatch`. Each module exports:
```js
export const interfaceVersion = 1;
export async function dispatch({ verb, args }, { call }) { /* ... */ }
```
`call(verb, args)` is a core-created, already business-bound human transport.
The module returns its resolved bus result unchanged, or propagates its refusal
unchanged. It receives no capability, proof, human/tenant selector, socket path,
process API or configuration writer. It must not import a transport or start a
process. The shipped modules only validate their supported operation and forward
it to `call`; presentation, HTTP guards, thread resolution and paging remain in
their current core surfaces. These are trusted in-tree modules, not a sandbox or
an authorization boundary (`loader.mjs:1`, `:41`; PRD `docs/prd/mosaic-stack.md:598`).
Supported operations are `project.list`, `project.create`, `thread.list`,
`thread.create`, `thread.messages`, `thread.send` and `thread.open`. The CLI
module also forwards `message.receive` and `message.read` for the existing
thread talk/follow loop only. These exports support future surfaces without
requiring surface-specific function names in the kind. An unsupported verb
refuses `channel-operation`; no arbitrary verb fallback. Existing REQUEST
construction stays in CLI `cli.mjs:354` and row-129 `chat.mjs:11`.
Core helper, new `packages/plugins/src/channel.mjs`:
```js
createChannelCaller({ name, call, log }) // returns async (verb, args = {}) => result
```
It reads current settings with the existing core `call('plugins', {})`, validates
that response and projects just its channel key into `createLoader` (or `{}`
when absent), then selects the requested name from
the matching `loaded().channel` / `modules('channel')` snapshot, and invokes
`dispatch`. The name is a core literal (`cli` or `webui`), never browser input.
Take names and modules as one atomic snapshot, then release selection before
invoking dispatch. Never hold a lock over dispatch: a slow thread.send must not
block project.list (sage-0766). The existing loader has only separate synchronous
getters, `loaded()` and `modules(kind)` (`loader.mjs:148`–`:157`); it does not
currently return matched pairs in one call. Proposed for Sage/Mos to choose:
add synchronous `snapshot(kind)` returning the current immutable list of
`{ name, module }` entries. Those entries and their array are already frozen
(`loader.mjs:71`, `:136`). The getter performs no await or callbacks. The helper
captures that one return value, selects the requested entry synchronously, and
invokes dispatch without a lock. No edits to path, version or last-good behavior.
This adds `src/loader.mjs` and its snapshot test to the proposed scope; no code
starts until Sage accepts the loader API choice and Mos accepts the design.
Keep a loader per caller; a malformed settings response refuses rather than
silently inventing configuration. Read settings again for each chat operation,
including the thread receive loop, so a valid off switch takes effect on the
next operation. An operation already admitted may finish once. A loader refusal
uses the existing last-good policy; first-load refusal has no enabled modules.
Log refusal metadata without message bodies or proofs.
Projecting the channel key avoids loading unrelated usage/search modules into
the human CLI or Console; it does not change the organization document.
| Surface | Existing seam | Proposed routing |
|---|---|---|
| CLI project create/list | `cli.mjs:541` | Pass a channel caller into `projectBusCommand`; local init/check remain core. |
| CLI threads and thread create/read/open | `cli.mjs:542`, `:543`; `thread.mjs:40`, `:53`, `:72` | Pass the channel caller through the current command/helper signatures. Preserve resolution, formatting and 200-row paging. |
| CLI talk/follow with --thread | `cli.mjs:345`, `:349`, `:354`, `:382`, `:390` | Use the channel caller for this flow, including its receive/read operations. Non-thread talk/follow are unchanged. |
| WebUI chat | row-129 `chat.mjs:3`–`:12` | Wrap the supplied core call once with the webui channel caller; preserve all seven public method signatures. |
| Administrative CLI and other Console views | `cli.mjs:540`, `:544`–`:546`; row-129 webui `cli.mjs:59`–`:65` | Retain their existing raw core call. Never wrap the common transport factory globally. |
Both modules load only through `createLoader`; no core import names either
module. `kinds.mjs:9` is the registry; `loader.mjs:41`–`:69` already supplies
name/path/symlink/export/version checks. `hasModule` uses the same registry
(`loader.mjs:77`), so the existing organization setter can validate the new names.
## 2. Off behavior and the recovery path
The setting is, for example, `"plugins": { "channel": ["cli", "webui"] }`.
Only `cli` disables web chat; only `webui` disables the CLI's project/thread
surface; `[]` disables both. Removing the channel key also disables both. No
implicit default: an absent key means off (`loader.mjs:117`, plugins README:63).
A disabled CLI channel refuses `channel-disabled`, exit 3, before a project,
thread, delivery or read operation. A disabled WebUI channel returns HTTP 503,
`error: "channel-disabled"`, with no successful send receipt and no chat bus
operation. Both refusals include fixed, operator-facing recovery text:
"Run mosaic plugins to read the revision, then mosaic plugins set --file PATCH
with plugins.channel set to [\"cli\",\"webui\"]." Include the actual CLI
business selector when available. Assert the recovery text in both tests.
Do not edit proof transports.
The HTTP mapping actually belongs to row-129 `src/chat-http.mjs:12`–`:22`:
its closed STATUS table and safeMessage function decide the status and message;
its catch ignores arbitrary transport error text (`:114`–`:119`). `chat.mjs`
alone cannot deliver a new status or reflected message through that contract.
Propose adding only channel-disabled:503 and its fixed recovery message in
chat-http.mjs, with the seam adapting the refusal to BusReadError. This avoids
serve.mjs entirely and does not conflict with row 154's static routes. This is a
correction to the initial design's suggested serve.mjs mapping, for Sage's read.
The chat page can still render its normal refusal state; other Console routes,
Settings, and core human administration stay available. An empty channel list
does not stop the bus or revoke the human session.
In particular, **`mosaic plugins` and `mosaic plugins set` do not use a channel**.
The current dispatcher already gives them the raw `callFor` (`cli.mjs:546`),
and `plugins.mjs:34`–`:37` calls `plugins` / `plugins.set` directly. The broker
requires a proved human and its configured organization adapter
(`broker.mjs:1133`–`:1165`), independent of any channel selection.
`plugin-settings.mjs:34`–`:60` applies a per-kind patch with revision checking
and the existing organization writer. None of that path changes.
Exact operator recovery, with both channels off:
1. From a real human shell outside an agent, run
`mosaic plugins --business BUSINESS --json` and obtain its `revision`.
2. Create an operator-owned patch file with
`{"revision":"<revision>","plugins":{"channel":["cli","webui"]}}`.
3. Run `mosaic plugins set --business BUSINESS --file PATCH`.
4. Retry chat. Its next settings read sees the restored selection; no unit
action or hand-edit of the organization file is needed for this channel helper.
Stale revisions require another read. An unavailable bus, invalid organization
file or uncertain organization transaction still fails closed through today's
writer; this design adds no repair bypass for those independent failures.
Being switched off cannot itself make the recovery read or write unavailable.
Legacy inbox/decide, non-thread talk, limits and usage remain core operations;
the channel switch here controls the project/thread surfaces named by the brief,
not the entire `mosaic` executable or human-proof transport.
### Cut-over and parity fixture exception (Sage and Mos accepted)
Existing organization files have no channel selection. Recommend an explicit
human-approved `plugins.set` patch enabling both modules in Mos's re-pin window,
after the new registry is running. Until that patch, only the converted chat
surfaces refuse; the independent recovery path remains available. Do not silently
enable omitted settings or change generic loader semantics to hide this cut-over.
Jason runs that plugins.set right after activate in Mos's re-pin window, then
smokes `mosaic threads --business BUSINESS` and Console chat. No agent runs this
step against the live organization file; see BUILD.md's cut-over notes. Sage accepted this cost in sage-0766 (about 16:45Z; stamp
corrected in sage-0768) and will put it in the re-pin plan.
There is also a concrete tension with the brief's unchanged-tests sentence.
CLI `thread-cli.test.mjs:35`–`:59` builds a broker without an organization adapter;
row-129 `chat.test.mjs:33`–`:43` records every injected bus call. A settings read
cannot pass those fixtures unchanged. Sage accepted this narrow exception in
sage-0766:
give the CLI fixture an organization read adapter returning enabled channels;
give the WebUI seam fixture the same `plugins` response, recording that management
read separately from chat operations. Keep every existing behavioral assertion,
HTTP fence, payload and expected result unchanged. No production test bypass or
default-enabled fixture mode in product code. Browser tests injecting chat methods
directly need no change; confirm this when row 129 lands. In those two files,
add only the organization read adapter or plugins response and a separate record
of management reads. Every existing assertion, payload and expected result must
remain byte-identical. BUILD.md will identify both fixture hunks for line-by-line
review. Mos accepted this narrow exception via sage-0769 / mos-0768.
## 3. Human proof remains entirely in core
Existing call graph stays:
```text
CLI core humanTransport ─┐
├─ core human-cli.mjs -> Client -> socket server
Console core humanCall ─┘ -> runtime.verifyHuman
-> Broker.bindHuman
channel dispatch receives only an existing call closure ─┘
```
No new direct caller of the shim, verifier or process reader. Modules never
import or spawn them. The new settings read uses the same existing call closure
and therefore the same proved route, not a second proof implementation.
| Proof input read | Exact source and unchanged use |
|---|---|
| `/proc/<pid>/stat` | `human.mjs:19`–`:21`: parent PID and start time for submitted process and traversed ancestors. |
| `/proc/<pid>/environ` | `human.mjs:25`–`:34`: only nonce and existing marker names retained; existing EACCES handling unchanged. |
| `/proc/<pid>/cmdline` | `human.mjs:41`: executable/argv ancestry checks and exact shim path. |
| `/proc/<pid>` metadata | `human.mjs:40`: lstat UID; not another file-content read. |
| Shim stdin, fd 0 | `human-cli.mjs:17`: strict request envelope; no token/config file added. |
The submitted process is read again before success (`human.mjs:89`–`:95`).
The proof also consumes the existing in-memory launch PID/start records and
resolved business human (`runtime.mjs:115`–`:121`); it opens no organization,
wrapper, shim-source, credential or system-config file to prove a request.
In particular, the verifier compares a **literal argv path**, not a file hash
(`human.mjs:70`). Hash checks below are regression evidence, not a new proof rule.
Unchanged core source and direct production callers:
| File | Current role/caller, unchanged |
|---|---|
| `packages/bus/src/human.mjs` | `verifyHuman` called by runtime only; exported `readProcess` also already used by human-cli, tester and tester-cli. No new caller. |
| `packages/bus/src/human-cli.mjs` | Self re-executes its own path (`:8`–`:12`); existing CLI transport and Console humanCall spawn it. No new caller. |
| `packages/cli/src/transport.mjs` | `HUMAN_CLI` resolved beside the running tree (`:12`), humanTransport at `:55`; existing CLI callers stay in place. |
| `packages/webui/src/bus.mjs` | Imports the same `HUMAN_CLI` (`:12`); existing humanCall spawn (`:27`–`:31`) and busCaller (`:60`). No new caller. |
| `packages/bus/src/runtime.mjs` | Same verifier import/call and same own-tree shim path (`:115`–`:116`). No edit. |
| `packages/bus/src/server.mjs` | Same authenticateHuman admission (`:62`–`:64`), capability envelope and refusals. No edit. |
Recorded unchanged byte baselines for later comparison:
```text
b995fc5cff3af8ade4c990d0e3bebf9d83829e00f034ebc9c3dcfd05f252b573 packages/bus/src/human.mjs
269c3a66008c0d57a54b14b73cf988d5f61f5e815455486296716e98ce5e8073 packages/bus/src/human-cli.mjs
5129c44b4d9f642e825344df65c9bfb4bac4fc8d6b25343b42d39853dbd40774 packages/cli/src/transport.mjs
dbad731ca8be19619064f050e766aeca856cf614783b9eca887caff3c2451f24 packages/webui/src/bus.mjs
```
Bus, Console, wrapper and modules continue to run from the one pinned tree. No
copy/wrapper/unit change is proposed. The loader already resolves modules from
its own package tree (`loader.mjs:15`, `:41`–`:54`); pinned copies already include
the entire plugins package (plugins README:43–:46).
## 4. `via` is still the proof transport, not the channel selector
Keep `via: 'cli'` everywhere. WebUI already obtains that same human proof today.
`webui` names a selected presentation module, never a claim of human identity.
The brief's four call sites, at their current lines:
| Site | Value/read after this row |
|---|---|
| `runtime.mjs:121` (brief :117) | `bindHuman({ business, human, via: 'cli', outsideAgent: true })`, unchanged after verifyHuman. |
| `broker.mjs:530` (brief :526) | Protected role-end authorization still recognizes the human decision's `via === 'cli'`. |
| `broker.mjs:1887` (brief :1867) | Launch revoke/restore event still records `via: 'cli'`. |
| `landing.mjs:107` | Human resolution still requires `res.via === 'cli'` plus the existing actor/answer checks. |
Also leave broker `#human` (`:330`) and `bindHuman` (`:472`) unchanged. A module
does not set `via`, bind a session or supply the owner. No schema change or
existing decision/event rewrite is needed.
## 5. Discord is not connected
No Discord module, connector edit, binding/token read or new service. A future
`packages/plugins/channel/discord/index.mjs` can export `interfaceVersion = 1`
and `dispatch(request, { call })` with the same bus-operation/result contract.
That future row must provide an authenticated core caller bound to the right
human/business and map Discord interaction to the fixed operations; a module
cannot manufacture proof. This interface does not authorize that future ingress.
Its authentication, subscriptions and deployment are separate decisions; merely
adding a module of this kind does not require a kind-version bump.
## Proposed owned files, tests and mutants
Product: `packages/plugins/src/kinds.mjs`, proposed `src/loader.mjs` snapshot getter, new `src/channel.mjs`, new
`channel/cli/index.mjs` and `channel/webui/index.mjs`; CLI `src/cli.mjs`
and, only if passing the caller needs it, `src/thread.mjs`; WebUI `src/chat.mjs`
and proposed `src/chat-http.mjs` (only channel-disabled status/recovery text).
No serve.mjs edit planned. Docs:
`packages/plugins/README.md`, `docs/prd/mosaic-stack.md:822` and operator cut-over
notes in this packet. No public/ UI changes planned. New helper, snapshot getter
and chat-http mapping are explicitly proposed additions to the brief's call sites.
| Acceptance/guard | Named test file and killing assertion | Mutant |
|---|---|---|
| Both shipped modules load and forward through loader | new `packages/plugins/tests/channel.test.mjs`: each named module loaded, exact verb/args/result/refusal preserved | Remove registration, either export, or bypass dispatch; separate mutants. |
| Bad name, missing directory, symlink, missing export, wrong version | same new file, scratch loader tree following `tests/helpers.mjs:19` | One disabled guard per refusal, exercised specifically for channel. |
| Nonblocking matched snapshot | new plugins `channel.test.mjs`: names/modules stay paired across a switch; a blocked send does not prevent a concurrent list completing | Separate getters across an await; hold a selection lock across dispatch. |
| Only fixed operations | same file: unsupported verb refuses without calling transport | Remove operation allowlist. |
| CLI parity through actual loaded cli module | `packages/cli/tests/thread-cli.test.mjs`, fixture change described above; all current assertions retained; new `channel-cli.test.mjs` verifies module path | Bypass dispatch; change thread verb, arguments or result; each named killer retained in build table. |
| WebUI parity through actual loaded webui module | row-129 `packages/webui/tests/chat.test.mjs`, fixture change described above; retain `chat-browser.test.mjs` unchanged | Bypass module; change fixed REQUEST or mapped verb. |
| Independent off behavior | new `channel-cli.test.mjs` and `packages/webui/tests/channel-chat.test.mjs`: off CLI exit 3, off webui 503, both name recovery, zero chat/delivery/read calls; other channel still works | Ignore off selection; use wrong module; allow receive/read after off. |
| Both off and missing key recover | new `packages/cli/tests/channel-recovery.test.mjs`: real fixture organization writer + socket proof, plugins read/set work, next chat succeeds; stale revision refuses | Gate plugins management behind channel; cache selection forever; invent missing-key defaults. |
| Proof path, bytes, import/caller set unchanged | new `packages/bus/tests/channel-proof.test.mjs`; compare four baselines, source imports and actual fixture socket admission; direct no-proof request refuses | Substitute shim path; skip authenticateHuman; introduce module proof import/spawn. Mutants run only in detached fixtures. |
During implementation list each actual mutant and exact killing test in BUILD.md;
the table above is the design inventory, not a claim that any test has run.
Dewey reviews; Sage gates plugins, CLI, bus, WebUI and all shell suites. Request
the test slot before any run. Claim only after 129 is done and this design is
accepted by Sage and Mos. No live settings change or re-pin is part of the build.
## Design revision — sage-0766 / sage-0768
Sage accepted absent-key-off and the fixture-only exception. Mos subsequently
accepted the original design with those conditions (sage-0769 / mos-0768). Added operator recovery text, removed dispatch locking,
and proposed one matched snapshot getter because the loader has no such API.
HTTP inspection found that the existing chat-http.mjs table owns the mapping,
so propose that local edit instead of serve.mjs. Recheck every row-129 reference
against its landed tree after its test-only round 2. Row 164 remains unclaimed.
+1
View File
@@ -1138,3 +1138,4 @@ are never rewritten or removed; corrections are new entries.
2026-10-18T16:34:13Z | Filbert (Opus 5.5, 048f3c63) | row 149 / #1643 round 4 review on 0f715a054 plus build.patch df0fec543dba (manifest 6b4af9c2685b) | approve, comment 28929, rev 1771; round 3 finding resolved; 21 singles 162/162 and 8 of 8 own mutants caught (16:33:06Z-16:33:12Z); doc-only follow-ups: business README:194-196, launch.instances doc gap (refused instance-not-listed, not silent)
2026-10-18 16:42:30 UTC | Rocko (Codex gpt-6.1-sol, d99326cc) | row 164 #1661 channel kind | five-question design packet ready at agents/rocko/work/queue-164/DESIGN.md; proof and recovery traced; explicit enablement and fixture-only parity exception proposed to Sage/Mos; unclaimed pending row 129; no product edits, tests or live actions.
2026-10-18T16:45:07Z | Filbert (Opus 5.5, 048f3c63) | row 129 r1 review, #1623 (Console chat area, candidate cfbadbd4, base 70504d23a) | changes, comment 28933, rev 1780: 4 of my 6 mutants survived (chat.js send path, createThread instance receipt, receipt fields, bidi controls), test-only fixes; (a) count edits and (b) read-array fix verified; 5 singles 40/40 16:42:28Z-16:44:02Z
2026-10-18 16:46:44 UTC | Rocko (Codex gpt-6.1-sol, d99326cc) | row 164 #1661 design revision | recorded sage-0766 and Mos acceptance via sage-0769; recovery text, fixture-only additions and Jason-after-activate cut-over; proposed atomic snapshot getter and chat-http-local 503 mapping to Sage; row 129 r2 first, no code/tests.