I2487 — A screen is streamed, and one stream tells an open page which readings changed
Send a screen as it becomes known and keep it current without polling: the shell and every panel whose reading is at hand are written at once, a panel whose first reading is pending follows on the same response, and after that one WebSocket subscription tells the page which readings changed.
READY wave 2 · p1 · implementation profile · runs alone
Part of development-runtime — The runtime has a development surface.
Ready. Every dependency is done, so majordomus plan start I2487 will be accepted.
Objective
Send a screen as it becomes known and keep it current without polling: the shell and every panel whose reading is at hand are written at once, a panel whose first reading is pending follows on the same response, and after that one WebSocket subscription tells the page which readings changed.
Why
ADR 0142, part 2. After I2486 a screen no longer waits for a source it has read before, but a first reading is still waited for whole, and an open page learns of a change by reading itself again on a timer (60 s, or the catch-up re-read). The owner asked for a streamed UI. ADR 0033 made /events a WebSocket with a cursor and refused a second event channel, and the UI-performance batch's live-stream slice gave it paged replay, a heartbeat and a gap check, so the stream to build on exists.
Current state
A response is written whole with its Content-Length (http/server.rs respond; chunking is switched off). The UI's script polls ?fragment every 60 s and, after I2486, re-reads a screen that is catching up. /events carries execution events only, and the UI opens no socket.
Desired state
The router can answer with a body written in parts. A UI screen writes its head, shell and every panel whose reading is at hand first; a panel whose reading is pending is written when it arrives, in document order, so the page is complete without a script and no reader waits for the slowest source to see the rest. capability::readings publishes a typed event when a reading changes (source, input digest, state of the repository), on the event model of ADR 0033; the UI's script holds one subscription per page, with the cursor and gap check the live-stream slice defined, and replaces the panels that name a changed source with the server's rendering of them. The 60 s poll and the catch-up re-read are removed. A page without the script, or without the socket, is still complete and says when it was read.
Scope
- apps/majordomus-cli/src/http
- apps/majordomus-cli/src/ui
- apps/majordomus-cli/src/capability/readings.rs
- share/ui/ui.js
- docs/MAJORDOMUS_UI.md
- test/cases
- .ai/repo/project/issues/I2487.yaml
Dependencies
Acceptance criteria
- The first bytes of a screen whose slowest source is pending arrive before that source answers, and the response ends with that panel in its place
- With scripts off, every screen is complete HTML once the response ends
- A change of a reading reaches a subscribed page as one typed event naming the source, and the page replaces the panels that cite it without reading the whole screen again
- A subscriber that fell behind is told so and reads the screen again; it is never left showing a value it was not told had changed
- The UI's script holds no timer that reads a screen again
Validation
- bin/majordomus plan validate
- cargo test --lib http::
- cargo test --lib ui::
- MJ_TEST_JOBS=2 bash test/run.sh 1097_a_screen_is_streamed
Evidence required
- streamed_response_tests
- reading_changed_event_tests
- a_screen_is_streamed_case_1097
- browser_probe_no_poll
Evidence
None recorded. Every token above needs a command or an artifact behind it before this issue can be completed; narrative is refused.
Timeline
- started
- —
- verified
- —
- completed
- —
Those three fields, the evidence above and the state of the dependencies are all the status is made of. There is no status field to disagree with them.
Canonical record: .ai/repo/project/issues/I2487.yaml. Read it back with majordomus plan show I2487.