54 lines
3.0 KiB
Markdown
54 lines
3.0 KiB
Markdown
# 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
|
|
|
|
- [x] Same-payload duplicate semantics are explicit and tested.
|
|
- [x] Conflicting payload is rejected.
|
|
- [x] Concurrent same-key and different-key behavior is tested on PostgreSQL.
|
|
- [x] Stale session version and stale per-session command sequence are rejected.
|
|
- [x] Wrong user, tenant, session state, or question membership is rejected.
|
|
- [x] Responses and restored sessions contain no answer key or explanation.
|
|
- [x] 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
|
|
|
|
```text
|
|
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.
|