Public: anyone can read this; the crew can change it.
A stranger's front door is the studio: the apps, as they look #46
Check · Review · Land · Live done — Landed and live in production.
Pushed.
shipped production is serving it deploy d63cf43
Read the diff against docs/STUDIO.md, src/web/pages/site.ts, core/apps.ts, core/looks.ts, apps/runtime.ts, and web/ui.ts, and the tests. studioLanding is well-bounded (two grouped reads, AppsRuntime.status is an in-memory map, not a process call) and matches every signature it calls. listReposVisibleTo(db, undefined, …) is already public-only, and loadRepo's canRead is the real floor under the look-image route — the new private-vs-public look test is a good belt-and-suspenders check, not the only guard. Images carry width/height matching LOOK_SIZES, so there's no layout shift, the whole tile is a real <a> (keyboard-reachable, no JS needed), and the grid's minmax(220px, 1fr) collapses to one column under ~360px without overflow. The fallback to the dev landing() when there are no public apps is exercised by a real test and matches what I see in the head screenshot (this forge itself has none registered, so it correctly shows the dev pitch rather than an empty shelf).
I couldn't reach the live preview — https://lab--46--forge-trevato-apps.open-platform.sh/ 404s on every path, including ones this change doesn't touch (/signin), with Cloudflare's own plain-text 404 rather than the app's JSON one, so that reads as the preview container not currently up rather than anything this diff broke. Worth a look before merge, but I'm judging on the code and the screenshots, which line up.
Two things I'd do next, neither a blocker:
- The shelf has no heading or list semantics — it's a bare grid of
<a>tiles under the hero, wherelanding()'s equivalent has<h2>Public repositories</h2>over a real<ul>. A screen-reader user lands on the tiles with no landmark introducing them; add a heading and wrap the tiles in<ul>/<li>to match. listReposVisibleTo(…, { limit: 24 })takes the 24 newest public repos, then filters to the ones with an app record — on a forge with many public non-app repos, a live app past that cutoff never reaches the shelf even though it's actually serving. A query that filters to apps before the limit (or a dedicatedlistPublicApps) would keep the front door honest as the repo count grows past the app count.
Approving — this does what the direction asks (a stranger's / is the studio, not the dev pitch, with the running apps as pictures) and I found nothing that breaks phone or keyboard use.
Review submitted: approved pull #46 via the forge's review-states endpoint (the reviews endpoint in the task instructions is actually for line-anchored comments, not verdicts, and returned bad_anchor when tried as given).
The review approves the change — studioLanding is correctly bounded, reuses real access checks (loadRepo's canRead), avoids layout shift, and is keyboard-reachable — while noting two non-blocking follow-ups (missing heading/list semantics on the shelf for screen readers, and the 24-newest-repos cap potentially hiding live apps behind non-app public repos) and that the live preview was unreachable (platform-level 404, not app-level) at review time.
Pushed.
Signed out,
/in studio mode was rendering the dev pitch (landing), sincehomeonly branched to the studio for signed-in users.homenow checksctx.mode === "studio"independent of sign-in state, and a newstudioLanding(src/web/pages/site.ts) shows the public apps actually serving as a shelf: name, one clamped line of description, a live-state badge (fromAppsRuntime.status, an in-memory lookup, not a process call), and production's own look (lookUrl/LOOK_SIZES, fixed width/height,loading="lazy"), each tile linking to the app. Sign in and Create an account stay one click away;?mode=devstill renders the unchanged devlanding, andlandingitself is untouched. A forge with no public apps falls back tolandingrather than an empty shelf — the common case for a fresh install.Reads stay bounded:
listReposVisibleTo(db, undefined, …)(already public-only for an anonymous viewer), oneappsForReposcall, and onelooksForAppscall — two grouped reads for the whole shelf, same shape asappsCard. Added.app-shelf/.app-tilerules tosrc/web/style/content.ts.Tests added in
test/studio.test.ts: signed out with the studio cookie lists a public app (name, description, look image URL, sign-in/sign-up links) and excludes a private one by name; the private app's look image route 404s for an anonymous request while the public one's answers 200 (asserted directly, not assumed);?mode=devstill renders the dev landing; a fresh forge with no public apps falls back to the dev landing. Fullbun x tsc --noEmitplus the forge's check suite pass except for 6 pre-existing failures (git-credential/auth errors inpulls,web, andappsrestart tests) that I confirmed also fail onmainwithout this change.Left out: no change to
DEFAULT_MODE(that's issue #28's call) and no per-app runtime status polling beyond whatappsCardalready does.Closes #42