Skip to content

fix: keep learning from earlier bookings of a sequence after event pruning - #102

Open
claude-for-timatic[bot] wants to merge 5 commits into
mainfrom
fix/35-previous-booking-after-pruning
Open

claude-for-timatic[bot] wants to merge 5 commits into
mainfrom
fix/35-previous-booking-after-pruning

Conversation

@claude-for-timatic

Copy link
Copy Markdown
Contributor

The lookup that finds the earlier booking of a recurring event now survives event pruning. Each suggestion keeps the sequences it was built from, so PreviousBookingsOfSequences no longer joins through events and activities, which are pruned after 30 days. Open suggestions that were never booked are now pruned too.

Closes #35

Decisions (answers to the open questions)

  • Store the sequence key? Yes, per suggestion, in a new entry_suggestion_sequences table (entry_suggestion_id, source_id, external_id). It is not a single column on entries, because a suggestion often chains several sequences. A meeting that learned its customer, for example, merges with nearby commits. "Only set it for a single sequence" would drop the meeting in exactly the case the learning creates.
  • Sequences are written when a day is rebuilt (RebuildUserDay), not when the entry is booked. Rebuild is the only moment the events are guaranteed to exist. That leaves one write point and no change to entry create or update. The lookup follows entries.entry_suggestion_id.
  • The lookup also fixed a second bug. Rebuilding a booked day deleted that day's activities, including the booked suggestion's, so the old join chain broke even within 30 days.
  • "Latest booking of the sequence wins, whatever its date" is unchanged, because a recurring meeting belongs to one customer.
  • Retention keeps counting from created_at? Yes. A late-arriving event has a fresh created_at, and counting from ended_at would prune it before anyone could book it.
  • Prune suggestions without an entry? Only open ones, 30 days after created_at (MassPrunable). Their activities are gone by then anyway. Dismissed suggestions are kept because they must keep suppressing (lifecycle doc). Booked suggestions are kept.
  • A suggestion with a soft-deleted entry counts as booked, both when pruning and when rebuilding a day. Otherwise the SET NULL FK would cut the link of an entry that can still be restored.
  • A backfill migration copies sequences from the existing join chain, using insertOrIgnoreUsing, so it can't fail on rows written between the two migrations. Limitation: it only recovers suggestions whose activities still exist. Older history, and booked days that were rebuilt before this deploy, already lost their link through the old bug.

Review

A code-review agent found no blockers. Fixed after its review:

  • an end-to-end test (book → rebuild → prune → learn) without hand-seeded rows
  • consistent soft-deleted-entry handling in the rebuild
  • an idempotent backfill

Left as is:

  • No created_at index for the first prune run. The first nightly model:prune walks every open suggestion since the start. It's a one-off, so watch it.
  • Dismissed suggestions keep their sequence rows. Nothing reads them; they only cost storage.

Docs to update after #96

  • suggestions/lifecycle.md:
    • "suggestions live forever" → open suggestions without an entry are pruned after 30 days; dismissed and booked ones are kept. Test: deletes open suggestions that are older than the retention period.
    • "A rebuild … keeps everything with an entry" → an entry counts even when soft-deleted. Test: a suggestion whose entry was deleted survives the rebuild.
  • suggestions/suggestions.md, "Learning from an earlier booking": the lookup uses sequences stored on the suggestion, so it survives pruning. Tests:
    • a booked sequence still teaches a later occurrence after its day is rebuilt and pruned
    • rebuilding stores the event sequences of each suggestion
  • suggestions/events.md, sequence bullet: the sequence is copied onto the suggestion so it outlives the event.

Verification

Full Pest suite green (620), PHPStan 0 errors, Pint applied.

…ts are pruned

Store each suggestion's event sequences (source + external id) when a day is
rebuilt, and look up the previous booking through them instead of through
activities and events, which are pruned after 30 days. A migration backfills
the sequences of existing suggestions.
Open suggestions without an entry are pruned 30 days after creation, like
the events and activities they are built from. Dismissed and booked
suggestions are kept.
A rebuild force-deleted a suggestion whose entry was soft-deleted, which
cut the entry's link to it. It now treats a trashed entry as an entry,
like the pruning does.
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.

Looking up previous bookings of recurring events breaks after event pruning

1 participant