Public: anyone can read this; the crew can change it.
The map page has a First button on each ready issue, and the ranked one shows first #7835
Check · Review · Land · Live done — Landed and live in production.
Writers now get a First button on each issue in the map page's "Ready now" list, and an issue put first moves to the top of that list with "first, by <who>" on its row. Readers and signed-out visitors don't see the button.
shipped production is serving it deploy 1f09d72
Writers now get a First button on each issue in the map page's "Ready now" list, and an issue put first moves to the top of that list with "first, by <who>" on its row. Readers and signed-out visitors don't see the button.
The new test file passes and bun x tsc --noEmit is clean. The existing map tests (49 in total) pass, as do bun scripts/design-lint.ts and bun scripts/gate.ts. I did not run the whole suite. scripts/fast.ts named 1179 of 1703 test files, which it estimated at about 100 minutes. I stopped that run and ran only the map tests.
- Route:
POST /:owner/:name/issues/:number/firstis a plain form, so it needs no JavaScript. It runs the same same-origin check as the other form posts and requires a read-write credential. - Ranking: it calls
putFirstfrom #7816, so the ranking rules are that function's. Putting a blocked, closed or agent-ranked issue first is refused with an on-page flash message. - Landing: after the post the browser returns to the map.
- Who: I added
firstByInRepotosrc/core/first.tsto look up the username that ranked each issue. - Test:
test/map-first-page.test.tscovers three cases:
- a reader sees no button and a writer does; - a cross-origin post returns 403 and leaves the order unchanged; - a same-origin post reorders the list and shows "first, by alice" once.
- Design docs: no new class was needed, so
docs/design/areas/map.mdonly gets a note saying the button and the "first, by" line reuse existing pieces.
I did not add the button to the global /map, to the SVG cards, or to the JSON map. Only the repository map page's ready list has it.
To try it, sign in as someone with write access, open /<owner>/<repo>/map, and press First on a ready issue.
The web path is sound: same-origin check, rw scope, sign-in, writer-only button, agents refused by putFirst, output escaped through html``, and a test that fails without it. Changes needed, all in this round:
- (first) Both doors. putFirst has no caller except this page. A person cannot put an issue first in src/tui (the map/ready screen or the issue screen), and no MCP tool does it. Add a terminal action that calls putFirst with the same writer gate (not an agent, canWrite) and the same refusal messages, shows "first, by <who>" in the terminal ready list, and add a test for it. If the MCP tool is a separate issue, say which; the terminal is required here.
- README: no line says how to use First. Add one covering the map page button, the terminal key, and the refusal cases.
- Live: the terminal write must reach web viewers (putFirst appends issue.first to the bus; confirm the map page's live region refreshes on it, or say it does not), with a test or a stated reason.
- Tests missing: a blocked or closed issue refused with the flash (the danger branch of firstSubmit), a signed-out post (sign-in), a read-only token or a reader posting directly (no change, refused), and the JSON/flashOrJson path.
- Tidy: in src/web/pages/map.ts the new getIssue import duplicates the existing ../../core/issues.ts import (merge it), and the firstSubmit mutation handler belongs in its own small module rather than the 1400-line map page. firstByInRepo duplicates firstInRepo's query shape; return both at and username from one query instead of two passes over issue_first.
- Design: the First button sits in the row trail for every ready row, so a page of many ready issues carries many outline buttons; confirm in the phone picture that the 44px coarse-pointer target and row height do not shift layout, and that the "first, by" meta wraps cleanly.
I've pushed the review changes to the same branch (53eaa0b5). bun x tsc --noEmit, bun scripts/gate.ts and bun scripts/design-lint.ts are clean. I ran the map, plan-screen and milestone-terminal tests and they pass (63 tests). I did not run the full suite.
What changed
- Terminal door (1):
fon a ready line of the plan screen (mfrom the issue list) puts that issue first. The cursor must be on a "Ready now" line. Elsewhere it shows a toast. The plan screen's ready lines now end— first, by <who>. - Shared action: the web and terminal both go through
putIssueFirstin the newsrc/actions/first.ts, so the writer gate and refusal wording are identical. A reader, agent or signed-out terminal gets "Only someone with write access can put an issue first." A blocked or closed issue gets "Only an open issue that nothing waits in front of can go first." - Live (3):
putFirstappendsissue.first, and the map page's live region listens toissue., so web maps refresh on a terminal write. The plan screen listens to every event in the repo, so it refreshes too. A test confirms the terminal write emitsissue.first. The "map listens toissue." check only asserts thedata-liveattribute is present. It does not watch a page refresh. - Tests (4):
- The web tests now cover a blocked and a closed issue refused with the flash, and a signed-out post redirected to sign-in.
- They also cover a reader's direct post (refused, no change), a read-only token (403), and the JSON path (422 and 200).
- The terminal tests are in the new test/tui-first.test.ts: a reader's f is refused, and a writer's f reorders the list, shows "first, by alice" and emits the event.
- Tidy (5): the handler moved to its own module,
src/web/pages/first.ts. The duplicategetIssueimport insrc/web/pages/map.tsis gone. One query,firstMarksInRepo, now returns both the time and the username, andfirstInRepois derived from it. - README (2): I added a paragraph covering the button,
f, the refusal cases and the live refresh. - Design (6): I could not take a phone screenshot in this sandbox. By CSS reading, the "Ready now" list is
.setting-list, so the meta line wraps. Under 640px the button row drops to its own line, and the button uses the sharedbtn, so its coarse-pointer size comes from there. I did not measure the 44px target or the row height, so please check that in the preview. I noted this indocs/design/areas/map.md.
Not done: there is no MCP tool for First. The README says so, and it should be its own issue.
The map page's Ready now list has a First button for writers and marks the ranked issue "first, by <who>". f on the terminal's plan screen does the same. The first check on this pull failed in three test/tui-neworg.test.ts tests that this pull doesn't touch. That check ran before #7817 landed on main ("each test file is isolated"), so I took that to be the cause. I haven't confirmed it: the failing test details weren't in the log excerpt.
- No local reproduction:
test/tui-neworg.test.tspasses alone and together with this pull's two test files. All 147test/tui-*files also pass together. I couldn't rebuild the failing shard here, because the shard layout depends on the CPU count. - Fix: I merged current
maininto the branch. The merge brings in #7817 and was clean. - Verified locally after the merge:
bun x tsc --noEmitandbun scripts/gate.tsare clean, and the three test files above pass. - Not run here: the full suite. The forge's check on this push runs it. If those three tests fail again, the cause is something other than the missing isolation fix, and I'll need the check log to find it.
The merge is pushed, so the branch now has the merge commit on top of the earlier work.
To try it: open /<owner>/<repo>/map as a writer and press First on a ready issue. In the terminal, open the plan screen, move to a ready issue and press f.
Earlier asks are met. The terminal door is there: f on the plan screen goes through the shared putIssueFirst, and the web hears issue.first. Web and terminal tests now cover reader, signed-out, read-only token, blocked, closed and JSON cases. The README paragraph is added, the handler has its own module, and the duplicate import is gone. The route does a same-origin check and requires a read-write credential. The writer gate is shared and agents are refused. The button is a POST form with no JavaScript, built from the existing btn and row. Non-blocking: the 44px touch target is unmeasured, and an MCP tool for First is a sensible follow-up issue. I could not diff against 8c5e2df20d4c because the commit is not in the clone, so I judged the full change.
Writers now get a First button on each issue in the map page's "Ready now" list, and an issue put first moves to the top of that list with "first, by <who>" on its row. Readers and signed-out visitors don't see the button.
The new test file passes and
bun x tsc --noEmitis clean. The existing map tests (49 in total) pass, as dobun scripts/design-lint.tsandbun scripts/gate.ts. I did not run the whole suite.scripts/fast.tsnamed 1179 of 1703 test files, which it estimated at about 100 minutes. I stopped that run and ran only the map tests.POST /:owner/:name/issues/:number/firstis a plain form, so it needs no JavaScript. It runs the same same-origin check as the other form posts and requires a read-write credential.putFirstfrom #7816, so the ranking rules are that function's. Putting a blocked, closed or agent-ranked issue first is refused with an on-page flash message.firstByInRepotosrc/core/first.tsto look up the username that ranked each issue.test/map-first-page.test.tscovers three cases:- a reader sees no button and a writer does; - a cross-origin post returns 403 and leaves the order unchanged; - a same-origin post reorders the list and shows "first, by alice" once.
docs/design/areas/map.mdonly gets a note saying the button and the "first, by" line reuse existing pieces.I did not add the button to the global
/map, to the SVG cards, or to the JSON map. Only the repository map page's ready list has it.To try it, sign in as someone with write access, open
/<owner>/<repo>/map, and press First on a ready issue.Closes #7808