3.0 KiB
EDU-008 — Verify idempotent answer saving
- Status: done — answer idempotency and rollback contract verified on PostgreSQL
- Type: implementation/verification
- Phase: 2
- Blockers: EDU-007
Implementation result
The existing unified PostgreSQL idempotency claim remains the final guard. Matching keys replay only a complete, valid stored response; null, blank, malformed, or structurally incomplete replay data now fails closed without re-executing the answer mutation. Completion of a newly claimed response must update exactly one idempotency row before session/question state changes.
Answer saving remains limited to Option-backed Questions. Optionless/free-text behavior is explicitly rejected until a separate subjective-answer contract is designed. The answer HTTP seam now uses the EDU-007 Member principal and TenantContextHolder boundary and rejects ADMIN principals.
PostgreSQL tests prove same-key/same-payload replay, same-key/different-payload conflict including concurrent requests, different-key CAS serialization, stale version/sequence rejection, user/tenant/state/question ownership checks, full rollback of answer/session/claim state, refresh recovery, and no answer-key/explanation leakage. No migration was added or executed by EDU-008.
Scope
- Same key and same canonical payload replays the original result.
- Same key and different payload returns a conflict.
- Database uniqueness is the final idempotency guard.
- Session version and client sequence prevent stale updates.
- Selected options are validated against the safe snapshot contract.
- Optionless answer behavior remains blocked until explicitly designed; do not pretend it is option-backed.
Acceptance criteria
- Same-payload duplicate semantics are explicit and tested.
- Conflicting payload is rejected.
- Concurrent same-key and different-key behavior is tested on PostgreSQL.
- Stale session version and stale per-session command sequence are rejected.
- Wrong user, tenant, session state, or question membership is rejected.
- Responses and restored sessions contain no answer key or explanation.
- Failure does not partially update answer, sequence, session version, or the idempotency claim.
Verification
Focused answer service/controller/Mapper tests, PostgreSQL concurrency tests, EDU-001 regressions, and required diff/compile gates.
Verification performed
PracticeAnswerControllerHttpTest: 16 passed
PracticeAnswerServiceImplTest: 37 passed on PostgreSQL/V4030
Total focused: 53 passed
Failures/errors/skipped: 0
The service suite includes concurrent same-key identical and conflicting payloads plus exact different-key winner/loser assertions. Incomplete replay rows fail closed, and rollback assertions cover session version, session sequence, question state, and claim removal.
Risk and rollback
- Risk: Medium-to-high concurrency and offline-retry risk.
- Rollback: Application rollback with schema retained; forward migration for any constraint correction.