3.1 KiB
3.1 KiB
T10.1 — GoalId and goal-scoped query
| Field | Value |
|---|---|
| Phase | P10 — Orchestration |
| Size | S — under 1 day |
| Status | Not started |
| Flags | — |
| Spec | inlined below |
| Blocks | T10.2, T10.3, T10.4, T10.8 |
Goal
New identity GoalId(Ulid) grouping runs that share an objective, optional at
spawn. Extend T1.7's query surface to read across RunIds sharing one
GoalId.
Facts (inlined — no spec read needed)
GoalIdis tenant-scoped likeRunId, notTaskId.TaskIdis already the grading comparison-group key (§11.5) — reusing it corrupts group-epoch/quorum semantics the learning loop depends on.- Attaching
goal_idat spawn is optional. A run with noGoalIdbehaves exactly as today — this is additive, not a required field. GoalViewis a new, separate query. It does not replace per-runEpisodeView; it lists memberRunIds and references their existing metadata, no duplication.- Same parity rule as T1.7:
GoalViewfrom materialized state must equalGoalViewfrom a cold re-fold (T0.8's property applied here too).
Steps
- Declare
GoalId(Ulid)in theidscrate, alongsideRunId. - Add optional
goal_id: Option<GoalId>to run-spawn input and the run record. - Index runs by
(TenantId, GoalId)in materialized state. - Define
GoalView { goal: GoalId, runs: Vec<RunSummary> },RunSummaryreferencing existing run metadata — do not duplicateEpisodeViewfields. - Implement the query against materialized state and against cold re-fold.
- Test: two runs sharing a
GoalId, one plain run with none; assertGoalViewreturns exactly the two, in spawn order.
Acceptance
- Two runs sharing a
GoalIdare both returned byGoalView; a run with noGoalIdnever appears in anyGoalView. GoalViewfrom materialized state equalsGoalViewfrom cold re-fold.
Verify
Harness: two runs sharing a GoalId, one run with no GoalId, one
branch/rewind case reused from T1.7's harness.
Integration test — tests/it_goal_view_equivalence.rs:
- Spawn run A and run B both with
goal_id=G; spawn run C with none. - Query
GoalView(G)from materialized state →view_a. - Drop state tables; query again via cold re-fold →
view_b. - Assert
serialize(view_a) == serialize(view_b). - Assert
view_acontains exactly{A, B}, neverC. - Assert order is spawn order, stable.
Command: cargo test -p query goal_view_equivalence
False pass:
- Testing only one run per goal — a grouping bug is invisible with a single member.
- Skipping the "run without
goal_id" exclusion check. A filter that defaults to "all runs" passes silently without it.
Traps
- Deriving
GoalIdfromTaskId"since they're both groupings." Different lifecycle, different owner — grading vs orchestration. - Making
goal_idrequired at spawn. Breaks every existing plain-workflow spawn call.
Background (not required to do this task): rust-agentic-sys.md §11.5 · T1.7-episode-query-surface.md · T0.8-fold-and-re-derive.md