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

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

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

opened this

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: openPlan in src/actions/plan.ts asks the map's own hold logic (mapHeldFor) about the issues it just opened. by and detail are 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 reads an open pull already proposes it.
  • What stays the same: ready and later are unchanged. An issue that can start is not in held.
  • Docs: docs/PLANNING.md names the field in the sentence that describes the answer. The MCP tool's reply carries held too.
  • Test: test/plan-held.test.ts makes src/busy.ts hot with remembered pull files. It plans one item naming it and one naming a cold file, and checks that only the first is in held, with the map's sentence. The second is in ready.
  • Left out: held only 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. held is not shown on the plan-proposal path either: that opens nothing until a person agrees.

Closes #7427

commented

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: openPlan in src/actions/plan.ts asks the map's own hold logic (mapHeldFor) about the issues it just opened. by and detail are 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 reads an open pull already proposes it.
  • What stays the same: ready and later are unchanged. An issue that can start is not in held.
  • Docs: docs/PLANNING.md names the field in the sentence that describes the answer. The MCP tool's reply carries held too.
  • Test: test/plan-held.test.ts makes src/busy.ts hot with remembered pull files. It plans one item naming it and one naming a cold file, and checks that only the first is in held, with the map's sentence. The second is in ready.
  • Left out: held only 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. held is not shown on the plan-proposal path either: that opens nothing until a person agrees.
Changes requested — before the latest push

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:

  1. Fix first: the MCP door's held has no test. src/http/mcp/tools/plan.ts now adds held to the tool's reply, but no test calls the MCP plan tool and reads held. Deleting that line keeps every test green. Add one assertion: call the plan tool (as test/mcp.test.ts or test/plan-route.test.ts already do) with an item naming a hot file, and check the reply's held entry. One check on POST …/plan in test/plan-route.test.ts would also pin the HTTP answer.
  2. 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 to test/plan-held.test.ts: hold a file through file_holds.ts, plan an item naming it, and expect { by: "hot_file", detail: "<path> is held by an admin" }. open_pull cannot happen for an issue opened a moment ago, so leave it out, and say so in the doc (point 3).
  3. The doc line is wrong. docs/PLANNING.md says held holds "a hot or pinned file … or an open pull". mapHeldFor returns every hold in HOLDS. A new issue in a FLOW ONLY repository comes back as flow_only, and one a red fix covers comes back as red_fix. Say by is one of the map's hold names (HOLDS in src/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:

  • held is typed by: string. Make it HoldName so the type says what the map says.
  • mapHeldFor runs heldBy on the whole ready list (85 issues on this repository today, about ten queries each) on every openPlan. That includes the triage path in crew/triage.ts, which opens a single issue per thought. Only the opened numbers are read afterwards. Pass heldBy the ready rows of the opened issues only, so the cost grows with the plan, not with the repository.
commented

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.ts now calls the plan tool and POST …/plan with a hot-file item and a cold one. Each checks that held has only the hot one, with the map's sentence.
  • Pinned case: The same file holds a case where an admin holds a file with holdFile and a plan names it. It expects by: "hot_file" and detail: "src/pinned.ts is held by an admin".
  • Doc: docs/PLANNING.md now says by is one of the map's hold names (HOLDS in src/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[].by is now HoldName.
  • Cost: mapHeldFor takes an optional set of issue numbers, and openPlan passes 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.

Approved

Round 2 on dcc20102. Every earlier ask is met:

  1. MCP door test: met. test/plan-held.test.ts calls the MCP plan tool and POST …/plan and reads held from each. Dropping held from either reply now fails a test.
  2. Pinned-file case: met. holdFile plus 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.
  3. Doc: met. by is 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. mapHeldFor takes an optional only set, and openPlan passes the numbers it opened. holdOf works 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.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs