Submit a review atomically: update the card and append the log #28

Open
opened 2026-09-26 13:58:37 +00:00 by belvedere · 0 comments
Collaborator

Objective: One action that grades a card, reschedules it, and writes the audit row — or
changes nothing at all.

Files:

  • Create: lib/first_thousand_words/study/review_service.ex (or an Ash action with a change)
  • Modify: lib/first_thousand_words/study.ex

Steps:

  1. submit_review(deck, card, rating, opts) runs inside Ash.DataLayer.transaction /
    Repo.transaction.
  2. Load the card for update (row lock), run Scheduler.review/3, persist the new state,
    insert the Review.
  3. Reject a review for a card the actor does not own, and a review for a suspended card.
  4. Make it idempotent per client submission if a session can retry — accept an optional
    client_review_id and unique-index it.

Verify: a forced failure after the card update rolls back the card row (test asserts
unchanged state after a raised error).

Why high risk: double-submitting a review silently corrupts the schedule, and the damage is
invisible until the user notices words they know are being shown every day. Note that
config/config.exs already opts into transaction_rollback_on_error?: true — verify the
interaction with your implementation rather than assuming it.

**Objective:** One action that grades a card, reschedules it, and writes the audit row — or changes nothing at all. **Files:** - Create: `lib/first_thousand_words/study/review_service.ex` (or an Ash action with a `change`) - Modify: `lib/first_thousand_words/study.ex` **Steps:** 1. `submit_review(deck, card, rating, opts)` runs inside `Ash.DataLayer.transaction` / `Repo.transaction`. 2. Load the card **for update** (row lock), run `Scheduler.review/3`, persist the new state, insert the `Review`. 3. Reject a review for a card the actor does not own, and a review for a suspended card. 4. Make it idempotent per client submission if a session can retry — accept an optional `client_review_id` and unique-index it. **Verify:** a forced failure after the card update rolls back the card row (test asserts unchanged state after a raised error). **Why high risk:** double-submitting a review silently corrupts the schedule, and the damage is invisible until the user notices words they know are being shown every day. Note that `config/config.exs` already opts into `transaction_rollback_on_error?: true` — verify the interaction with your implementation rather than assuming it.
Sign in to join this conversation.
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
nickkeers/first-thousand-words#28
No description provided.