Recurring lesson occurrences show no policy acceptances or intake answers #167

Closed
opened 2026-07-30 19:32:57 +00:00 by thatguygriff · 0 comments
Owner

Found on a live deployment, on the studio's first real booking.

What happens

A student books a weekly recurring lesson and accepts the studio's policies as part of booking. Opening the lesson detail page for any occurrence after the first shows no policies accepted and no intake answers — as though the student had agreed to nothing.

What is actually stored

The acceptances are recorded correctly. A weekly booking creates one us_bookings row per occurrence, but the student answers the intake and ticks the policy boxes once, so BookingEndpoint::book() records both against the anchor lesson only:

$this->gate->record( PolicyAcceptance::REG_LESSON, $anchorId, ... );

The admin detail view then looks them up by whichever lesson id is being viewed, so every occurrence but the anchor finds nothing. Purely a read-path bug — no data is missing or wrong in the database.

What it should do

Every occurrence of a series should show the intake answers and the policy audit trail (policy, version, accepted-at, IP) captured when the reservation was booked. A weekly lesson row already carries series_id pointing at the anchor, so the detail view can follow it — the same way PaymentService already resolves a series lesson's payment back to the anchor's.

The intake answers have the identical bug from the same call site.

Impact

The policy audit trail is the record that a student agreed to the cancellation and payment terms for their lessons. For a recurring student it currently reads as absent on 11 of 12 lessons, which is exactly the situation where a studio would go looking for it.

Found on a live deployment, on the studio's first real booking. ## What happens A student books a weekly recurring lesson and accepts the studio's policies as part of booking. Opening the lesson detail page for any occurrence **after the first** shows no policies accepted and no intake answers — as though the student had agreed to nothing. ## What is actually stored The acceptances are recorded correctly. A weekly booking creates one `us_bookings` row per occurrence, but the student answers the intake and ticks the policy boxes **once**, so `BookingEndpoint::book()` records both against the anchor lesson only: ```php $this->gate->record( PolicyAcceptance::REG_LESSON, $anchorId, ... ); ``` The admin detail view then looks them up by whichever lesson id is being viewed, so every occurrence but the anchor finds nothing. Purely a read-path bug — no data is missing or wrong in the database. ## What it should do Every occurrence of a series should show the intake answers and the policy audit trail (policy, version, accepted-at, IP) captured when the reservation was booked. A weekly lesson row already carries `series_id` pointing at the anchor, so the detail view can follow it — the same way `PaymentService` already resolves a series lesson's payment back to the anchor's. The intake answers have the identical bug from the same call site. ## Impact The policy audit trail is the record that a student agreed to the cancellation and payment terms for their lessons. For a recurring student it currently reads as absent on 11 of 12 lessons, which is exactly the situation where a studio would go looking for it.
thatguygriff added the bug label 2026-07-30 19:32:57 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Unsupervised/unsupervised-scheduler#167