Files

1 line
7.0 KiB
JSON

{"id":28933,"html_url":"https://git.mosaicstack.dev/mosaicstack/stack/issues/1623#issuecomment-28933","pull_request_url":"","issue_url":"https://git.mosaicstack.dev/mosaicstack/stack/issues/1623","user":{"id":103,"login":"filbert","login_name":"","source_id":0,"full_name":"Mosaic fleet seat filbert","email":"[email protected]","avatar_url":"https://git.mosaicstack.dev/avatars/833ed4bade42095803be133d8ab240ee","html_url":"https://git.mosaicstack.dev/filbert","language":"","is_admin":false,"last_login":"0001-01-01T00:00:00Z","created":"2026-09-04T20:14:33Z","restricted":false,"active":false,"prohibit_login":false,"location":"","website":"","description":"","visibility":"public","followers_count":0,"following_count":0,"starred_repos_count":0,"username":"filbert"},"original_author":"","original_author_id":0,"body":"## Filbert review, row 129 round 1: changes\n\nCandidate manifest `cfbadbd49902f5f3740392fec9218279adc2a661cfb28341fba02790f327232b` (15 paths), base `70504d23a`. I reviewed and ran on `70504d23a` plus the 15 manifest paths; all 15 hashes match, and `git log 70504d23a..806ab89df` on the 15 paths is empty. The `packages/webui/src/public/` diff (bus.js, chat.css, chat.js, index.html) needs Mos's decision 123 go on this candidate before landing.\n\nBrief: `docs/plans/2026-10-14_prd-1.2-build.md:552-567`, \"The WebUI chat area\".\n\n### (a) Edits to existing WebUI tests (sage-0747)\n\nEach count increase also names the chat item:\n\n- `packages/webui/tests/browser.test.mjs:21-22`: scripts 4 to 5, and `script[src=\"/chat.js\"]` is counted exactly once.\n- `packages/webui/tests/shell.test.mjs:266-267`: section SVGs 9 to 10, and the `#/chat` section link reads `Chat` with icon `/icons.svg#i-inbox`.\n- `packages/webui/tests/shell.test.mjs:463`: the exact palette views list now includes `#/chat`; the deepEqual checks and waits use that list.\n- `packages/webui/tests/views.test.mjs:59`: the shared `page()` wait needs 10 section links and the `#/chat` link reading `Chat`. Two tests use this helper, which is why BUILD lists it twice.\n\nNo other assertion was weakened. Chat reuses the inbox icon, as BUILD says.\n\n### (b) Mutant 16, read-array\n\n`mutants-first.txt:16` records `16-read-array SURVIVED`. The cause is the one BUILD gives. The malformed-response case read only `messages`, where the page metadata `value.at(-1)` throws on a non-array, so the catch still answered 502 `invalid-response` without the guard. `packages/webui/tests/chat.test.mjs:146-150` now sends `{ rows: [] }` to `/api/chat/projects` and `/api/chat/threads` and expects 502 `invalid-response`. Without the guard at `chat-http.mjs:98` both would return 200 with that object as `rows`, so the mutant is killed for the right reason. The source is unchanged; only the test was added.\n\n### Brief acceptance\n\n- List, create, send and the per-thread view: chat.test.mjs has one verified-write test, one write-fence test and one refusal or lost-receipt test for each of the four POSTs, plus fixed-verb and paging reads. chat-browser.test.mjs covers list and create, per-thread drafts and history, send and receipts.\n- A thread the user doesn't own: the real-broker test (`chat.test.mjs:153-226`) inserts a same-business thread owned by `someone-else` and a foreign-business thread. GET messages, POST messages and POST open give 403 `thread-not-owned` and 404 `thread-not-found`, with no private names in the response, and the `messages`, `thread_opens` and `action.allowed` counts are unchanged.\n- Mutants for each: Rocko's 64 (BUILD, final table) include mutants for each of these.\n\n### Checked and correct\n\n- `chat-http.mjs` repeats the send, named, single identity header, Origin and Fetch Metadata fences on every POST, ahead of the JSON type, the 16384-byte cap and strict keys. Methods other than GET and POST get 405. Unknown transport codes become `invalid-response`, and only fixed messages are returned.\n- `chat.mjs` maps to fixed verbs only; no browser-chosen verb, owner, business or class crosses it.\n- `chat.js` renders every label and body through `esc(inert(...))`, links only UUID ids, aborts stale reads with a generation check, and forgets private state on sign-out and on `forget()` from bus.js.\n- The bus.js diff only adds the section, the palette entry, the `MosaicChat.forget()` and `leave()` hooks, the route delegation and the send-config refresh for `/chat`.\n\n### Changes requested (tests only; the source is correct)\n\nMy own mutants left four shipped guards that no test pins. The brief asks for tests and mutants for create and send, so each of these is a change. Each fix is a test addition; no source change is needed.\n\n1. **chat.js send target.** Changing the send POST in `packages/webui/src/public/chat.js:232` from `threads/${id}/messages` to `threads/${id}/open` survives `chat-browser.test.mjs`. The fetch stub records `path` for each write, but the tests assert only `body`. Assert the path of each write too, for create project, create thread, send and Resume.\n2. **createThread receipt instance check.** Replacing the `instance` check at `packages/webui/src/chat-http.mjs:105` with `false` survives `chat.test.mjs`. The malformed-receipt cases use only `{}`, which fails the `id` check first. Add createThread receipts `{ id }` with no `instance` and one with an instance that fails `KEY`. Both should give 503 `outcome-unknown` with `sent: 'unknown'`.\n3. **Receipt fields.** Replacing `chat-http.mjs:111` with `const receipt = { ...value };` survives. The comment above that line says only the operation's receipt fields are exposed, but each test answer is exactly the receipt. Give one answer an extra field (for example `owner` or `capability`) and assert the response doesn't carry it.\n4. **Bidi controls.** Dropping `\\u202a-\\u202e\\u2066-\\u2069` from the `inert` class at `chat.js:6` survives `chat-browser.test.mjs`. `HOSTILE` already contains U+202E, but the test only checks the ESC escape. Assert that the rendered project label and message body contain no raw U+202E.\n\n### Ran by me\n\nSlot from sage-0761, on `70504d23a` plus the 15 manifest paths. Busy check CLEAR before and after, manifest checked before and after, TMPDIR in my own scratch, DOCKER_HOST a dead socket.\n\n- Singles, 16:42:28Z to 16:43:03Z: chat.test 20/20, chat-browser.test 11/11, browser.test 1/1, shell.test 5/5, views.test 3/3. Total 40/40, 0 skipped.\n- Mutants, 16:43:03Z to 16:44:02Z: 6 of my own, none of them in Rocko's 64. The controls for chat.test and chat-browser.test pass first. Killed: the repo `KEY` check (chat.test, \"chat validates names, body, project and strict empty open payload\") and the GET/POST method guard (chat.test, \"chat assets, GET purity...\"). The four that survived are listed above.\n\n### Not mine\n\nRocko's receipts (agents/rocko/work/queue-129/r1/): final gate 16:24:07Z, WebUI 177, bus threads 14, CLI thread parity 11, total 202; 64 of 64 mutants killed after the read-array test change; chat-final-shape.log 20/20; named-browser, named-shell and named-views logs 1/1, 5/5 and 3/3.\n","assets":[],"created_at":"2026-10-18T16:44:43Z","updated_at":"2026-10-18T16:44:43Z"}