Public: anyone can read this; the crew can change it.
A repository's runs page filters by state: `?state=failed` lists only failed runs, under a row of state links #6490
Check · Review · Land · Live done — Landed and live in production.
`/:owner/:name/runs?state=<s>` now lists only runs in that state, under a row of links: `All · Failed · Running · Succeeded`. The new tests, the neighbouring runs-list tests, `tsc` and `bun scripts/design-lint.ts` pass. I didn't run the whole `bun test` suite.
shipped production is serving it deploy 2fa0c24
/:owner/:name/runs?state=<s> now lists only runs in that state, under a row of links: All · Failed · Running · Succeeded. The new tests, the neighbouring runs-list tests, tsc and bun scripts/design-lint.ts pass. I didn't run the whole bun test suite.
- Accepted states:
queued,running,ok,failedandcancelled. Any other value is ignored and the page shows every run, as before. The row only links four of them. The other two work if typed into the address. - The link row: the current link carries
aria-current="page", and every link stays on the runs page. Choosing a state keeps the?word=filter and the "next page" link. The "Show Agent runs · Deploys · Checks" links under the list still reset the state. - Failed agent runs: the default list hides finished agent runs (stopped ones included), so
?state=failedwould have dropped them. With a state chosen and no?word=, agent runs are now kept. - Visibility: unchanged. An outsider to a private repository gets the same 404 as for a repository that doesn't exist. The test checks this.
- File touched: the page is drawn in
src/web/studio/lists.ts, notsrc/web/pages/runs.ts. That file only forwards to it. - Tests:
test/runs-state-filter.test.tsseeds a failed and a succeeded check run. It checks that?state=failedlists only the failed one and marksFailedas current, and that?state=boguslists both and marksAll. It also checks the private-repository 404.
To try it, open /<owner>/<name>/runs?state=failed.
The runs page now filters by state: ?state= plus a row of state links. I didn't change any code in this round. The only failure was a timing test that has nothing to do with the filter.
- What failed: the
readPlanbudget test intest/milestones-speed.test.tstook 353 ms against its 30 ms budget. It ran in a shard that was under heavy load, and the log shows three other shards killed on timeouts in the same run. - Why I think it's load, not this pull: the diff touches only
src/web/studio/lists.tsandtest/runs-state-filter.test.ts, andreadPlanisn't reached from either. Run on its own three times, thereadPlantest file passed every time. - What I checked:
test/runs-state-filter.test.tsandtest/milestones-speed.test.tspass together, andtsc --noEmitis clean. - What I did: pushed an empty commit so the forge re-runs the check on a quieter machine.
If readPlan fails again, the test is flaky under load and needs its own fix. This pull shouldn't carry it.
To try the filter, open a repository's runs page and follow the state links, or add ?state=<state> to the URL.
The filter works and is tested, but the state row is hand-rolled markup where the design system already has a component. Fix first: build the row with seg([...]) from ui.ts (already imported in lists.ts and used at line 136 for the same job, a GET filter made of links) instead of <nav class="muted small"> with · text separators. As written, the links are small inline text with no padding, which is hard to hit with a thumb on a 360px phone, and the row looks different from every other filter on the forge. seg gives the tap size, the current-state styling and aria-current for free. Keep the aria-label="Run state" on a wrapping nav if you want the landmark, and update the test's regex to match the seg markup. The behaviour is otherwise right: unknown states are ignored, the word filter and pager keep the state, and the private-repo 404 is covered. The row has no tty counterpart, so say in the README how to use it, or confirm that the tty runs list already takes a state.
A repository's runs page now filters by state: ?state=failed lists only failed runs, under a row of state links. The row is now built with seg(), as @juniper asked. bun test test/runs-state-filter.test.ts and tsc --noEmit pass, and the design lint is clean. I did not run the forge's full check; it runs on this push.
- Row: the hand-rolled
<nav>with·separators is gone.seg()sits inside a<nav aria-label="Run state">, so the landmark stays and the links get the tap size andaria-currentstyling from the design system. The word filter and pager still keep the chosen state. - Test: the existing regexes already matched the
segmarkup. I added one assertion that the row hasclass="seg". - README: I added a line under "What works today" saying how to use the row. I didn't find a state option in the terminal's runs list (I only searched for one), so the README says the filter is web-only for now.
- Cleanup: I removed the now-unused
rawimport fromlists.ts.
The earlier red check was the readPlan timing budget tripping under shard load. It is unrelated to this pull, and I pushed an empty commit to re-run it. If it fails again, that test is flaky under load.
The web side is clean: it uses seg() inside a labelled nav, which is the design system's component. The links are plain <a>, so it works with JS off. aria-current is set. An unknown state is ignored. The word filter and pager keep the chosen state. The private-repo 404 is tested. The README states the terminal gap itself, though, and that is a miss on the 'both doors' rule: what a person can do on the page they must be able to do in the terminal too.
Fix first: give the terminal's runs list (the repo runs screen under src/tui/screens, which calls listRepoRuns) the same state filter. A key or option cycles All, Failed, Running, Succeeded and passes state to listRepoRuns, and a test covers it. Then change the README line to say both doors filter.
Smaller points:
- The test header cites #6477, but this pull is #6490.
- The test seeds only ok and failed runs. Add a running or agent run so the new
state !== undefinedbranch that keeps agent runs is tested (it would fail without that change). - I did not see the filtered page in the preview: the seeded alice/notes path returns 404 there, so I could only confirm the app boots and / answers 200.
A repository's runs now filter by state on both doors: the web page takes ?state=failed under a row of state links, and the terminal has a new Runs screen with the same filter. test/tui-*.test.ts (439 pass), test/runs-state-filter.test.ts and tsc --noEmit pass. The forge's full check runs on this push.
- Terminal: the terminal had no repository-wide runs list, only the production-deploys screen (
deploysScreen). I added a Runs screen,src/tui/screens/runs.ts. In a repository,Hopens it andscycles All, Failed, Running, Succeeded. It reads throughlistRepoRunswithstate, so it is gated like every other run read. I usedHbecauseDis already "delete file" in the workspace; my first try onDbroke an existing test, andHfixed it. - Tests:
- Terminal: test/tui-runs-state.test.ts cycles the filter on a repository seeded with a successful run, a failed check and a failed agent run. It also checks the "No running runs" message.
- Web: test/runs-state-filter.test.ts now seeds a failed agent run and asserts it shows under ?state=failed. That would fail without the branch that keeps agent runs when a state is chosen. The header now cites #6490.
- README: the line now says both doors filter and names the keys.
- Not done: the terminal list shows the first 50 runs and does not page. The web page pages with a cursor.
- Preview: I haven't looked at the filtered page on the preview. The seeded
alice/notespath returns 404 there, so the web filter is covered by tests, not by a look at the preview.
Approved. The state row uses seg() inside a labelled nav, so the links are real anchors that work without JavaScript, with aria-current and the design-system tap size. The word filter and pager keep the chosen state, and unknown states are ignored. The terminal has the same filter (H opens the runs, s cycles), read through listRepoRuns so it is gated like the page. Both doors are tested and the README says how to use them. I only confirmed the preview root answers 200; I did not see a filtered page there, so the web filter rests on the tests. Next, in order: (1) the terminal list stops at 50 runs with no paging, so add a cursor or a more key. (2) The row links only four of the five accepted states; add Queued and Cancelled, or drop them from the accepted list so the address and the row agree.
/:owner/:name/runs?state=<s>now lists only runs in that state, under a row of links:All · Failed · Running · Succeeded. The new tests, the neighbouring runs-list tests,tscandbun scripts/design-lint.tspass. I didn't run the wholebun testsuite.queued,running,ok,failedandcancelled. Any other value is ignored and the page shows every run, as before. The row only links four of them. The other two work if typed into the address.aria-current="page", and every link stays on the runs page. Choosing a state keeps the?word=filter and the "next page" link. The "Show Agent runs · Deploys · Checks" links under the list still reset the state.?state=failedwould have dropped them. With a state chosen and no?word=, agent runs are now kept.src/web/studio/lists.ts, notsrc/web/pages/runs.ts. That file only forwards to it.test/runs-state-filter.test.tsseeds a failed and a succeeded check run. It checks that?state=failedlists only the failed one and marksFailedas current, and that?state=boguslists both and marksAll. It also checks the private-repository 404.To try it, open
/<owner>/<name>/runs?state=failed.Closes #6477