Intent.AGENTS.md promises the terminal is an equal door: "what a person can do on the page they can do here", and "a write made there reaches web viewers live like any other". The first half is true. The second is not: the bus in src/live.ts is a set of listeners in one process, and src/tty.ts is another process. emit there announces to nobody. A host who opens a table over ssh watches a lobby that stays a reload behind, and so does everyone else's.
It is the one place the doors are unequal, and it is a promise in writing rather than a missing feature, which is why it is a bug and not an idea.
Done looks like
[ ] A write from src/tty.ts wakes an open page as fast as the same write over HTTP does — same event type, same address-only payload, same data-live refresh.
[ ] The bus stays the app's own: no broker, no dependency, and no second copy of the rule in src/live.ts. The sqlite database under FORGE_APP_DATA is already the state both processes share; a table of events the server tails, or a socket in the data directory, is the shape to weigh — say in the pull which was chosen and why.
[ ] Replay still works across the seam: a client reconnecting with Last-Event-ID hears what a terminal write did while it was away, numbered in the same sequence as everything else. Ids cannot be a per-process counter if two processes emit.
[ ] The payload rule holds unchanged: an event's data is an identifier, never content, and notAnAddress is still the one place that says so.
[ ] A test that fails without it: emit from a second process (Bun.spawn, as src/server.test.ts already does for the production path) and assert the first process's /events stream delivers it.
[ ] AGENTS.md and the module comment in src/live.ts lose the sentence that excuses the gap ("the terminal is another process, and its writes show on the next load rather than live"), because it is no longer true.
Worth knowing. Found while reviewing #51. Best done after #42, which changes emit's signature to take a topic — a cross-process bus wants to carry the topic from the start rather than be rewired twice.
Intent.
AGENTS.mdpromises the terminal is an equal door: "what a person can do on the page they can do here", and "a write made there reaches web viewers live like any other". The first half is true. The second is not: the bus insrc/live.tsis a set of listeners in one process, andsrc/tty.tsis another process.emitthere announces to nobody. A host who opens a table over ssh watches a lobby that stays a reload behind, and so does everyone else's.It is the one place the doors are unequal, and it is a promise in writing rather than a missing feature, which is why it is a bug and not an idea.
Done looks like
src/tty.tswakes an open page as fast as the same write over HTTP does — same event type, same address-only payload, samedata-liverefresh.src/live.ts. The sqlite database underFORGE_APP_DATAis already the state both processes share; a table of events the server tails, or a socket in the data directory, is the shape to weigh — say in the pull which was chosen and why.Last-Event-IDhears what a terminal write did while it was away, numbered in the same sequence as everything else. Ids cannot be a per-process counter if two processes emit.datais an identifier, never content, andnotAnAddressis still the one place that says so.Bun.spawn, assrc/server.test.tsalready does for the production path) and assert the first process's/eventsstream delivers it.AGENTS.mdand the module comment insrc/live.tslose the sentence that excuses the gap ("the terminal is another process, and its writes show on the next load rather than live"), because it is no longer true.Worth knowing. Found while reviewing #51. Best done after #42, which changes
emit's signature to take a topic — a cross-process bus wants to carry the topic from the start rather than be rewired twice.