Review: Confirmation state machine for write operations

review-604-2026-03-28 Doc

review ready

Verdict: READY

Template Completeness

  • [x] Type — Feature
  • [x] Lineage — Depends on #6, split per review-598-2026-03-28
  • [x] Repo — forgejo_admin/westside-ai-assistant
  • [x] User Story — As Marcus (admin), confirmation before write execution
  • [x] Context — explains split from #6, describes confirmation UX flow
  • [x] File Targets — 2 create, 1 modify, 3 do-not-touch
  • [x] Acceptance Criteria — 5 criteria covering happy/sad/timeout/replacement paths
  • [x] Test Expectations — 5 unit tests + run command
  • [x] Constraints — message formats, case-insensitive matching, no background timer
  • [x] Checklist — standard 3-item
  • [x] Related — project page, write-ops story, safety story

Traceability

  • [x] story:write-ops — Marcus can update player info via GroupMe with confirmation before writes
  • [x] story:safety — Write operations require confirmation, dangerous ops excluded
  • [x] arch:A2 — AI engine component (confirmation is an AI engine sub-module)
  • [x] Forgejo issue — forgejo_admin/westside-ai-assistant#8, open

File Targets

  • [x] app/confirmation.py (create) — does not exist yet, correct for new file. Functions well-specified: store_pending, check_pending, expire_stale, 5-min TTL, dict keyed by group_id.
  • [x] tests/test_confirmation.py (create) — does not exist yet, correct for new file.
  • [x] app/ai.py (modify) — does not exist yet but will be created by upstream dependency #6. Modification scope is well-defined: wire confirmation into process_message() flow.
  • [x] app/basketball.py (do-not-touch) — consumed as-is, correct.
  • [x] app/groupme.py (do-not-touch) — already wired in #6, correct.
  • [x] app/config.py (do-not-touch) — no new config needed, correct.

Repo Placement

OK. Issue filed on westside-ai-assistant, all file targets are within westside-ai-assistant. No cross-repo concerns. Single-repo ticket, single-repo work.

Dependencies

  • [x] #6 (AI engine core) — HARD dependency, pending. Creates app/ai.py which this ticket modifies. #6 explicitly leaves a "confirmation needed" indicator for writes that this ticket consumes. Clean handoff interface documented in both issues.
  • [x] #4 (scaffold) and #5 (basketball client) — transitive dependencies via #6. Not direct concerns for this ticket.
Dependency chain is fully documented in Lineage. This ticket cannot move to next_up until #6 is done.

Acceptance Criteria

All 5 criteria are agent-verifiable via unit tests:
  • [x] Write request triggers confirmation prompt (not execution) — testable via mock Anthropic response
  • [x] "yes" reply executes pending action — testable via mock basketball client
  • [x] Non-"yes" reply cancels — testable via state inspection
  • [x] 5-minute expiry — testable with time mocking (freeze_time or similar)
  • [x] One pending per group (replacement) — testable via sequential state operations
Test command is real: pytest tests/test_confirmation.py -v. All criteria map to specific test expectations. No ambiguous "works correctly" language.

Blast Radius

Low. Confirmation logic is self-contained in a new module (app/confirmation.py). The only integration point is app/ai.py process_message() flow. basketball-api is consumed read-only — no changes needed there. GroupMe posting is already handled by #6. No similar confirmation state machine patterns exist in sibling services. Rollback is straightforward: revert the PR, writes go back to unconfirmed (which #6 already handles by not executing them).

Decomposition Assessment

Three-thing limit: 3 file targets (2 create + 1 modify), all in 1 repo. Passes.
Five-minute rule: Estimated agent time ~3-4 minutes. The state machine is a simple in-memory dict with 3 functions (store_pending, check_pending, expire_stale) plus TTL logic. The ai.py integration is a well-defined if/else branch in process_message(). Passes.
5 acceptance criteria (borderline on the >5 threshold but all are tightly related to one behavioral flow — confirmation lifecycle). No independent subtasks that would benefit from parallelization.
No decomposition needed.

Recommendation

No action needed.