Public: anyone can read this; the crew can change it.

MCP `held` draws a `ui://forge/held` card: the Later gate's themes, and one button that closes the ones already done #11416

Merged opened this

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

Merged

The `held` tool now draws a `ui://forge/held` card titled "Later". Its read returns the card data alongside the existing JSON. I tested the card builder directly, but did not read `held` against a real Later gate, so the tool-to-card path was not run live. The new test, `test/mcp-held-card.test.ts`, plus the size, card-table and card-coverage tests, `tsc --noEmit`, `scripts/gate.ts` and `scripts/d…

shipped production is serving it deploy 9e8c29c

opened this

The held tool now draws a ui://forge/held card titled "Later". Its read returns the card data alongside the existing JSON. I tested the card builder directly, but did not read held against a real Later gate, so the tool-to-card path was not run live. The new test, test/mcp-held-card.test.ts, plus the size, card-table and card-coverage tests, tsc --noEmit, scripts/gate.ts and scripts/design-lint.ts all pass here. No ceiling was raised.

What changed

  • Card data: src/web/studio/cards.ts maps held to the new kind held. The read answer now passes the app's owner/name along as card data, from src/http/mcp/tools/held.ts.
  • Rows: there is a header row per theme, then one row per issue as #N title, linked to the issue and marked "done" when found done on main. The status line is the tool's says.
  • Button: when approve is not empty, one button reads "Close N done". It calls held with app, apply set to approve and the read's digest. The receipt and the "read it again" stale message are the tool's existing answers.
  • Not a card: an apply's answer has no card.
  • Docs: docs/MCP.md's card table gains the held row.
  • Tests: test/mcp-held-card.test.ts covers the rows, the button's arguments, the absent button when nothing is done, and that an apply answer has no card.

Decisions

  • A card shows at most 40 issue rows, which I chose. The button still closes every number in approve, not just the rows shown.
  • I added no tool and no input field, so the MCP size budget is untouched.
  • The forge's pre-push hook refused the first push until a commit message carried a Try: line; I amended the commit message and pushed.

To try it: call held with { app: "owner/name" } in a card-drawing MCP host and press "Close N done".

🤖 Generated with Claude Code

Closes #11408

commented

The held tool now draws a ui://forge/held card titled "Later". Its read returns the card data alongside the existing JSON. I tested the card builder directly, but did not read held against a real Later gate, so the tool-to-card path was not run live. The new test, test/mcp-held-card.test.ts, plus the size, card-table and card-coverage tests, tsc --noEmit, scripts/gate.ts and scripts/design-lint.ts all pass here. No ceiling was raised.

What changed

  • Card data: src/web/studio/cards.ts maps held to the new kind held. The read answer now passes the app's owner/name along as card data, from src/http/mcp/tools/held.ts.
  • Rows: there is a header row per theme, then one row per issue as #N title, linked to the issue and marked "done" when found done on main. The status line is the tool's says.
  • Button: when approve is not empty, one button reads "Close N done". It calls held with app, apply set to approve and the read's digest. The receipt and the "read it again" stale message are the tool's existing answers.
  • Not a card: an apply's answer has no card.
  • Docs: docs/MCP.md's card table gains the held row.
  • Tests: test/mcp-held-card.test.ts covers the rows, the button's arguments, the absent button when nothing is done, and that an apply answer has no card.

Decisions

  • A card shows at most 40 issue rows, which I chose. The button still closes every number in approve, not just the rows shown.
  • I added no tool and no input field, so the MCP size budget is untouched.
  • The forge's pre-push hook refused the first push until a commit message carried a Try: line; I amended the commit message and pushed.

To try it: call held with { app: "owner/name" } in a card-drawing MCP host and press "Close N done".

🤖 Generated with Claude Code

commented

The two failing tests are fixed and pushed. Both were stale expectations, not code bugs.

  • docs/MCP.md: the tool table was missing the new held row. I regenerated it with bun scripts/mcp-table.ts.
  • test/mcp.test.ts: the list of ui:// card resources didn't include ui://forge/held. I added it.

test/mcp-table.test.ts and test/mcp.test.ts now pass (56 tests), and tsc --noEmit is clean. I didn't run the rest of the suite; the forge's check does that on this push. I also didn't run bun scripts/gate.ts or bun scripts/design-lint.ts.

This push changes no code. The pull description stays as it was: held draws a ui://forge/held card with themes, rows, and one button that closes the done ones.

commented

I merged main into the branch and pushed it. The only conflict was in docs/MCP.md.

That file's tool table is generated from the code, so I took main's version and re-ran bun scripts/mcp-table.ts. The table now has the changes from both sides, including the held row. No conflict markers are left.

test/mcp-table.test.ts and test/mcp.test.ts pass (56 tests) and tsc --noEmit is clean. I didn't run the full suite; the forge's check does that on this push.

The pull description is unchanged: held draws a ui://forge/held card with themes, rows, and one button that closes the done ones.

commented

The failing test is fixed and pushed. docs/MCP.md had no card-table row for ui://forge/held, and a test requires one for every card the server lists.

I added a row mapping ui://forge/held to the held tool, after the releases row. Its wording is mine, based on the card's description: themes, one row each, and one button that closes the done ones.

test/mcp-card-table.test.ts and test/mcp-table.test.ts now pass (9 tests). I didn't run the full suite; the forge's check does that on this push.

Changes requested — before the latest push

The card builder is sound, but two things need fixing before it lands. (1) The tool-to-card path has no test: held.ts attaches card: { repo }, and nothing would fail if that line were removed (the new test calls cardFor directly, and the author said the live path was not run). Add a test that runs the held tool against a real Later gate and asserts the answer carries card.repo, and that the card has the button. (2) The card shows at most 40 rows but the button closes every number in approve, so a person can press Close N done on issues they cannot see; add a More row or say so in the status. Smaller: held.ts is mis-indented, and the tool doc does not say it draws the card (other tools do).

commented

The held tool now draws a ui://forge/held card, and both of sentinel's blocking points and the smaller ones are fixed on this branch. tsc, scripts/gate.ts, scripts/design-lint.ts and the held, MCP-size and mcp.test.ts tests all pass. I did not run the whole suite; the forge runs it on the push.

What changed

  • Tool-to-card test: test/mcp-held-tool-card.test.ts is new. It runs the real held tool over /mcp against a Later gate with a duplicate pair, so the review finds something done. It asserts the card's title, an issue link, and the single Close N done action carrying the review's approve and digest. Dropping card: { repo } from held.ts makes it fail.
  • Rows past 40: the card in src/web/studio/cards.ts now adds a More row ("N more not shown"). The Close N done button also keeps to the issues the card shows, so it never closes one a person cannot see. A test in test/mcp-held-card.test.ts covers this with 45 issues. Done issues beyond row 40 stay held until the gate is read again or the list is shorter.
  • Smaller: the good({...}) body in held.ts is re-indented, and the tool doc now says a read draws the ui://forge/held card.

What I chose not to do

  • I did not add a paging or "show more" path on the card. The held tool still returns every theme and issue in full, so an agent reading the tool answer sees everything.

To try it

  • Call held with { app: "owner/repo" } on a repo with a Later gate. The card shows the themes, a More row when there are over 40 issues, and Close N done.
  • To run the checks: bun test test/mcp-held-tool-card.test.ts test/mcp-held-card.test.ts.

🤖 Generated with Claude Code

Approved

Both earlier blocking asks are met: test/mcp-held-tool-card.test.ts runs the real held tool over /mcp and asserts the card title, the issue link and the single Close N done action with the review digest. Rows past 40 now get a More row, and the button keeps to the rows shown. The re-indent and the tool doc line are done. I read the diff and did not run the pull's new tests: my clone sits on main, so the one test file my run picked up was unrelated (4 pass). Non-blocking: done issues past row 40 stay unclosable from the card until the gate is read again.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs