Watches topology_runs' event stream for the INT-XX marker protocol
(see skills/foundation/int-xx-marker-protocol.md) and materializes
mission_tasks rows with typed status so the canvas Tasks tab renders
a live timeline instead of raw agent chatter.
Migration 0051 adds mission_id + mission_phase_id columns to
topology_runs (nullable) so runs enqueued by a mission phase can be
attributed. Populated by future phase executors; NULL for legacy
research/loops runs (parser skips them cleanly).
New Rust surface:
- task_card_parser::parse(text) — line-scanner over TASK/WORK/
HANDOFF/TEST_PASS/TEST_FAIL/REVIEW_APPROVE/REVIEW_BLOCK/COMPLETED
markers. Strict: exact kind + colon + INT- prefix, no in-prose
matches, no bold/code-fence wrappers.
- task_card_parser::apply_for_run(pool, run_id) — reads the run's
mission binding, walks its event payloads, extracts text/output/
content/message string fields (matching every ZeroClaw event
shape we see), parses markers, UPSERTs mission_tasks via the
(phase_id, external_id) unique key from Slice 1.
- task_card_worker::spawn — 15s poller over runs updated in the
last 5 minutes. Idempotent + generous window survives server
restarts + task-scheduling jitter.
Boot wires the worker after the content loaders. Silent no-op when
mission wiring isn't populated yet.
MarkerKind → status mapping (monotonic-forward):
TASK → created
WORK → working
HANDOFF → validating
TEST_PASS → validating
TEST_FAIL → failed
REVIEW_APPROVE → validating
REVIEW_BLOCK → failed
COMPLETED → complete
Follow-ups:
- Wire phase executor to populate topology_runs.mission_id +
mission_phase_id (Slice 6/7/8 work)
- Assign assigned_agent_id via the event's producing agent alias
(currently always None)
- SSE stream on /api/missions/{id}/tasks for live canvas updates
(currently the canvas polls via mission GET)
Co-Authored-By: Claude Opus 4.7 <[email protected]>
18 lines
800 B
SQL
18 lines
800 B
SQL
-- Slice 5 — wire topology_runs to missions so the task-card parser
|
|
-- can attribute agent output to the right mission + phase.
|
|
--
|
|
-- Populated by the phase executor (Slices 4/5/6/7/8) when it enqueues
|
|
-- a topology_run on behalf of a mission phase. Left NULL for legacy
|
|
-- runs and the existing research/loops paths that pre-date missions.
|
|
--
|
|
-- The parser (task_card_parser) skips runs where mission_id IS NULL —
|
|
-- keeps the surface additive during the Slice 9 transition.
|
|
|
|
ALTER TABLE topology_runs
|
|
ADD COLUMN mission_id UUID REFERENCES missions(id) ON DELETE SET NULL,
|
|
ADD COLUMN mission_phase_id UUID REFERENCES mission_phases(id) ON DELETE SET NULL;
|
|
|
|
CREATE INDEX topology_runs_mission_idx
|
|
ON topology_runs (mission_id, created_at DESC)
|
|
WHERE mission_id IS NOT NULL;
|