Problem
Two parallel contracts exist. missions.py still advertises itself as the “Single source of truth for parsing, querying, and modifying missions.md” and exposes pure functions over content strings (start_mission, complete_mission, pick_missions, …). MissionStore is the documented authority with stable IDs and atomic claim_next. Writers almost always call the string API through modify_missions_file / insert_pending_mission, which only accidentally update the store via full reconcile. Readers are split: some use mission_store.transition.read_sections, others still parse content/missions.md.
Why This Matters
Callers assume text-match identity (mission_title substring match) while the store has real IDs; mismatches already surface as “could NOT be removed from the queue (text mismatch)” paths. New features keep landing on the wrong abstraction, growing dual maintenance and correctness risk during the unfinished S8 cutover.
Suggested Fix
Make the port the only write/read surface for lifecycle:
- Update
missions.py module docstring: content helpers are export/parse utilities, not authority.
- Add thin facades:
queue_mission(), finalize_mission(mission_id, status=...) that call store methods + export_view.
- Deprecate content-mutating entry points for daemon paths; keep pure parsers only for tests and markdown export formatting.
- Thread
mission_id through run/finalize instead of matching free-text titles.
Track remaining modify_missions_file call sites and migrate by subsystem (bridge insert → run claim/complete → recover → dashboard).
Details
|
|
| Severity |
🟡 Medium |
| Category |
interface_risk |
| Location |
koan/app/missions.py:1-7,1241-1335,2054+; koan/app/mission_store/base.py:86-165; koan/app/utils.py:893-967 |
| Effort |
🏗️ Significant work |
🤖 Created by Kōan from audit session
Problem
Two parallel contracts exist.
missions.pystill advertises itself as the “Single source of truth for parsing, querying, and modifying missions.md” and exposes pure functions over content strings (start_mission,complete_mission,pick_missions, …).MissionStoreis the documented authority with stable IDs and atomicclaim_next. Writers almost always call the string API throughmodify_missions_file/insert_pending_mission, which only accidentally update the store via full reconcile. Readers are split: some usemission_store.transition.read_sections, others still parse content/missions.md.Why This Matters
Callers assume text-match identity (
mission_titlesubstring match) while the store has real IDs; mismatches already surface as “could NOT be removed from the queue (text mismatch)” paths. New features keep landing on the wrong abstraction, growing dual maintenance and correctness risk during the unfinished S8 cutover.Suggested Fix
Make the port the only write/read surface for lifecycle:
missions.pymodule docstring: content helpers are export/parse utilities, not authority.queue_mission(),finalize_mission(mission_id, status=...)that call store methods +export_view.mission_idthrough run/finalize instead of matching free-text titles.Track remaining
modify_missions_filecall sites and migrate by subsystem (bridge insert → run claim/complete → recover → dashboard).Details
koan/app/missions.py:1-7,1241-1335,2054+; koan/app/mission_store/base.py:86-165; koan/app/utils.py:893-967🤖 Created by Kōan from audit session