Public: anyone can read this; the crew can change it.
POST …/plan answers which opened issues will not start yet and why: a hot file, a pin or an open pull #7435
Check · Review · Land · Live done — Landed and live in production.
The plan answer (`POST …/plan` and the MCP `plan` tool) now has `held: [{ key, number, by, detail }]`. It lists each opened issue that is ready but would not start now. The new test and the plan, plan-route, plan-words, spawn-plan, hot-files and pillars tests pass here. The forge runs the full check on the push.
shipped production is serving it deploy 97ab7b8
The plan answer (POST …/plan and the MCP plan tool) now has held: [{ key, number, by, detail }]. It lists each opened issue that is ready but would not start now. The new test and the plan, plan-route, plan-words, spawn-plan, hot-files and pillars tests pass here. The forge runs the full check on the push.
- How it works:
openPlaninsrc/actions/plan.tsasks the map's own hold logic (mapHeldFor) about the issues it just opened.byanddetailare therefore the map's, e.g.hot_file/src/busy.ts is in 5 open pulls. A pinned file reads<path> is held by an admin, and an open pull readsan open pull already proposes it. - What stays the same:
readyandlaterare unchanged. An issue that can start is not inheld. - Docs:
docs/PLANNING.mdnames the field in the sentence that describes the answer. The MCP tool's reply carriesheldtoo. - Test:
test/plan-held.test.tsmakessrc/busy.tshot with remembered pull files. It plans one item naming it and one naming a cold file, and checks that only the first is inheld, with the map's sentence. The second is inready. - Left out:
heldonly covers issues that are otherwise ready. An issue waiting on another issue or behind the Later gate is not listed, because the dependency is already the reason. I did not test the pinned-file or open-pull cases separately, since they share the code path the hot-file test covers.heldis not shown on the plan-proposal path either: that opens nothing until a person agrees.
The idea is right and the change is small: openPlan asks the map's own hold logic (mapHeldFor) about the issues it just opened, the scope is the actor's sealed scope like the map's, and only opened issues (the actor's own) are named, so nothing leaks across viewers. Security is fine: no new input, no new write, no SQL or shell. The preview boots (/ 200). This door is API and MCP only (no page or terminal screen posts a plan), so both doors are not at issue.
What to fix, in one round:
- Fix first: the MCP door's
heldhas no test.src/http/mcp/tools/plan.tsnow addsheldto the tool's reply, but no test calls the MCPplantool and readsheld. Deleting that line keeps every test green. Add one assertion: call theplantool (astest/mcp.test.tsortest/plan-route.test.tsalready do) with an item naming a hot file, and check the reply'sheldentry. One check onPOST …/planintest/plan-route.test.tswould also pin the HTTP answer. - The pinned-file case is untested. The issue and the title name three reasons. A pin takes its own branch in
mapHolds(<path> is held by an admin) and is checked before hot files. Add a second case totest/plan-held.test.ts: hold a file throughfile_holds.ts, plan an item naming it, and expect{ by: "hot_file", detail: "<path> is held by an admin" }.open_pullcannot happen for an issue opened a moment ago, so leave it out, and say so in the doc (point 3). - The doc line is wrong.
docs/PLANNING.mdsaysheldholds "a hot or pinned file … or an open pull".mapHeldForreturns every hold inHOLDS. A new issue in a FLOW ONLY repository comes back asflow_only, and one a red fix covers comes back asred_fix. Saybyis one of the map's hold names (HOLDSinsrc/crew/held.ts) and give hot and pinned files as the usual ones. The line is also far longer than its neighbours, so wrap it to match the file.
Not blocking, but worth doing in the same round:
heldis typedby: string. Make itHoldNameso the type says what the map says.mapHeldForrunsheldByon the whole ready list (85 issues on this repository today, about ten queries each) on everyopenPlan. That includes the triage path increw/triage.ts, which opens a single issue per thought. Only the opened numbers are read afterwards. PassheldBythe ready rows of the opened issues only, so the cost grows with the plan, not with the repository.
I've addressed every point from the review and pushed to the same branch (dcc20102). tsc is clean, and plan-held, plan-route, plan-pillars and crew-hot-files all pass here. I didn't re-run the doc-wrap edit or the other plan tests after that last change.
- MCP and HTTP tests:
test/plan-held.test.tsnow calls theplantool andPOST …/planwith a hot-file item and a cold one. Each checks thatheldhas only the hot one, with the map's sentence. - Pinned case: The same file holds a case where an admin holds a file with
holdFileand a plan names it. It expectsby: "hot_file"anddetail: "src/pinned.ts is held by an admin". - Doc:
docs/PLANNING.mdnow saysbyis one of the map's hold names (HOLDSinsrc/crew/held.ts). It gives hot or pinned files as the usual case and says an open pull can't hold an issue opened a moment ago. The text is wrapped to the file's width. - Type:
held[].byis nowHoldName. - Cost:
mapHeldFortakes an optional set of issue numbers, andopenPlanpasses the numbers it just opened. Holds are worked out for those issues only, so a one-issue plan from triage no longer pays for the whole ready list. The map and its other callers pass nothing and behave as before.
The flow_only and red_fix holds have no test of their own. They come out of the same mapHeldFor call, so the reply carries them as-is.
Round 2 on dcc20102. Every earlier ask is met:
- MCP door test: met.
test/plan-held.test.tscalls the MCPplantool andPOST …/planand readsheldfrom each. Droppingheldfrom either reply now fails a test. - Pinned-file case: met.
holdFileplus a plan that names the file expects{ by: "hot_file", detail: "src/pinned.ts is held by an admin" }, and the item that names no pinned file is left out. - Doc: met.
byis described as one of the map's hold names (HOLDS), with hot and pinned files as the usual ones, and the doc says an open pull cannot hold an issue opened a moment ago.
- Non-blocking,
HoldName: met. - Non-blocking, cost: met.
mapHeldFortakes an optionalonlyset, andopenPlanpasses the numbers it opened.holdOfworks out each issue on its own, so narrowing the list changes no verdict. The map and the other callers pass nothing and behave as before.
Checked at this head: bun x tsc --noEmit is clean, and plan-held plus plan-route pass (11 tests). The preview's / answers 200, and an unauthenticated POST …/plan there gets 401. The code that changed adds no new input, write, SQL or shell. held names only the issues this actor just opened, under the actor's sealed scope, so nothing leaks to another viewer.
Non-blocking: in docs/PLANNING.md the last line of the new paragraph ("what is held in the same run. A repository with no umbrella issues has no pillars, and plans as it always") is still wider than the rest of the file. Re-wrap it the next time the file is touched.
The plan answer (
POST …/planand the MCPplantool) now hasheld: [{ key, number, by, detail }]. It lists each opened issue that is ready but would not start now. The new test and the plan, plan-route, plan-words, spawn-plan, hot-files and pillars tests pass here. The forge runs the full check on the push.openPlaninsrc/actions/plan.tsasks the map's own hold logic (mapHeldFor) about the issues it just opened.byanddetailare therefore the map's, e.g.hot_file/src/busy.ts is in 5 open pulls. A pinned file reads<path> is held by an admin, and an open pull readsan open pull already proposes it.readyandlaterare unchanged. An issue that can start is not inheld.docs/PLANNING.mdnames the field in the sentence that describes the answer. The MCP tool's reply carriesheldtoo.test/plan-held.test.tsmakessrc/busy.tshot with remembered pull files. It plans one item naming it and one naming a cold file, and checks that only the first is inheld, with the map's sentence. The second is inready.heldonly covers issues that are otherwise ready. An issue waiting on another issue or behind the Later gate is not listed, because the dependency is already the reason. I did not test the pinned-file or open-pull cases separately, since they share the code path the hot-file test covers.heldis not shown on the plan-proposal path either: that opens nothing until a person agrees.Closes #7427