1 · A Comment state machine behind one seam
Strong
in-process · pure
app/models.py (Comment.status — 8 states, a code comment) · revision_svc.py (_on_triage_done · _on_staging_apply_done · _on_apply_done · discard_staging) · revision_api.py (reject_comment · apply_batch) · comments_api.py (submit)
Before — status set in 7 places
field
Comment.status
no enum · no guard
→ needs_designer
→ applied
→ applied
→ open
draft → open
→ rejected
Each writer owns a slice of the truth. The bugs (rejected shows AI text, accidental “Kész”) live between them.
After — one transition seam
seam
deep module
core/comment_state.py
transition(c, event) → Comment
not_done ⇄ done ⇄ rejected · locked (derived)
One pure function owns every legal move. Callers pass an event; the DAG is enforced once.
Problem. 7 write sites mutate Comment.status with no enum and no transition guard — the state machine has no locality.
Solution. A pure transition() module enforces the legal DAG; all sites call through it.
- locality: transitions in one module
- leverage: one interface, 7 call sites
- interface is the test surface — no DB
- deletion test: scatter reappears → earns keep
- kills “rejected shows AI text” class
- maps to new-plan §2