Host appointment detail crashes after its meeting type is removed from config #85

Closed
opened 2026-10-24 00:00:59 +00:00 by eleith-gitea-agent · 0 comments

Observed

A signed-in host cannot view an existing appointment after its meeting type is no longer configured. The detail loader attempts its historical snapshot fallback but returns HTTP 500.

Reproduced against landed main aee8312b54, using an isolated production build and Chromium. This predates the in-progress host duration-choice work.

Steps to reproduce

  1. Configure a meeting type and book an appointment through When.
  2. Remove that meeting type from configuration and reload the configuration.
  3. While signed in as the host, visit the existing appointment's detail URL.

Expected: show the host's historical appointment using its stored snapshot, keeping unavailable meeting-type actions disabled.
Actual: HTTP 500 instead of the detail page.

Confirmed runtime evidence

The reproduction booked a real 30-minute appointment through the authenticated create action. The production writer, not a hand-built fixture, stored this snapshot:

{"title":"30-minute chat","duration_minutes":30,"description":"A quick introductory call.","slug":"chat"}

To exercise removal without changing any running configuration, the isolated fixture row's meeting key was changed to an absent key; its real stored snapshot was left untouched. This drives the same missing-config/snapshot-fallback branch. The authenticated GET returned 500 and logged:

TypeError: meeting.additional_duration_minutes is not iterable
    at durationsOf
    at toPublicEventType
    at load

Cause / relevant ownership

  • apps/web/src/lib/server/appointment/create.ts writes a partial meeting_snapshot: title, actual duration, description, slug.
  • The detail loader in apps/web/src/routes/(app)/appointment/[id]/+page.server.ts treats parsed snapshot JSON as a complete Meeting.
  • Projection in appointment/sanitize.ts calls config durationsOf(), which spreads additional_duration_minutes. That property is absent from actual snapshots.

A synthetic full-Meeting snapshot test would mask this failure. Use the actual persisted snapshot shape in the regression test.

Bounded acceptance

  • Host historical detail renders after type removal using the real partial snapshot shape.
  • Preserve guest access restrictions and disabled actions for removed meeting types; do not grant new booking/editing authority.
  • Retain behavior for currently configured meeting types, malformed/missing snapshots and appropriate not-found cases.
  • Keep snapshot normalization/projection focused; no scheduling-policy or duration-editor expansion is needed.

No live application data, provider/SMTP calls or service restarts were used to reproduce this. Duplicate check covered existing open and closed issues; no matching report found.

## Observed A signed-in host cannot view an existing appointment after its meeting type is no longer configured. The detail loader attempts its historical snapshot fallback but returns **HTTP 500**. Reproduced against landed main **aee8312b54a60254282007abaaa3bd6241ecbef6**, using an isolated production build and Chromium. This predates the in-progress host duration-choice work. ## Steps to reproduce 1. Configure a meeting type and book an appointment through When. 2. Remove that meeting type from configuration and reload the configuration. 3. While signed in as the host, visit the existing appointment's detail URL. Expected: show the host's historical appointment using its stored snapshot, keeping unavailable meeting-type actions disabled. Actual: HTTP 500 instead of the detail page. ## Confirmed runtime evidence The reproduction booked a real 30-minute appointment through the authenticated create action. The **production writer**, not a hand-built fixture, stored this snapshot: ```json {"title":"30-minute chat","duration_minutes":30,"description":"A quick introductory call.","slug":"chat"} ``` To exercise removal without changing any running configuration, the isolated fixture row's meeting key was changed to an absent key; its real stored snapshot was left untouched. This drives the same missing-config/snapshot-fallback branch. The authenticated GET returned 500 and logged: ```text TypeError: meeting.additional_duration_minutes is not iterable at durationsOf at toPublicEventType at load ``` ## Cause / relevant ownership - apps/web/src/lib/server/appointment/create.ts writes a **partial** meeting_snapshot: title, actual duration, description, slug. - The detail loader in apps/web/src/routes/(app)/appointment/[id]/+page.server.ts treats parsed snapshot JSON as a complete Meeting. - Projection in appointment/sanitize.ts calls config durationsOf(), which spreads additional_duration_minutes. That property is absent from actual snapshots. A synthetic full-Meeting snapshot test would mask this failure. Use the actual persisted snapshot shape in the regression test. ## Bounded acceptance - Host historical detail renders after type removal using the real partial snapshot shape. - Preserve guest access restrictions and disabled actions for removed meeting types; do not grant new booking/editing authority. - Retain behavior for currently configured meeting types, malformed/missing snapshots and appropriate not-found cases. - Keep snapshot normalization/projection focused; no scheduling-policy or duration-editor expansion is needed. No live application data, provider/SMTP calls or service restarts were used to reproduce this. Duplicate check covered existing open and closed issues; no matching report found.
eleith-gitea-agent Bot added the bug label 2026-10-24 00:00:59 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: eleith/when#85