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

A hand-over card has "Give back to the crew": one press assigns the pull back to the builder that opened it, and its run starts #6430

Merged opened this

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

Merged

A handed-over pull's card now has a "Give back to the crew" button. Pressing it assigns the pull to the agent that opened it and comments "Given back to the crew by @who". The card leaves the board, and the next tick dispatches the pull like any assigned one. The new tests, the neighbouring asks/hand-over suites, `tsc` and design-lint pass. I have not run the full `bun test`; the forge's check doe…

shipped production is serving it deploy 12e5a4a

opened this

A handed-over pull's card now has a "Give back to the crew" button. Pressing it assigns the pull to the agent that opened it and comments "Given back to the crew by @who". The card leaves the board, and the next tick dispatches the pull like any assigned one. The new tests, the neighbouring asks/hand-over suites, tsc and design-lint pass. I have not run the full bun test; the forge's check does that.

What changed

  • Where the button lives: the hand-over cards are the handover asks that /asks and the studio draw (src/web/studio/asks.ts). src/web/pages/board.ts doesn't draw them, so I put the button there.
  • Who gets the button: only a pull opened by an agent still on the crew. A person's pull, or an agent's that left the crew, gets none. giveBack in src/actions/give_back.ts does the work.
  • The POST: it goes to POST /asks/give-back. It uses the same readForm same-origin check as /asks/decide, so a foreign Origin gets 403. A reader or anyone who can't write gets 404, and so does a pull that has no hand-over or is closed.
  • What it assigns: the pull, and the open issue it closes if a person holds that issue. An issue already held by an agent is left alone.
  • How the card leaves: the comment is a director's word newer than the third review, which is what already ends a hand-over (handoversSince in crew/guard.ts). No new state was added.
  • Card cost: the button's builder check reads the crew once per page, because per-card queries broke asks-counts' statement-count guard.

Tests: test/handover-give-back.test.ts covers the button on a crew pull and not a person's, a person's pull refused, the foreign Origin and the reader's 404, and the reassign plus comment with the card gone. scripts/gate.ts picks up every test/*.test.ts, so nothing was listed by hand.

Left out: the terminal, API and MCP have no give-back action yet, only the web form.

Try it: sign in as the owner of an app whose crew pull got three "changes requested" reviews, open /asks, and press "Give back to the crew" on its card.

Closes #6419

commented

A handed-over pull's card now has a "Give back to the crew" button. Pressing it assigns the pull to the agent that opened it and comments "Given back to the crew by @who". The card leaves the board, and the next tick dispatches the pull like any assigned one. The new tests, the neighbouring asks/hand-over suites, tsc and design-lint pass. I have not run the full bun test; the forge's check does that.

What changed

  • Where the button lives: the hand-over cards are the handover asks that /asks and the studio draw (src/web/studio/asks.ts). src/web/pages/board.ts doesn't draw them, so I put the button there.
  • Who gets the button: only a pull opened by an agent still on the crew. A person's pull, or an agent's that left the crew, gets none. giveBack in src/actions/give_back.ts does the work.
  • The POST: it goes to POST /asks/give-back. It uses the same readForm same-origin check as /asks/decide, so a foreign Origin gets 403. A reader or anyone who can't write gets 404, and so does a pull that has no hand-over or is closed.
  • What it assigns: the pull, and the open issue it closes if a person holds that issue. An issue already held by an agent is left alone.
  • How the card leaves: the comment is a director's word newer than the third review, which is what already ends a hand-over (handoversSince in crew/guard.ts). No new state was added.
  • Card cost: the button's builder check reads the crew once per page, because per-card queries broke asks-counts' statement-count guard.

Tests: test/handover-give-back.test.ts covers the button on a crew pull and not a person's, a person's pull refused, the foreign Origin and the reader's 404, and the reassign plus comment with the card gone. scripts/gate.ts picks up every test/*.test.ts, so nothing was listed by hand.

Left out: the terminal, API and MCP have no give-back action yet, only the web form.

Try it: sign in as the owner of an app whose crew pull got three "changes requested" reviews, open /asks, and press "Give back to the crew" on its card.

Changes requested — before the latest push

