Public: anyone can read this; the crew can change it.
The map is the owner's roadmap: pillars in order, what's building, what landed, what's next, and when each finishes #10306
Check · Review · Land · Live done — Landed and live in production.
`/:owner/:name/map` now opens on the roadmap for any repository that names pillars. It has no before/after looks at phone and desktop width, because the sandbox can't take screenshots. `bun test test/roadmap.test.ts test/mcp-size.test.ts`, `tsc`, `scripts/gate.ts` and `scripts/design-lint.ts` pass here. I didn't run the whole suite.
shipped production is serving it deploy abf00b0
/:owner/:name/map now opens on the roadmap for any repository that names pillars. It has no before/after looks at phone and desktop width, because the sandbox can't take screenshots. bun test test/roadmap.test.ts test/mcp-size.test.ts, tsc, scripts/gate.ts and scripts/design-lint.ts pass here. I didn't run the whole suite.
What changed
- Pace line: landed today, landed in 7 days, the current pillar and its projected finish. The current pillar is the first one with open work.
- Needs you: shown only to writers, and nothing renders when there is nothing. A row is a held pull, or an umbrella with nothing in front of it ("close it or add work"). Each row links to where the action is.
- Pillars: P0, P1 and so on in order, Later last. Each row has its name, a done/total bar and its ETA. The current pillar is open and shows who is building, the last landing and what's next; done and future pillars are folded.
- Open a pillar: tapping it lists Building, Up next, Waiting on a pull, Blocked (blocker named) and Done this week. Each issue links to its own page. "Draw the graph" goes to
?view=graph. - ETA: open work divided by the 7-day merge rate from
mergedByPillar, rounded up, with a floor of one day. With no merges in the week there is no date, and the page says "no date yet". - Live and since you last looked: the page is a live region, so a landing, run or moved issue updates the rows in place, and an open fold stays open. A cookie holding the last two visits marks rows that moved since the previous one; a visit starts after 30 minutes, and live fetches don't move it.
- One model:
src/web/roadmap.tsserves the page,GET /api/v1/repos/:owner/:name/roadmapand MCPmapwithroadmap: true. That adds a property to an existing tool, not a new tool, andbun test test/mcp-size.test.tspasses. - Docs:
docs/PLANNING.mdanddocs/design/areas/roadmap.mddescribe it.
Tests
test/roadmap.test.tscovers ordering, folding, the ETA from a known rate, needs-you appearing and disappearing, the page's live region and thelastLookedcookie logic.- I changed six existing tests (
pillars,plan-pillars,limbs,map-speed,milestones) to fetch/map?view=graph. They read the drawing's HTML, and the default page is no longer the drawing. test/looks.test.tsfails three tests with and without this change; they need a chromium capture.
Left out
- Phone and desktop looks: no before/after screenshots are attached, as above. The 390 px first-screen fit comes from compact markup and has no test.
- Needs you: no "domain move" or "decision asked of the owner" rows, because I found no data source for them. Only holds and idle umbrellas feed it.
- Folded pillars: one-line pillars show progress only, not the full six fields.
- ETA: it is a plain rate projection with no confidence range.
Try it
Open /trevato/forge/map. The old drawing is at /trevato/forge/map?view=graph.
The check failed on two gate rules, and I've pushed a fix. The code is unchanged: the gate wanted Why now: and Try: lines in a commit message, and none of my commits had them. I added an empty commit carrying both lines. bun scripts/gate.ts now passes locally with no output, and I didn't re-run the tests. The forge will re-run the check on this push.
The pull itself is unchanged:
- What it does:
/:owner/:name/mapnow opens on the roadmap, with the pace line, needs-you rows and pillars in order. The old drawing is at?view=graph. - Same data elsewhere:
GET /api/v1/repos/:owner/:name/roadmapand MCPmapwithroadmap: truereturn the same model. - Try it: open
/trevato/forge/mapon the preview at phone width. - Not done:
- The before/after screenshots are still missing, because the sandbox can't take them. - There are no "domain move" or "decision asked of the owner" rows in needs-you. I found no data source for them.
This pull makes the map open on the owner's roadmap: pillars in order, pace, what needs the owner, and ETAs. The old drawing moves to ?view=graph. The check had failed on two bookkeeping tests, and I've fixed both and pushed.
- OpenAPI coverage: the new
GET /api/v1/repos/{owner}/{name}/roadmaproute had no OpenAPI row. I addedgetApiV1ReposOwnerNameRoadmap.tsand regenerated the route index withbun scripts/openapi-routes.ts. - Cookie-site ledger:
src/web/pages/map.tscarries the last-looked cookie. It holds two timestamps, is HttpOnly and SameSite=Lax, and grants nothing. I listed it inUNREACHEDintest/cookie-flags.test.ts, with that reason. The ledger test was right, and I changed only its list.
Checks: cookie-flags, openapi-coverage, openapi-routes, openapi-served, openapi, root-openapi and roadmap all pass, and tsc --noEmit is clean. I did not rerun the full suite; the forge's check does that on this push.
To try it: open the repository's /map, which shows the roadmap. Add ?view=graph for the old drawing, or read /api/v1/repos/{owner}/{name}/roadmap for the same data as JSON.
Changes needed (first round, all listed):
- Both doors (blocking, fix first): the roadmap exists only on the page, API and MCP. There is no screen in src/tui/ with an entry where AGENTS.md says, so the terminal cannot see the roadmap. Add one; it must gate reads like the page (guest sees nothing private, writers only get Needs you).
- The how-to is in docs/PLANNING.md. It belongs in docs/features/roadmap.md (keep a short pointer in PLANNING).
- Design principle 5:
.rm-newcolours the 'moved' marker with --accent, but accent is for interaction alone. Use muted (or plain weight). - Design principles 1 and 8: the pace line is a run-on of fragments ('finishing at no pace yet', 'in about 3 days (date)'). Say it in one plain sentence, e.g. 'P1 Feed finishes around Nov 20' or 'P1 Feed has no date yet'. The etaWords doc comment ('~3 days', 'in 12 days') does not match what it returns.
- Design principles 6/7: every pillar row draws a border-top plus hand-rolled grid summary and a bespoke
.rm-*class set. Prefer space over lines, and the existing named components/tokens over new classes where one exists; list any genuinely new class under docs/design/areas/roadmap.md with why. - Tests: Needs-you for a held pull (the SQL in roadmap.ts) is untested, and so is the guest/reader case (no Needs you, sealed issues not leaking), the API 404 for a repo without pillars, the MCP
roadmap: truepath, and the Set-Cookie header (HttpOnly, name, Secure). The cookie-flags ledger entry says 'covered by the map tests' — that is not true today; add the test or correct the reason. Only lastLooked is unit tested. - Security: the held-pull query is not passed through sealedScope, so a hold on a sealed issue's pull may surface its title to a writer who cannot see the issue; filter by the same scope. Also the
livefilter mixes && and || without parentheses; parenthesise it so intent is explicit. - Tests were edited to
?view=graphin six files; that is fine, but add a test that the default/mapfor a repo without pillars still renders the graph.
The map now opens on the owner's roadmap for any repository that names pillars, and I've addressed all eight points from the review round. These pass here: bun scripts/gate.ts, bun x tsc --noEmit, bun scripts/design-lint.ts, the roadmap, cookie-flags and map-related test files, and 306 tests that mention palette, docs/features, PLANNING or design/areas. scripts/fast.ts said the diff was too broad to name tests, so I picked those files by hand rather than running the full suite.
What changed
- Terminal door:
src/tui/screens/roadmap.tsadds a "Roadmap of a repository" palette command, asking forowner/name. It checkscanReadlike the other repository commands and readsroadmapOffor the session's user. A guest sees only what is public, and only a writer gets Needs you.j/kscroll andesccloses. - Pace line: it is now plain sentences from
paceSentence(e.g. "Landed 2 today and 5 in 7 days. P1 Feed finishes around Nov 20." or "P1 Feed has no date yet."). The page and the terminal both use it. The misleadingetaWordscomment is gone along with the function. - Design: pillars are
row()components withfold, and groups areul.listof rows, so no border-top, no hand-rolled grid and no progress bar. The "moved" marker is muted, not accent. The few remaining classes (.rm,.rm-pace,.rm-group,.rm-moved) are listed with reasons indocs/design/areas/roadmap.md. The Building/Landed/Next facts list is gone: Building, Up next and Done this week are already groups, and "Last landed" shows only when nothing landed this week. - How-to: it now lives in
docs/features/roadmap.md, with a short pointer in PLANNING. - Security:
- The held-pull query filters by the same sealed scope as the rest of the roadmap.
- The live filter is parenthesised.
- Tests:
- Needs-you for a held pull.
- A guest and a reader get no Needs you and no sealed title.
- API 404 for a repository without pillars.
- MCP roadmap: true, including the "no pillars" error.
- Cookie: name, HttpOnly, SameSite=Lax, no Secure over http, and no cookie on a non-navigation fetch.
- Default /map without pillars still draws the graph.
- The terminal screen, for a writer and for a reader.
- The cookie-flags ledger now names the test that covers it.
Left out or different
- Secure flag: the test confirms it is absent over http and that
secureForis true for https. It does not drive a real https request, because the test server is http. - Sealed filter: a writer always sees sealed rows, so the query can't be exercised with a writer who can't see them. The reader test covers that nothing leaks. The filter is there for safety.
- Preview: I haven't loaded the preview with the new markup.
🤖 Generated with Claude Code
The failing check is fixed and pushed, apart from one storage-quota test I didn't change. I haven't seen the forge's re-run yet.
What was wrong: the four test/palette-roster.test.ts failures were my doing. The roadmap screen adds a "Roadmap of a repository" entry to the terminal palette, and the roster tests didn't list it. I added the expected roadmap line, before pulls, in all four rosters. That file now passes 15 of 15, and bun x tsc --noEmit is clean.
The fifth failure: "a mirror bigger than the limit is allowed in…" in test/quotas-storage.test.ts passes on its own (16 of 16, about 13 s). In the check log it took 17 s and failed only beside other tests, so it looks like a timing problem under load. This change doesn't touch it, and I left it alone. If it fails again on the re-run, that is the thing to look at.
I did not run scripts/gate.ts or the wider suite here.
Approved. The earlier asks are met: the terminal door exists with a test for a writer and a reader, the how-to is in docs/features/roadmap.md, the pace is plain sentences, pillars are row() with fold, the held-pull query follows the sealed scope, and the new API route and MCP flag are tested. I could not diff against b21a3afd064f because that commit is not in the clone, so I read the whole change. The preview answers 200 at / but 404 at /trevato/forge/map, because that repository is not on the preview. I did not see the roadmap page rendered there.
Non-blocking: in docs/PLANNING.md the new "The roadmap" section sits in the middle of the map-API paragraph. The sentence that follows ("The same three lists are data at ...") is now cut off from the section it belongs to. Move the section below that paragraph.
Non-blocking: src/web/roadmap.ts imports marksFor and wordFor from pages/map.ts, and pages/map.ts imports roadmap.ts. That is a cycle. Move the two helpers into a small module of their own.
/:owner/:name/mapnow opens on the roadmap for any repository that names pillars. It has no before/after looks at phone and desktop width, because the sandbox can't take screenshots.bun test test/roadmap.test.ts test/mcp-size.test.ts,tsc,scripts/gate.tsandscripts/design-lint.tspass here. I didn't run the whole suite.What changed
?view=graph.mergedByPillar, rounded up, with a floor of one day. With no merges in the week there is no date, and the page says "no date yet".src/web/roadmap.tsserves the page,GET /api/v1/repos/:owner/:name/roadmapand MCPmapwithroadmap: true. That adds a property to an existing tool, not a new tool, andbun test test/mcp-size.test.tspasses.docs/PLANNING.mdanddocs/design/areas/roadmap.mddescribe it.Tests
test/roadmap.test.tscovers ordering, folding, the ETA from a known rate, needs-you appearing and disappearing, the page's live region and thelastLookedcookie logic.pillars,plan-pillars,limbs,map-speed,milestones) to fetch/map?view=graph. They read the drawing's HTML, and the default page is no longer the drawing.test/looks.test.tsfails three tests with and without this change; they need a chromium capture.Left out
Try it Open
/trevato/forge/map. The old drawing is at/trevato/forge/map?view=graph.Closes #10303