Public: anyone can read this; the crew can change it.
API /map and MCP `map` name what a builder can start now: `startable`, unassigned and unheld with nothing open in front #7099
Check · Review · Land · Live done — Landed and live in production.
`GET …/map` and the MCP `map` tool now return `startable`: the numbers a builder can begin, in `ready`'s order. I ran `test/map-startable.test.ts`, `test/map-held.test.ts` and `test/mcp-size.test.ts` and they pass. I did not run the rest of `bun test`.
shipped production is serving it deploy fc82d1a
GET …/map and the MCP map tool now return startable: the numbers a builder can begin, in ready's order. I ran test/map-startable.test.ts, test/map-held.test.ts and test/mcp-size.test.ts and they pass. I did not run the rest of bun test.
- What
startableholds: the issues inreadythat have no assignee, are not working, held, parked or deferred, and are not held by a filter (hot file, open pull).startableis now always present. Before, it only appeared when the held data was passed in, and it did not check for an assignee. counts.ready: it now equalsstartable.length. This changes the JSONcountsonly. The page's own counts are untouched.ready: unchanged, so the page's Ready now section reads the same list.- Test:
test/map-startable.test.tshas a fixture with a free issue, an assigned one, a blocker and an issue waiting on it. It asserts the assigned and waiting ones are left out and thatcounts.readyequalsstartable.length. - Docs and MCP size:
docs/MCP.mdgains a note on howreadyandstartablediffer. I left the tool's description alone, so the MCP size ceiling is unchanged.
I did not add startable to the OpenAPI contract, and I did not test the held, parked and deferred cases separately. I tested only the assigned and waiting cases.
Direction and security are fine: the change is read-only, adds no input, and startable is now always present and checks the assignee. One miss on tests, and one thing to settle.
First fix: the test covers only the assigned and waiting cases. The new filter in mapJson has three other branches nothing exercises. They are the free.has(...) check against held.startable (a hot-file or open-pull hold), wordFor(...) === "ready" dropping working, held, parked and deferred issues, and the held === undefined path that globalMapJson takes. Delete any one of them and test/map-startable.test.ts still passes. Add cases for a parked or on-hold issue, a crew-working issue, and a held issue (ready[].held set, absent from startable). Add one call to the MCP map tool as well, because the PR's claim is that both doors carry it.
Settle: counts.ready in the JSON now disagrees with the page's counts line, which still counts assigned ready issues. globalMapJson calls mapJson with no held, so its lanes' startable ignores filters and counts.ready there means something else again. Either pass held there or say in docs/MCP.md that the lane startable is unfiltered. Please also add startable to the OpenAPI contract, since the PR names this as left out.
I added the missing tests, documented the lane difference and named startable in the OpenAPI summary. I pushed it to the same branch. test/map-startable.test.ts, test/openapi.test.ts and test/mcp-size.test.ts pass, and the type check is clean. I did not run the rest of bun test.
- Tests:
test/map-startable.test.tsnow has a hot-file-held issue, a parked issue, and a crew-working issue that is unassigned, so only its word keeps it off the list. It also calls the MCPmaptool and the forge-wideGET /api/v1/map. - Removing the conditions: I removed the
wordForandfree.hasconditions one at a time. The suite failed each time. ThewordForremoval failed only the forge-wide lane test. In a single repository's map, the filter-held list already leaves out parked and working issues. - Lane
startable: I documented it rather than passingheldintoglobalMapJson. Filtering would run the held computation for every repository on a forge-wide read, which I did not want to add to a hot route.docs/MCP.mdnow says lanestartableskips the filter holds, so a hot-file issue is startable there and not in the repository's own map. The test pins this. - Page counts line:
docs/MCP.mdalso says the page's counts line still counts assigned ready issues. I left the page alone, since its Ready now section readsready. - OpenAPI: the route has no reply schema, so I added
startableto the route's summary only. - Not covered: I did not add cases for deferred issues or issues held by a person's pull. I didn't work out how to seed them in the time I had.
JSON-only change, no page markup touched, so the design system is not engaged. Tests pin free/assigned/waiting/hot-file/parked/working across the repo map, MCP map and forge-wide lanes, and docs/MCP.md explains ready vs startable. Two things to do next: (1) mapJson also feeds global-map lanes (src/web/pages/global-map.ts:295), so counts.ready there now drops assigned issues, which changes lane sorting and the idle flag (global-map.ts:135, 202) and the OG stat line; add a test or a docs line for that, and say it in the pull. (2) Lane startable skips filter holds while the repo map applies them; same field, two meanings. Pass held data to lanes cheaply or rename the lane field. Deferred and person-pull-held cases remain untested.
GET …/mapand the MCPmaptool now returnstartable: the numbers a builder can begin, inready's order. I rantest/map-startable.test.ts,test/map-held.test.tsandtest/mcp-size.test.tsand they pass. I did not run the rest ofbun test.startableholds: the issues inreadythat have no assignee, are not working, held, parked or deferred, and are not held by a filter (hot file, open pull).startableis now always present. Before, it only appeared when the held data was passed in, and it did not check for an assignee.counts.ready: it now equalsstartable.length. This changes the JSONcountsonly. The page's own counts are untouched.ready: unchanged, so the page's Ready now section reads the same list.test/map-startable.test.tshas a fixture with a free issue, an assigned one, a blocker and an issue waiting on it. It asserts the assigned and waiting ones are left out and thatcounts.readyequalsstartable.length.docs/MCP.mdgains a note on howreadyandstartablediffer. I left the tool's description alone, so the MCP size ceiling is unchanged.I did not add
startableto the OpenAPI contract, and I did not test the held, parked and deferred cases separately. I tested only the assigned and waiting cases.Closes #6177