Skip to content

Let invitees suggest other times for the organizer to add - #44

Merged
rockfordlhotka merged 3 commits into
mainfrom
claude/pensive-darwin-g89d94
Nov 4, 2026
Merged

rockfordlhotka merged 3 commits into
mainfrom
claude/pensive-darwin-g89d94

Conversation

@rockfordlhotka

@rockfordlhotka rockfordlhotka commented Nov 3, 2026 •

Copy link
Copy Markdown
Member

Closes #38.

When none of the proposed times work, someone invited can suggest others. The organizer gets an email and decides whether to add each time to the poll or dismiss it.

What changes

  • Suggesting: a new suggest_slots MCP tool, and a "None of these work?" form on the voting page.
    • Up to 5 times per request, and at most 5 waiting per person, which also limits the email one person can cause.
    • Times are local wall time plus an IANA zone, as with slots. The voting page fills in the viewer's own zone when JavaScript is on, and uses the organizer's zone without it.
    • One person's requests are saved one at a time, under a lock on their participant rows, so a double submit can't save duplicates.
  • Organizer email: one "Suggested time" email per request that adds suggestions. It lists the times in the organizer's zone with a link to the event page, and has plain-text and HTML bodies.
  • Adding: propose_more_slots takes a new suggestionIds parameter, and slots is now optional. On the event page this is "Add to the poll" / "Add all".
    • It goes through the existing propose path, so the version check, the 20-time limit, reopening an expired or finalized event, and the "New times" email to every invitee all still apply.
    • A suggested time is built from its stored local time, seconds included. It is resolved leniently, like the time-zone job (new SlotTimeResolver.ResolveStored, which the job now uses too).
    • A time already in the round is added once, whether it is the organizer's own or the same moment suggested by two people. Every waiting suggestion of a time the round adds is marked added.
  • Dismissing: a new dismiss_suggestions tool, and a "Dismiss" button on the event page.
    • It emails no one. The person who suggested the time sees "not added by the organizer" on their voting page, even after voting closes.
    • It takes the version, like any organizer edit.
  • Visibility: the organizer sees every suggestion and who made it, and the /events dashboard shows how many are waiting. A participant sees only their own suggestions, with their status.
  • Retrying is safe: a time already on the poll, or already suggested by the same person, isn't suggested again, and a notice says so. A dismissed time can't be suggested again.
  • Email subjects: every event email's subject is now cut to the outbox's 256 characters. A long name plus a long title could overflow the limit and fail the change that queued the email. The invitation and "can't make any time" subjects had the same problem.
  • Data: a new SlotSuggestion entity and the SlotSuggestions migration. Suggestions are their own rows, so, like votes, they don't change the event's version. They are deleted with their event.
  • Agents: the server instructions and the handle_scheduling_requests prompt now cover suggestions.
  • Docs: a new "Suggested times" section in docs/design.md, plus updates to the data model, tools, email, web UI, jobs and audit sections.

Choices worth a look

  • The person who suggested a time isn't recorded as voting for it. They vote on it like everyone else once it's added.
  • Withdrawing a time still sends no email, as before.

Testing

dotnet test Scheduler.slnx: Core 124, Data 170 and Web 93 tests pass, after merging main.

New tests:

  • SuggestionTests: suggesting, visibility, retries, concurrent requests, limits, adding (including duplicate instants, seconds and times the time-zone rules now skip), dismissing, reopening an expired event, purge.
  • Email-wording and subject-length tests in Core.
  • A voting-page form test, which also checks the suggestion list after voting closes.
  • A bUnit test of Add and Dismiss on the event page.

SchedulerApp.Browser.SubmitFormAsync can now post a specific form, because the voting page has two.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NZSHCijStZzTcMJSBYoY6t

When none of the proposed times work, someone invited can suggest up to five
others: suggest_slots over MCP, or a "None of these work?" form on the voting
page. The organizer is emailed once per call that adds suggestions and
decides: propose_more_slots with suggestionIds (or "Add to the poll" on the
event page) adds them as a new round, which emails everyone invited as new
times always did; dismiss_suggestions (or "Dismiss") emails no one, and the
participant sees "not added" on their voting page.

Suggestions are their own rows (SlotSuggestion), so like votes they don't move
the organizer's version. Only the organizer and the person who suggested a
time see it. Retrying is safe: a time already proposed or already suggested
isn't suggested again, and a dismissed one can't be re-suggested. At most five
can wait per participant, which also bounds the email one person can cause.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NZSHCijStZzTcMJSBYoY6t

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

Unresolved concurrency, slot-resolution, status-visibility, and email-length defects can create duplicate suggestions, fail or mis-time slot additions, hide organizer decisions, and roll back submissions.

6 open issues
1 file not reviewed
  • src/Scheduler.Data/Migrations/20261103210630_SlotSuggestions.Designer.cs: Generated file
What changed in this PR

Adds the invitee-suggestion workflow from #38 across the scheduling service, MCP tools, and web UI. Invitees can suggest alternative times; organizers receive an email and can add those times to the poll or dismiss them.

Changes:

  • Adds persisted suggestions, participant-specific visibility, limits, and organizer decisions.
  • Connects suggestions to voting and organizer pages, MCP tools, and plain-text/HTML notifications.
  • Adds workflow tests and documents the behavior.
