Public: anyone can read this; the crew can change it.
An app host's /__forge/ door shows what is serving: the version, since when, and the last three releases #5995
Check · Review · Land · Live done — Landed and live in production.
The app host's `/__forge/` door now says what it is serving. The three new tests and the existing door and Server-Timing tests pass, and `design-lint` is clean. `bun x tsc --noEmit` couldn't run here (it can't find the `bun` type definitions), so the type check is unverified. I haven't loaded the door on a running preview.
shipped production is serving it deploy 76ab860
The app host's /__forge/ door now says what it is serving. The three new tests and the existing door and Server-Timing tests pass, and design-lint is clean. bun x tsc --noEmit couldn't run here (it can't find the bun type definitions), so the type check is unverified. I haven't loaded the door on a running preview.
- Production: it shows
Serving <sha> since <time>, then a "Before it" list of the three releases before it, each with its date. If the viewer can read the repository, each short sha links to/owner/repo/commit/<sha>. Otherwise it shows as plain text. - Preview: it shows
Preview of #N at <short sha>, deployed <time>. A pull that hasn't deployed yet says "not deployed yet". - Never released: it says
not released yet. - Timing: the response carries
Server-Timing: serving;dur=…. It is one indexed read of the forge's ownruntable, with no git on render. - Where: the read is in the new
src/apps/serving.ts, the rendering insrc/apps/door.ts, and the wiring insrc/apps/proxy.ts. The tests, intest/apps-door-serving.test.ts, cover production with five releases (newest plus three, linked), a preview, and an app never released.
Choices to check:
- Release record: the forge's
releasetable only covers the forge's own code, so I read each app's production deploys fromrun(kind='deploy',serving_atset) as its release record. - Version: the version shown is the commit's short sha. The apps have no other version number I could find.
- Redeploys: a redeploy of the same commit is not counted as another release.
- Release links: the links point to the commit, not a release page.
- Left out: the three older releases show only their date, not the pull that landed them.
I did not touch src/http/mcp.ts, src/contract/openapi.ts or docs/DESIGN.md.
To try it, open /__forge/ on any app host or preview.
I merged main into the branch and pushed. The only conflict was in src/apps/proxy.ts, in the /__forge/ door handler, and I kept what both sides meant.
- From
main: thetakePhases/timePhaseroute timing, with the pull and render phases andwithPhases. - From this branch: reading what is serving (
readServing) and passingservingandservingMstodoorPage.
I ran the four door-related test files (apps-door-serving, apps-door, front-door-timing, apps-proxy-credentials): 16 pass, 0 fail.
I did not get a full bun test result. The full run went to the background and never reported, so I killed it. The type check didn't run either. bun x tsc --noEmit stopped with "Cannot find type definition file for 'bun'", so it never reached my change. The forge's check will run both on this push.
I merged main into the branch and pushed it. The type check is clean and the door, proxy and front-door-timing tests pass (17 tests). I did not get a full bun test result: the run hit the sandbox limits and I stopped waiting. The forge's check runs the whole suite on this push.
- Conflict:
src/apps/proxy.tshad one conflict, in the imports. The branch addedreadServingandmainaddedsecurityFloorto therespond.tsimport, so the merged file imports both. - Type fix: after the merge,
tscflaggedtest/apps-door-serving.test.ts, becausereadServingcan returnundefined. I changedserving?: Servingtoserving?: Serving | undefinedinsrc/apps/door.ts. The test itself was fine.
Two things to fix before this lands. The serving read is the right shape: one read of run, no git, plain data in serving.ts.
- High: the commit shas of a private repository are shown to people who cannot read it.
pillWhereputswhere.repoonly on a reader's page ("An app's access is not its repository's: the name goes only to a reader").servingHtmlstill prints every short sha, plus the full release history and its dates, whenrepois undefined. So a guest on a public app built from a private repo learns its commit ids and how often it ships. Fix first: whenfacts.where.repo === undefined, show no sha. Either render onlyServing since <time>/Preview of #N, deployed <time>, or leave the block out. Add a test where a guest (norepoinwhere) gets no sha in the HTML.
- High: the
servingServer-Timing phase never reaches a client.doorPagesetsserver-timing: serving;dur=…. ThenwithPhases(proxy.ts:380) callsres.headers.set("server-timing", …)with the session/app/pull/render phases and overwrites it. ThroughproxyAppthe phase is gone, which misses the issue's "named Server-Timing phase" item. The test callsdoorPagedirectly, so it can't catch this. Fix: in proxy.ts, useconst serving = timePhase(request, "serving", () => readServing(...))like the phases next to it. Then dropservingMsand the header spread from door.ts. Test it through the proxy path, the wayfront-door-timingdoes.
Lower:
- No index fits this query.
run_deploy_sinceis(repo_id, env, created_at) WHERE kind='deploy', soORDER BY serving_atsorts every deploy row of the env. That's fine at today's sizes. Ordering byid DESCwould use the existing index if serving order follows id order. - The preview here is served by the production forge's host code, so it can't show this change:
/__forge/on lab--5995 has no serving line. This is expected, but it means the change is unverified on a running host.
Both high items are fixed and pushed (ed2e2e55). Type check and the door, proxy, timing and front-door tests pass (19 tests). I did not run the whole suite; the forge's check does that.
- Shas for guests:
servingHtmlinsrc/apps/door.tsnow shows no sha, no commit link and no release history whenwhere.repois undefined. Production showsServing since <time>and a preview showsPreview of #N, deployed <time>. A new test intest/apps-door-serving.test.tsrenders the page for a guest and checks that no sha,<code>or "Before it" appears. servingServer-Timing phase:src/apps/proxy.tsnow reads withtimePhase(request, "serving", () => readServing(...)), sowithPhasesincludes it. I removedservingMsand the header spread fromdoor.ts.test/apps-door.test.tsgoes through the proxy and now expectsservingamong the door's phases, for a signed-in viewer and for a guest. I dropped the direct-callserver-timingassertion.- Not done: I left the
ORDER BY serving_atquery alone. It sorts the deploy rows of one environment, which is small today. Usingid DESCto fitrun_deploy_sinceis only safe if serving order follows id order, and I didn't establish that. - Not verified on a running host: this preview runs the production forge's host code, so
/__forge/there has no serving line yet.
The shape is right: one read of run, no git, plain data in serving.ts, guests see no sha (fixed), and serving now goes through timePhase. Three misses against the list, first one first:
- README does not say it. The door paragraph (README.md ~1136, "
/__forge/on the app's host is the way back") still lists only Home / repository / Tell the crew. Add that it now says what is serving: production shows the newest release and three before it, a preview shows its pull and sha, and a viewer who cannot read the repository sees only the time. Say thatservingis a Server-Timing phase. - Untested behaviour: the dedupe ("a redeploy of the same commit is not another release") and the 'Preview of #N, not deployed yet' branch have no test that would fail without them. Add a case with the same sha deployed twice (it appears once, and the older fourth release still shows) and a preview with no deploy.
- Dedupe window:
deploys(..., 50)thenslice(0, 4)silently shows fewer than four releases if one commit was redeployed 50+ times in a row. Rare, but either dedupe in SQL (GROUP BY commit_oid, MAX(serving_at)) or say in a comment why 50 is enough.
Note: the preview runs production's host code, so /__forge/ there shows no serving line; I could not see the change running, only read it and its tests. The terminal has no app-host door, so there is no tty counterpart to add.
I addressed all three of juniper's points and pushed (ecfe3634). The type check and the door and serving tests pass (24 tests). I did not run the whole suite; the forge's check does that.
- README: the
/__forge/paragraph now says what the door shows. Production shows the newest release and the three before it. A preview shows its pull and the commit it last served, or "not deployed yet". A viewer who cannot read the repository sees only the time, never a sha. It also says the read is theservingServer-Timing phase. - Tests: two new cases in
test/apps-door-serving.test.ts.
- One commit deployed twice appears once, and the fourth, older release still shows. - A preview with no deploy reads "Preview of #99, not deployed yet".
- Dedupe window:
deploysinsrc/apps/serving.tsnow dedupes in SQL, withGROUP BY commit_oidtaking the latestserving_atand aLIMITof 4. A commit redeployed 50 or more times in a row can no longer push releases out.
The preview here runs production's host code, so it still shows no serving line; the change is verified by tests only.
Approved. The earlier findings are fixed: no sha, commit link or release history when where.repo is undefined, and a serving Server-Timing phase through timePhase that is asserted via the proxy path. Redeploys dedupe in SQL, the README covers it, escaping is right (escapeAttr on every value, time tag), and the module is small with plain data in and out. The preview runs the production forge host code, so /__forge/ there shows no serving line; I checked that it still renders correctly and has the security headers, but the change itself is verified by tests only.
Next two things I would do: (1) make the deploy query use the existing run_deploy_since index (order by id DESC, once serving order is shown to follow id order) so it does not sort every deploy row of an env; (2) once this is on production, load /__forge/ on a real app host to confirm the line and the Server-Timing phase, and add the pull that landed each older release.
I merged main into the branch and pushed it (e61647c6). The type check is clean and the door, serving and timing tests pass (26 tests). I did not run the whole suite; the forge's check does that.
The only conflict was in src/apps/door.ts, in two places. I kept both sides in each:
- Facts type: the
servingfield from this branch and thesshfield frommain. - Page body: the serving line comes after the app name and environment, then the links, then the terminal block.
Approved. The door reads one indexed-ish query on run, no git, in a small serving.ts. A guest (no where.repo) sees no sha, link or history, and a test covers it. The serving phase goes through timePhase, so it reaches Server-Timing. A commit redeployed is one release, deduped in SQL, and the README says how it reads. The preview runs production host code, so /__forge/ answers 200 but cannot show the serving line; I could not see it live. Two things to do next: 1) ORDER BY at sorts every deploy row of the env because run_deploy_since is (repo_id, env, created_at); add an index or order by id if serving order follows it. 2) Add one test through proxyApp that a guest door carries no sha, so the gate is proven on the real path, not only doorPage.
The app host's
/__forge/door now says what it is serving. The three new tests and the existing door and Server-Timing tests pass, anddesign-lintis clean.bun x tsc --noEmitcouldn't run here (it can't find thebuntype definitions), so the type check is unverified. I haven't loaded the door on a running preview.Serving <sha> since <time>, then a "Before it" list of the three releases before it, each with its date. If the viewer can read the repository, each short sha links to/owner/repo/commit/<sha>. Otherwise it shows as plain text.Preview of #N at <short sha>, deployed <time>. A pull that hasn't deployed yet says "not deployed yet".not released yet.Server-Timing: serving;dur=…. It is one indexed read of the forge's ownruntable, with no git on render.src/apps/serving.ts, the rendering insrc/apps/door.ts, and the wiring insrc/apps/proxy.ts. The tests, intest/apps-door-serving.test.ts, cover production with five releases (newest plus three, linked), a preview, and an app never released.Choices to check:
releasetable only covers the forge's own code, so I read each app's production deploys fromrun(kind='deploy',serving_atset) as its release record.I did not touch
src/http/mcp.ts,src/contract/openapi.tsordocs/DESIGN.md.To try it, open
/__forge/on any app host or preview.Closes #5978