A deploy publishes app.serving at the swap-in (src/apps/runtime.ts:681), the same instant its log says serving …, and sseStream forwards every event for the repository to the browser (src/http/sse.ts:203). The studio's live client never listens for it: KINDS in src/web/live.ts:174-181 carries run.queued, run.started and run.finished but not app.serving. Since the deploy run only finishes when its tests end — seconds to half a minute later — a person watching the app page learns that a change is live when the tests are done, not when it started answering. That is the direction's exact moment, and the page misses it.
Acceptance
[ ] app.serving is in the live client's KINDS, and an app.serving event for the app being viewed refreshes the app fragment (refreshApp) the same way a deploy run event does.
[ ] The existing collapse still holds: a burst of run.started, app.serving and run.finished for one push makes at most one fetch in flight and one more queued behind it.
[ ] On a page that is not an app's (a thread, a list), app.serving behaves like any other event — the activity pill, nothing else — and never triggers /app/state.
[ ] A test fails on today's code: the client script served to an app page contains app.serving, and the studio test that drives the fragment covers an app.serving payload shape (app, env, commitOid, servingAt, testsRunning).
[ ] No new dependency, no change to the event's payload, and the fragment's authorization is untouched.
Files I expect to change
src/web/live.ts, test/studio.test.ts (or test/web.test.ts for the script's content).
Risks
isDeploy keys on data.payload.kind === 'deploy', which an app.serving payload does not carry — the new branch must match on the event kind and on payload.app/payload.env instead, and must not make every app event on the forge refresh a page about another app.
A deploy publishes
app.servingat the swap-in (src/apps/runtime.ts:681), the same instant its log saysserving …, andsseStreamforwards every event for the repository to the browser (src/http/sse.ts:203). The studio's live client never listens for it:KINDSinsrc/web/live.ts:174-181carriesrun.queued,run.startedandrun.finishedbut notapp.serving. Since the deploy run only finishes when its tests end — seconds to half a minute later — a person watching the app page learns that a change is live when the tests are done, not when it started answering. That is the direction's exact moment, and the page misses it.Acceptance
app.servingis in the live client'sKINDS, and anapp.servingevent for the app being viewed refreshes the app fragment (refreshApp) the same way a deploy run event does.run.started,app.servingandrun.finishedfor one push makes at most one fetch in flight and one more queued behind it.app.servingbehaves like any other event — the activity pill, nothing else — and never triggers/app/state.app.serving, and the studio test that drives the fragment covers anapp.servingpayload shape (app,env,commitOid,servingAt,testsRunning).Files I expect to change
src/web/live.ts,test/studio.test.ts(ortest/web.test.tsfor the script's content).Risks
isDeploykeys ondata.payload.kind === 'deploy', which anapp.servingpayload does not carry — the new branch must match on the event kind and onpayload.app/payload.envinstead, and must not make every app event on the forge refresh a page about another app.Suggested: Torque.