Files

11 KiB

Row266 C2-10c — Console rooms (#1771)

Fethry14f80e3c, branch fethry/row266, NEW worktree /home/jwoltje/.t3/worktrees/mosaic-stack/fethry-row266. Original base962046aaa; fast-forwarded to doc-only487500a16 per sage4156. Both225 branches untouched. Pinned amended brief85e6fe2ecfc5, C2-10c; prior3a5ed91a had identical section but stale whole-file pin. Review order Boyd48a3ae38 then Dewey84fb346c; Sage owns landing. No token/other-seat credential access. Slot CLEAR sage4154 lasts until returned. Local root/webui npm ci, no dependency links. TMPDIR=/mnt/storage/scratch/tmp/KV9rHb, MOSAIC_REQUIRE_EDITOR_BUILD=1. Implementation and targeted checks complete; full gate in progress.

Current code and resolved seam

  • chat.mjs is the channel-gated fixed-verb seam. Add roomOpen({project}), roomRead({project,after,limit}), roomSend({project,body}), exactly one matching room verb each. Never fetch thread.messages to hydrate rooms.
  • chat-http.mjs already provides signed-in/send/Origin/Fetch Metadata, bounded JSON, strict keys, safe error text, audit and outcome-unknown handling. Extend it with POST rooms/PROJECT/open {}, GET rooms/PROJECT/messages ?after&limit, POST same messages {body}. Four room codes map409 and fixed lines. Open returns {project,threads}; send returns {ids,to}; read returns {rows,after,hasMore,at}. Room cursor is the LAST id in the final entry.ids, not the first entry.id; the broker groups human sends.
  • webui plugin needs exactly room.open/read/send in its allowlist, still rejecting arbitrary verbs.
  • /api/chat/instances already returns threaded instance keys and persona.name labels. No serve.mjs edit.
  • room.open returns canonical member threads; room.read returns one merged human entry with ids/to. Read-only GET must never open/create a room or wake an agent. No implicit retry of any write.
  • Amendment1 (sage4156): broker.mjs is owned only for shared check-event hydration and routing room.read through #withLast under the same condition as thread.messages. The missing check would otherwise hide badges AND reopen225's forged-notice defect. No other broker verb/refusal/field changes.

Design and implementation plan

  1. New plugin, HTTP/seam, bus metadata and browser files first; run whole new files RED, report first-run results per mos1272/1590, correct only demonstrably wrong NEW fixtures. No old test edits.
  2. Add the three plugin/seam calls and strict HTTP room routes/receipt validation. Reuse existing principal/write fences. Owner room verbs stay human-only; hide controls from granted users/testers, and never route a call through an owner transport for them.
  3. In broker, extract #withCheck(row), call it for thread messages and each final merged room entry; extend the existing last-routing condition to room.read. Test real checked reply parity, unchecked absence and unchanged merged human entry across two members. No broker room.open/send changes.
  4. Add /chat/rooms/PROJECT route inside chat.js, sharing its current state, generation/abort handling, capture/paint/scroll preservation and225 message renderer. Project view gets explicit Open room; direct room GET only reads and offers Open on room-not-open. Names come from instances catalog, membership from canonical room threads, with server room.read authoritative. Quiet members stay available for completion. Human entries display once, with all broker addressees; no client regrouping.
  5. Completion parses leading @ tokens with the exact broker grammar and its existing case vectors. Display typed tags in a preview; use that production tag reader for completion and browser parity. Suggest members by instance/name, insert the stable instance token, preserve unrelated text/caret. Arrow keys/Enter/Tab/Escape and click work; labels/text remain escaped and bidi/control inert. Browser sends original typed body, never a client-selected addressee list. Broker409 lines are fixed.
  6. Whole webui/plugins/bus (touched) suites, all12 scripts/test-*.sh under timeout -k10, then isolated mutants. No live-provider calls (MOSAIC_LIVE_PROVIDER unset). New worker/temp process groups get killpg cleanup and cwd/Chromium sweep; never touch another seat's processes. Record every red.
  7. Hash-pin audit by source path AND old64-hex digest for chat.js/chat-http.mjs/channel module before in-review. Freeze manifest, push fethry/* only, owner queue move in-review, handoff Boyd+Sage with candidate/digest; Sage posts because this seat has no Gitea token. No force push, merge or deploy.

Acceptance focus: grouped paging cursor, one entry for a broadcast even across two threads, quiet member completion and parser parity, checked reply badges/notice safety, malformed receipts/unknown outcomes,4 refusal codes, no read-side mutation, late reads/sign-out and project draft isolation.

Boundary rules: old-test red, any production path beyond the owned set/amendment, or weakened assertion goes to Sage BEFORE action. New-file first red is reported then fixture corrected.

Targeted RED/GREEN receipts (2026-10-24)

Start op fethry-266-start succeeded rev3978 after sage4156's re-pin; old-pin refusal wrote nothing. First whole NEW files RED: plugin0/1,HTTP0/5,bus1/1,browser0/7, all intended missing-feature paths; reported fethry0028 before production. Component GREEN plugin1/0,HTTP5/0,bus2/0. Browser5/2 exposed a missing submit branch in our new room event dispatcher; reported fethry0029, fixed only that branch, then browser7/0. No fixture/assertion changed to fix production behavior.

Boundary coverage added before full gate: malformed numeric member key was accepted by regex coercion (new HTTP6/1, fethry0030); required string and unique group ids/addressees, now HTTP7/0. New browser assertions use fresh send ids and read back exactly one broadcast entry. Expanded run8/1 exposed a nested quote in our new runtime CSS selector; reported fethry0031 BEFORE fixing fixture with JSON.stringify, same exact count=1 assertion retained. Final browser9/0,4864.326ms, with quiet member Arrow/Tab/Escape, raw body preservation, no duplicate pending send, uncertain draft, parser vectors, all4 refusal lines, checked reply/cite/notice safety and late-read/sign-out coverage. No pre-existing test/helper edit and no assertion loosened. Production set is precisely six brief- owned paths including the narrow broker amendment. All red/green raw logs under unique TMPDIR.

Full gate now runs run-gate.py: local editor build, whole webui/plugins/bus then all12 test scripts, serial timeout -k10, per-test30s, MOSAIC_REQUIRE_EDITOR_BUILD=1; live-provider env removed. Each step has its own process group and killpg cleanup, with signals recorded. Any failure stops for report.

Full gate first pass

Editor build exit0; whole webui458/0 (270.066s), plugins120/0 (.866s), no skips/cancels. Bus999/1 (132.9s): OLD library-credential.test.mjs T9 at317 expected library-fetch-no-grant, received library-sync-busy. Reported fethry0032 before changes. No old test/source change. Read-only diagnosis: fixture starts a50ms periodic sync; waiting for a completed log does not prevent the next tick from acquiring running(mirror) before the manual sync. Existing sync.mjs140 checks running before credential refusal. Row266 touches neither timer nor sync implementation. All12 scripts continue independently; rerun/ruling requested from Sage. Raw bus-full.tap and gate-summary.json remain in the scratch directory, preserving the red evidence.

Sage4158 confirms the pre-existing50ms T9 timer race and authorizes three unchanged whole-file credential runs followed by one unchanged whole bus run. Any recurring T9 red stops for Sage; no fixture or production patch is authorized. The12-script runner proceeds serially first.

All12 scripts/test-*.sh exited0 (scripts-summary.json). Queue's156 tests pass; wrapper28/0 and explicitly skips canonical queue verify/render checks in an isolated worktree. Task92/0 uses existing row244 live-provider exclusions, with MOSAIC_LIVE_PROVIDER unset. No script edited. Three unchanged whole credential-file reruns under sage4158 each pass6/0 without skips/cancels, 1.367s each wall clock. Full unchanged bus rerun is next/running.

Pin audit before in-review: source paths/basenames and old/current64hex values for chat.js, chat-http.mjs and channel/webui/index.mjs searched across package/script tests. No literal old or current digest pin. The10 frozen package hashes include all six production paths and four new test files; no existing test diff. sha256sum -c passes on all10.

Unchanged full bus rerun GREEN1000/0, no skips/cancels,142.919s. T9 passes. This completes sage4158's four unchanged green reruns (credential6/0 three times, bus1000/0 once) after the initial999/1. Preserve all five TAPs. Pre-existing T9 timer race is Sage's follow-up, no source or old test changed for it. Full applicable suites and12 scripts are green; mutants next. Evidence display copies strip trailing whitespace only; raw-log-provenance.json records original paths and both digests. All10 package hashes remain unchanged from full-suite verification.

Source candidate b8b26ae4d. First M01 attempt removed plugin room.open and deterministically refused channel-operation, but the strict assertion-only classifier did not count the uncaught PluginError. Restored hash and candidate unchanged. Reported fethry0033 BEFORE strengthening only the NEW room-channel test with doesNotReject; exact receipt/call assertions retained. Whole plugins rerun120/0, no skips/cancels. Only that new test hash changes in manifest.r1; all production hashes, HTTP/bus/browser tests and prior suite coverage remain identical. Excluded M01 TAP/summary preserved under evidence/mutants-r1, not a killed-mutant claim.

Final candidate and mutant verification

Tested source3095d6ea5 (b8b26ae4d plus assertion-strengthening new-test follow-up). All16 isolated mutants killed by assertions, exit1 with ERR_ASSERTION, zero skips/cancels, one anchor each, hash restored after each, candidate hashes unchanged. Evidence/mutants-r2/summary.json records every result. Initial excluded M01 remains separate. No timeout/error counted as a kill. All gate/mutant commands bounded with timeout -k10; runner-owned groups cleaned using killpg. Final /proc sweep finds zero node/Chromium processes with this worktree cwd or command path; process-sweep.json records it. No other seat process touched.

Final manifest.r1 SHA256:5f816042792b24b790d4faa5bfdc35a8138225819f85d9d32ae49ba8a2de033f, 10 package files. Six production paths, four NEW test paths, zero pre-existing test edits. No production/source change after suite verification; only the new plugin assertion strengthened and full plugins rerun120/0. Final static diff and manifest checks pass. Slot can return. Review first Boyd, then Dewey; Sage owns review-request credential and landing.

Canonical owner move fethry-266-inreview succeeded rev3979: row266 in-review round1 #1771, frozen manifest5f816042. Review request outcome rev3980 failed solely because MOSAIC_GITEA_CREDENTIAL_FILE is unset; no credential file read or alternate credential used. Sage must post the arranged review request. Boyd received direct candidate handoff fethry0035. Initial duplicate handoff to Sage timed out in T3 metadata GET; retry via outcome report0036.