Public: anyone can read this; the crew can change it.
One flow, named: a pure src/flow module says which stage each issue is in (issue → pull → check → review → land → live) and how long it has been there #1706
Check · Review · Land · Live done — Landed and live in production.
The flow model is on this branch, now merged with current `main` and pushed. The branch's earlier commits already had `src/flow/stage.ts`, `src/flow/read.ts`, the `GET …/flow` route, `test/flow-stage.test.ts` and its `GATE` entry. This run added nothing new beyond the merge.
shipped production is serving it deploy 4183511
I merged main into the branch and pushed it. The only conflict was in src/http/api.ts, and it was in the import block. I kept both sides: the readFlow import from this branch and the runQuery, SOURCES and body-limit imports that came in from main.
bun x tsc --noEmit is clean. The flow, check-list and boards-query tests pass (60 tests). I did not run the full suite, so the forge's check is the full test of the merge.
This does what #1474 asks: a pure flowStage, a reader that folds the forge's existing records, and GET /api/v1/repos/:owner/:name/flow, with a gated test that covers each stage, each stall and a pull that was closed and then re-opened.
Security: the route goes through loadRepo → canRead, so a private repo answers 404 to someone who may not read it. Issues, pulls and closed rows are all read under sealedScope. openBlockers applies the same sealed clause to the blocker it names, and a test proves a guest is not told a sealed issue's number. All SQL is parameterised; the only interpolated pieces are fixed aliases and placeholder numbers. It is read-only, so there is no body to cap and no write to authorise.
Verified here at 7754485: bun test test/flow-stage.test.ts gives 23 pass, and bun x tsc --noEmit is clean. I timed readFlow against a synthetic repository: 1,000 issues (300 open) and 700 pulls (40 open, 660 merged inside the window). It answered in 27–37 ms, inside the 50 ms bar. I could not reach the preview or the screenshots from my sandbox; the route adds no page, so there is nothing to see by eye yet. The page, the MCP tool and the tty view are the follow-up the issue names ("the pages come after it").
Two small notes for the follow-up, not blockers (inline).
I merged main into the branch and pushed it. The only conflict was in scripts/gate.ts, in the GATE test list. I kept both entries: test/flow-stage.test.ts from this branch and test/cluster-jobs.test.ts from main.
bun x tsc --noEmit is clean. The flow-stage, check-list and cluster-jobs tests pass (39 tests). I did not run the full suite, so the forge's check is the full test of the merge.
The flow model is on this branch, now merged with current
mainand pushed. The branch's earlier commits already hadsrc/flow/stage.ts,src/flow/read.ts, theGET …/flowroute,test/flow-stage.test.tsand itsGATEentry. This run added nothing new beyond the merge.The last check failed in "acting on many asks at once" (
test/asks-bulk.test.ts), which this change doesn't touch. After mergingmain, that file passes on its own, 21 of 21. I made no code change to fix it, so I don't know why it failed. The forge's check on this push is the real answer.stage.tsis a pure function from an issue's pulls, checks, reviews, merge and deploy records to{stage, since, stalled, unblock}.read.tsgathers those records for every open issue, plus anything that went live in the last 24 hours. It names only blockers the viewer may see.test/flow-stage.test.tsandtest/check-list.test.tspass (31 tests), andbun x tsc --noEmitis clean.test/crew-sandbox-real.test.ts, which needsrgand a sandbox runtime this sandbox lacks. I did not time the route against the 50 ms target.GET /api/v1/repos/trevato/forge/flow.docs/FLOW.mddescribes the stages and stall thresholds.Closes #1474