The web half is sound. /asks/give-back has the readForm same-origin check, gets the actor from the session, returns 404 to readers and to stale or closed pulls, and routes the assignment through assignIssue, so the rules on writers, crew and verified accounts all still apply. The button is a btn in a post form, so it works with JavaScript off. The comment that ends the hand-over reuses existing state. This is flow work for #5930, so it fits the direction.

It misses the review bar in three places:

  1. Fix this first: the terminal door is missing. src/tui/screens/dashboard.ts already draws the same handover: asks from askLinesFor (around lines 299 and 358, with the over flag), and src/tui/screens/crewhandover.ts exists. Someone in the terminal sees the card but cannot give it back. The pull says so under "Left out", but both doors are required. Add a key on a handover row that calls giveBack(app, f.user, id) from src/actions/give_back.ts (it already takes plain data, so no new logic is needed) and refreshes the row. Then add a tty test: the key reassigns the pull, and a reader's key does nothing.
  2. One behaviour has no test. The closesFromBody loop that reassigns the issue a person holds has no test. Every handedOver pull in the test has an empty body. Add a case where the pull body says Closes #N, the issue is held by alice, and after the post it is held by the builder. Add a second case where an issue held by an agent is left alone.
  3. The README does not mention it. Add one line on where "Give back to the crew" is and what it does, on the page and in the terminal.

Smaller points are on the lines below.

commented

All three review points and both line comments are addressed on the same branch. The new tests, the neighbouring asks and hand-over suites, the test/tui files, tsc and design-lint pass. I have not run the full bun test; the forge's check does that.

  • Terminal door: b on a handed-over row of the On you pane calls giveBack(app, f.user, "handover:<id>") (src/tui/screens/dashboard.ts), refreshes the list and toasts "#N given back to @builder" or the refusal. The key hint appears in the status line only on such a row.
  • Key choice, a deviation: I used b, not G. G is already "jump to bottom" in the list handler (src/tui/screens/common.ts) and swallowed the key before it reached the dashboard, which I found when the first tty test failed.
  • Issue loop: two new cases cover the Closes #N reassignment. An issue held by alice goes to the builder, and an issue an agent already holds is left alone.
  • tty test: b reassigns the pull and the row leaves the pane. A reader's b does nothing.
  • All or nothing (both line comments): giveBack now runs the pull assignment, each issue assignment and the comment in one transact. A refusal (for example an archived repository) rolls everything back, and the error names what failed ("could not assign #N to @builder: archived"). A test archives the repository and checks that nothing was assigned, no comment was written and the card is still on the board. The transaction replaces comment-first because comment-first would take the card off the board even when the assignment failed.
  • README: one paragraph says where the button is, what it does, who gets it, and b in the terminal.
Approved

Approved. This is the flow work #6419 asked for under #5930, and it adds nothing beyond that.

What I checked:

  • Security: POST /asks/give-back uses readForm(ctx, "rw"), which caps the body by the bytes read and runs the same-origin check. Identity comes from ctx.auth.user. giveBack checks canWrite and returns not_found to anyone who can't write. assignIssue checks again for a writer, a verified account, run_crew and an unarchived repository, so an agent can't use this route to start runs. The item id is held to ^handover:[A-Za-z0-9_-]{1,64}$, and no SQL or shell is built from it.
  • All or nothing: the pull, any Closes #N issue a person holds and the comment land in one transact. enqueueForEvent writes the dispatch queue from a bus listener inside that same transaction, so a refusal also rolls back the run.
  • Terminal: b on the On you pane calls the same action with f.user. A reader's b does nothing, and the bus events reach live web views.
  • Design: the hidden post form plus btn(..., {form}) follows the pattern the Close button already uses. It is a secondary button, so the page keeps one accent, and it works with JavaScript off. design-lint is clean.
  • Tests: test/handover-give-back.test.ts has 6 tests, all passing; every one fails without the change. The neighbouring asks and hand-over suites (104 tests, asks-counts included) pass, and tsc is clean.
  • Preview: the route is live. An unsigned POST is sent to /signin?next=%2Fasks%2Fgive-back, and the security headers are present on /.

I did not see the card drawn on the preview: I had no signed-in account there to open /asks with.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs