Skip to content

Give the AI connector a reopen_signup tool - #605

Merged
richshaw merged 9 commits into
mainfrom
claude/sharp-carson-ryvv43-2-assistant
Oct 25, 2026
Merged

richshaw merged 9 commits into
mainfrom
claude/sharp-carson-ryvv43-2-assistant

Conversation

@richshaw

Copy link
Copy Markdown
Owner

Part of #20. PR 2 of 5. Merge after #604, which it's stacked on: #604 adds the reopenSignup service 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_signup also 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 calls reopenSignup and returns the signup with its links, under the signups:write scope.
    • Its description: "Start taking signups again on a closed signup, at the same public link. Existing commitments stay. Only a closed signup can be reopened, not a draft or an archived one. A closing time that has already passed is removed, so people can sign up straight away, and the result then shows closesAt as null; a later closing time stays."
    • It describes the tool only, so the registry's no-directives check passes.
  • It isn't ask-first, unlike close_signup:
    • a reopen only ever follows the organizer asking for one, and close_signup undoes it;
    • the ask-first line sits in the part of the server instructions that must stay within 2048 bytes. That part is at 2,022 bytes today and is unchanged here; only the tools line at the end grows.
    • Like every status tool, it keeps destructiveHint: true.
  • close_signup now ends "reopen_signup starts taking signups again." instead of "This cannot be undone from here."
  • Help: "Connect an AI assistant" now says "Publish, close, reopen, archive or delete a signup. Archiving or deleting can't be undone." docs/connect-ai-assistant.md lists reopen too. affected-articles.mjs names only that article, edited directly. No walkthrough or test pinned the old sentence.
  • CHANGELOG: a line under Added.

Tests

  • src/mcp/tools.db.test.ts: the lifecycle test now publishes, closes and reopens through the tools, and a second reopen_signup gets conflict.
  • src/mcp/tools/signups-write.test.ts: reopen_signup calls reopenSignup with the id (the tool, service mock and table row are added).
  • src/mcp/registry.test.ts: the spelled-out roster includes reopen_signup.
  • src/app/api/mcp/route.test.ts's 2048-byte check still passes.

Ran and passed:

  • pnpm lint, pnpm typecheck, pnpm test (1391) and pnpm 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

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
@richshaw richshaw added enhancement New feature or request pipeline:ux Changes what a person using OpenSignup sees or does pipeline:working A session is working on it right now labels Oct 25, 2026 — with Claude
@richshaw
richshaw requested a balanced review from Copilot October 25, 2026 05:43

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota.

Copy link
Copy Markdown
Owner Author

Tophat: passed

Ran 46d9679 locally with pnpm dev, Postgres 16, and Chromium at 1280×900 and 390×844. A connected assistant was simulated end to end:

  1. signed in as a made-up organizer;
  2. approved the real consent screen for the static e2e-client;
  3. exchanged the code for a token at /api/oauth/token;
  4. sent JSON-RPC to POST /api/mcp with that bearer token: initialize, tools/list and tools/call.

The test signup was "Bake sale — Autumn fair", published, with a closing time two hours in the past.

Check Result What I saw
initialize instructions ✅ 2,022 bytes before the tools line, the same as before this PR. The tools line now lists reopen_signup after close_signup. The ask-first line is unchanged ("close_signup, archive_signup, delete_signup, delete_field, delete_slot").
tools/list ✅ reopen_signup has the title "Reopen signup", destructiveHint: true and the new description. close_signup now ends "reopen_signup starts taking signups again."
close_signup then reopen_signup ✅ Closed with closesAt still in the past, then reopened: status: open, closesAt: null, and links edit, preview and public.
reopen_signup again ✅ conflict on status (received: open, expected: closed).
Help page "Connect an AI assistant" ✅ "Publish, close, reopen, archive or delete a signup. Archiving or deleting can't be undone." on desktop and phone. No console errors.
src/mcp/tools.db.test.ts on this SHA ✅ 24 passed, including the new publish, close and reopen lifecycle.

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
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

Copy link
Copy Markdown
Owner Author

The e2e check was red on 46d9679, and not because of this PR. ubuntu-latest now gives the Ubuntu 26.04 image, and Playwright 1.59.1 won't install Chromium there, so the job stopped before running a test.

The fix is #607 (pins e2e to ubuntu-24.04). It comes in here with #604's branch, merged in fb426ff. That merge left conflict markers in CHANGELOG.md, which 26ec156 removes. 26ec156 keeps both entries and changes #604's line to say only the web app's way to reopen is still to come.


Generated by Claude Code

@richshaw richshaw left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 closed signup moves to open. A closing time that has passed is cleared and comes back as closesAt: 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 an open signup past its closing time, which the public page shows as closed (shownSignupStatus). reopen_signup refuses it ("cannot reopen a signup that is open"), and no tool description says that update_signup with closesAt: null is 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) and e2e, now on ubuntu-24.04 via #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 grep finds 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_signup description in src/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

@richshaw richshaw added pipeline:owner Passed; waits for the owner (UX or high-risk) and removed pipeline:review pipeline:working A session is working on it right now labels Oct 25, 2026 — with Claude
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
richshaw pushed a commit that referenced this pull request Oct 25, 2026
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
Base automatically changed from claude/sharp-carson-ryvv43 to main October 25, 2026 20:08
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

Copy link
Copy Markdown
Owner Author

Approved by the owner at 9c90879. They approved the whole Reopen stack in the session ("Please get this feature merged. Giving my approval for this."). Since the last review (26ec156), the PR's only new commits are merges from #604 and main; the latest one resolves a CHANGELOG-only conflict.


Generated by Claude Code

@richshaw richshaw added pipeline:merge and removed pipeline:owner Passed; waits for the owner (UX or high-risk) labels Oct 25, 2026 — with Claude
@richshaw richshaw added the pipeline:working A session is working on it right now label Oct 25, 2026 — with Claude
@richshaw
richshaw merged commit 285b695 into main Oct 25, 2026
5 checks passed
@richshaw
richshaw deleted the claude/sharp-carson-ryvv43-2-assistant branch October 25, 2026 20:18
@richshaw richshaw removed pipeline:merge pipeline:ux Changes what a person using OpenSignup sees or does pipeline:working A session is working on it right now labels Oct 25, 2026 — with Claude
richshaw pushed a commit that referenced this pull request Oct 25, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LrYa57fvbqWjZj89iH975K
richshaw pushed a commit that referenced this pull request Oct 25, 2026
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
richshaw pushed a commit that referenced this pull request Oct 25, 2026
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
richshaw pushed a commit that referenced this pull request Oct 26, 2026
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants