Repository navigation
Give the AI connector a reopen_signup tool - #605
Conversation
reopenSignup moves a closed signup back to open, under the same signup lock as every other status change, and writes a signup.reopened activity row. Only a closed signup reopens: a draft is published as before, and an archived one stays archived. People already signed up keep their spots and the first publish's opensAt stays. A closing time that has already passed is removed in the same update, since it would go on refusing every sign-up and the web app has no way to change it. The activity row keeps the removed time as clearedClosesAt. One still to come is kept. The no-slots refusal now names the action it refused, so a reopen says "reopen requires at least one slot" rather than "publish". POST /api/signups/[id]/reopen calls it, as /close calls closeSignup. Part of #20. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LrYa57fvbqWjZj89iH975K
reopen_signup calls reopenSignup, as close_signup calls closeSignup, and returns the signup with its links. Its description says what a reopen keeps and that a closing time that had passed comes back as null. close_signup no longer says closing can't be undone, and the help page "Connect an AI assistant" and docs/connect-ai-assistant.md list reopening. It isn't an ask-first tool: a reopen only follows the organizer asking for one, and close_signup undoes it. The ask-first line also sits in the part of the server instructions that must stay within 2048 bytes, which is nearly full. Part of #20. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LrYa57fvbqWjZj89iH975K
Tophat: passedRan 46d9679 locally with
The test signup was "Bake sale — Autumn fair", published, with a closing time two hours in the past.
This changes what the MCP tools say and do, and a help page, so it's UX. The screenshots of the help page (desktop and phone) are attached in the session. Screenshots are in https://claude.ai/code/session_01LrYa57fvbqWjZj89iH975K. Generated by Claude Code |
ubuntu-latest now gives the Ubuntu 26.04 image, and Playwright 1.59.1
refuses to install Chromium there ("Playwright does not support chromium
on ubuntu26.04-x64"), so every pull request's e2e job has failed in its
install step since, before a single test ran. The retry loop can't help.
24.04 is the image every e2e run passed on until now. The lint-type-test
job still passes on 26.04 and is left as it is.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LrYa57fvbqWjZj89iH975K
GET /api/signups/[id] lists every other status change in _links, so it lists /reopen too. A reopen refused for the signup's status now says "cannot reopen a signup that is draft" rather than "cannot open …", as its no-slots refusal already names reopen. The publish refusal tests now pin publish's own wording, which comes from the same branch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LrYa57fvbqWjZj89iH975K
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LrYa57fvbqWjZj89iH975K
The merge of #604's branch conflicted in CHANGELOG.md and was committed with the conflict markers still in. Keeps both lines: this PR's for reopen_signup, then #604's for the REST API with its new _links and refusal wording, now saying only the web app's way to reopen is to come. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LrYa57fvbqWjZj89iH975K
|
The The fix is #607 (pins Generated by Claude Code |
richshaw
left a comment
There was a problem hiding this comment.
Review: passed (round 1)
This adds reopen_signup, a status tool that calls #604's reopenSignup under signups:write. It also rewords close_signup, which no longer says closing can't be undone, and updates the "Connect an AI assistant" help line, docs/connect-ai-assistant.md and the CHANGELOG, as PR 2 of #20's plan says. It does this well:
- The description matches the service, sentence by sentence. Only a
closedsignup moves toopen. A closing time that has passed is cleared and comes back asclosesAt: null, and a later one stays. Nothing else keeps a reopened signup shut (signupShutReason). - It describes the tool, not the model's behaviour, and the registry's no-directives test passes.
- It stays off the ask-first list, which is choice 6 on #20. The rules before the tools line stay at 2,022 bytes.
- Nothing else still says closing is permanent. No help article, eval case or test pinned the old wording.
Since the last look, the branch merged #604's update. That brings the CI pin and "cannot reopen a signup that is …", so a refused reopen_signup now says "reopen". The PR's own code is unchanged.
Blocking (0)
Optional (1):
src/mcp/tools/signups-write.ts:162: the description doesn't cover anopensignup past its closing time, which the public page shows as closed (shownSignupStatus).reopen_signuprefuses it ("cannot reopen a signup that is open"), and no tool description says thatupdate_signupwithclosesAt: nullis what takes sign-ups again. It stays as is: #20 leaves that state for later.
Earlier threads: none. Copilot couldn't review (quota).
Checks:
- CI: green on 26ec156:
lint-type-test(lint, typecheck, knip,pnpm test,pnpm test:db, build, budgets) ande2e, now onubuntu-24.04via #604's port of #607. - The merge (fb426ff): apart from the CHANGELOG, it brought exactly #604's 0331eb5 and 8197208 (same patch id). The PR's own changes against its base are byte-for-byte the ones reviewed on 46d9679.
- CHANGELOG: fb426ff committed it with conflict markers. 26ec156 resolves them, and
git grepfinds none at this SHA. Both #20 lines are there, this PR's first, with nothing lost, and #604's now ends "The web app gets its own way to reopen in a follow-up change." - Tophat: passed on 46d9679. This PR's only commit of its own since then is 26ec156, which touches only the CHANGELOG. Against
origin/main, the shared check prints 2 until #604 lands: those are #604's own 8197208 hunks, which #604's tophat passed.
This waits for you because it's UX: it changes what the MCP tools say and do for an organizer's AI assistant (a new reopen_signup, and close_signup's wording) and one line of a help page. Worth a look:
- the
reopen_signupdescription insrc/mcp/tools/signups-write.ts; - the choice to leave it off the ask-first line;
- the help line "Publish, close, reopen, archive or delete a signup. Archiving or deleting can't be undone."
The tophat's help-page screenshots are in its session. Merge after #604.
https://claude.ai/code/session_01LrYa57fvbqWjZj89iH975K
Generated by Claude Code
Three conflicts, each kept both sides: - transitionStatus takes main's `extra` payload argument and this branch's 'signup.reopened' event, and writes both into the activity row along with `clearedClosesAt`. - signups.db.test.ts imports both recordPublishCheck and reopenSignup. - CHANGELOG keeps both entries. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LrYa57fvbqWjZj89iH975K
Only CHANGELOG conflicted: it keeps main's Publish and share entry, this branch's reopen_signup entry, and this branch's wording of the reopen entry, which already says the AI connector can reopen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LrYa57fvbqWjZj89iH975K
Only CHANGELOG conflicted: it keeps this branch's reopen entry, which no longer says the web app's Reopen is still to come, and its own entry for the button. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LrYa57fvbqWjZj89iH975K
Only CHANGELOG conflicted: it keeps this branch's reopen_signup entry and its wording of #604's entry, which says the AI connector can already reopen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LrYa57fvbqWjZj89iH975K
|
Approved by the owner at Generated by Claude Code |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LrYa57fvbqWjZj89iH975K
The CHANGELOG's only conflict: main's two new entries for #604 and #605 go after this branch's line for the share panel. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HoJtwsyrp6YC4DU9JAnc7H
Only CHANGELOG conflicted: it keeps this branch's reopen and web-app entries and its edit of #571's entry, and adds #602's entry from main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LrYa57fvbqWjZj89iH975K
Through the server, telemetry and screen branches. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UW9ZpEu4MWkeqTv2Qe14ks
Part of #20. PR 2 of 5. Merge after #604, which it's stacked on: #604 adds the
reopenSignupservice this tool calls.The problem
An organizer who closes a signup through their AI assistant, or closes one by accident in the web app, can't ask the assistant to open it again.
close_signupalso tells the assistant "This cannot be undone from here.", which won't be true once a reopen exists.The fix
reopen_signup(src/mcp/tools/signups-write.ts) is a status tool like the others. It callsreopenSignupand returns the signup with its links, under thesignups:writescope.close_signup:close_signupundoes it;destructiveHint: true.close_signupnow ends "reopen_signup starts taking signups again." instead of "This cannot be undone from here."docs/connect-ai-assistant.mdlists reopen too.affected-articles.mjsnames only that article, edited directly. No walkthrough or test pinned the old sentence.Tests
src/mcp/tools.db.test.ts: the lifecycle test now publishes, closes and reopens through the tools, and a secondreopen_signupgetsconflict.src/mcp/tools/signups-write.test.ts:reopen_signupcallsreopenSignupwith the id (the tool, service mock and table row are added).src/mcp/registry.test.ts: the spelled-out roster includesreopen_signup.src/app/api/mcp/route.test.ts's 2048-byte check still passes.Ran and passed:
pnpm lint,pnpm typecheck,pnpm test(1391) andpnpm test:db(548);pnpm knip: clean for this change. Locally it flagged only a sibling worktree's copies, which aren't in this branch.Generated by Claude Code