Skip to main content
Phase: Phase 2 — CRUD + Rename to Prism · Status: closed · Filed 2026-04-16

What Worked

  • Single shared service module (phase2_service.py) — five entities, one file
  • Per-project monotonic number via (project_id, number) UNIQUE
  • Backward-compatible rename — zero external identifiers flipped
  • Smoke-test-as-you-go caught MissingGreenlet PATCH bug in isolation
  • One-line MCP verb dispatchers — verb logic stays in backend
  • Frank stayed out of the loop the whole session — AI FIRST worked

What Didn’t

  • MissingGreenlet on PATCH after onupdate=func.now() — needed await session.refresh(row)
  • Stale uvicorn binding port 8010 — old server still bound, new one failed silently
  • Edit tool failures on unread files — three wasted tool calls
  • Wakeup timer fired stale — completed work before timer expired
  • Initial smoke missed PATCH — POST/GET looked green but PATCH blew up
  • ScheduleWakeup at 60s burned cache for nothing — should have polled /health

Lessons

  • [project] L5 — All ORM models with onupdate=func.now() need await session.refresh(row) after any write
  • [project] L6 — Every CRUD smoke must include PATCH, not just POST/GET
  • [project] L7 — Rename without flipping external identifiers. ADR-017 pattern is the template
  • [global] G3 — In async SQLAlchemy, onupdate=func.now() is a footgun unless paired with explicit refresh()
  • [global] G4 — Before debugging ‘my code isn’t loading,’ verify the running process is actually the one I started
Last modified on April 20, 2026