File Description
tests/​Scheduler.Web.Tests/​VotingPageTests.cs Tests submitting suggestions through the voting page.
tests/​Scheduler.Web.Tests/​SchedulerApp.cs Supports posting a specific named form.
tests/​Scheduler.Web.Tests/​OrganizerPageTests.cs Tests organizer add and dismiss actions.
tests/​Scheduler.Data.Tests/​VotingTests.cs Updates proposal calls for suggestion IDs.
tests/​Scheduler.Data.Tests/​SuggestionTests.cs Covers suggestion permissions, limits, decisions, notifications, and purge.
tests/​Scheduler.Data.Tests/​SchedulingJobsTests.cs Updates proposal calls for the extended API.
tests/​Scheduler.Data.Tests/​OrganizerTests.cs Updates organizer tests for suggestion IDs.
tests/​Scheduler.Data.Tests/​OrganizerLimitTests.cs Adapts email-limit tests to the extended API.
tests/​Scheduler.Core.Tests/​EmailComposerTests.cs Tests suggested-time email wording and time zones.
src/​Scheduler.Web/​wwwroot/​app.js Defaults suggestion inputs to the viewer’s zone.
src/​Scheduler.Web/​Mcp/​SchedulingTools.cs Exposes suggestion and dismissal tools; extends proposals.
src/​Scheduler.Web/​Mcp/​SchedulingPrompts.cs Adds suggestions to the participant workflow.
src/​Scheduler.Web/​Mcp/​SchedulerMcpOptions.cs Explains suggestion handling to agents.
src/​Scheduler.Web/​Email/​Templates/​EventEmail.razor Renders suggested times in HTML emails.
src/​Scheduler.Web/​Email/​HtmlEmailComposer.cs Composes organizer suggestion notifications.
src/​Scheduler.Web/​Components/​Pages/​Vote.razor Adds suggestion submission and status display.
src/​Scheduler.Web/​Components/​Pages/​Events.razor Displays pending suggestion counts.
src/​Scheduler.Web/​Components/​Pages/​EventDetails.razor Adds organizer controls for suggested times.
src/​Scheduler.Data/​SchedulingService.cs Implements suggesting, dismissing, adopting, and visibility.
src/​Scheduler.Data/​SchedulingJobs.cs Recomputes pending suggestions after time-zone updates.
src/​Scheduler.Data/​SchedulerDbContext.cs Maps suggestion rows, indexes, and relationships.
src/​Scheduler.Data/​Migrations/​SchedulerDbContextModelSnapshot.cs Records the updated persistence model.
src/​Scheduler.Data/​Migrations/​20261103210630_SlotSuggestions.Designer.cs Defines the migration’s target model.
src/​Scheduler.Data/​Migrations/​20261103210630_SlotSuggestions.cs Creates the suggestions table and indexes.
src/​Scheduler.Core/​Services/​ISchedulingService.cs Defines suggestion operations and extended proposals.
src/​Scheduler.Core/​Services/​Contracts.cs Adds suggestion views and pending counts.
src/​Scheduler.Core/​Model/​SlotSuggestion.cs Defines the persisted suggestion entity.
src/​Scheduler.Core/​Model/​SchedulingEvent.cs Adds the event’s suggestion collection.
src/​Scheduler.Core/​Model/​Enums.cs Defines suggestion decision states.
src/​Scheduler.Core/​FieldLimits.cs Adds the pending-suggestion limit.
src/​Scheduler.Core/​Email/​PlainTextEmailComposer.cs Adds suggestion notification text and shared wording.
src/​Scheduler.Core/​Email/​IEmailComposer.cs Adds the suggestion notification contract.
docs/​design.md Documents the workflow and its system integration.

Review effort: Balanced

Comment thread src/Scheduler.Data/SchedulingService.cs Resolved
Comment thread src/Scheduler.Data/SchedulingService.cs Resolved
Comment thread src/Scheduler.Data/SchedulingService.cs Resolved
Comment thread src/Scheduler.Data/SchedulingService.cs Resolved
- Email subjects are cut to the outbox's 256 characters. A 100-character name
  and a 120-character title could overflow it and fail the whole change that
  queued the email; this was also true of the invitation and "can't make any
  time" subjects.
- One person's suggest calls run one at a time, under a lock on their
  participant rows (not the event's, so the version doesn't move), so a double
  submit can't save duplicates, pass the waiting limit, or email twice.
- Adding a suggestion builds the slot from its stored local time and zone,
  resolved leniently like the tzdb job (new SlotTimeResolver.ResolveStored,
  which the job now uses too). It keeps seconds, and a time new rules skip
  moves forward instead of being refused.
- A suggested time already in the round (the organizer's own, or the same
  moment from two people) is proposed once, and every matching suggestion is
  marked added, so "Add all" no longer fails.
- The voting page keeps showing a person's suggestions and what the organizer
  decided after voting closes.

Also updates a test from #37 for the new ProposeMoreSlotsAsync parameter.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NZSHCijStZzTcMJSBYoY6t
@rockfordlhotka
rockfordlhotka merged commit e74dadb into main Nov 4, 2026
4 checks passed
@rockfordlhotka
rockfordlhotka deleted the claude/pensive-darwin-g89d94 branch November 4, 2026 00:28
@rockfordlhotka rockfordlhotka mentioned this pull request Nov 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Allow invitees to suggest a new date/time

3 participants