130 lines
5.6 KiB
Markdown
130 lines
5.6 KiB
Markdown
# T1.3 — Run executor
|
|||
|
|
|
||
|
|
| Field | Value |
|
||
|
|
|---|---|
|
||
|
|
| Phase | P1 — Walking skeleton |
|
||
|
|
| Size | L — over 3 days |
|
||
|
|
| Status | Not started |
|
||
|
|
| Flags | — |
|
||
|
|
| Spec | inlined below |
|
||
|
|
| Blocks | — |
|
||
|
|
|
||
|
|
## Goal
|
||
|
|
|
||
|
|
Drive a hardcoded three-step workflow through the full run lifecycle, emitting
|
||
|
|
every kernel transition to the log. T3.5 later replaces the hardcoded workflow
|
||
|
|
with the IR interpreter.
|
||
|
|
|
||
|
|
## Facts (inlined — no spec read needed)
|
||
|
|
|
||
|
|
Run lifecycle — the states and the legal moves:
|
||
|
|
|
||
|
|
```
|
||
|
|
spawn
|
||
|
|
│
|
||
|
|
v
|
||
|
|
Scheduled ─────────────────┐
|
||
|
|
│ admitted │
|
||
|
|
v │
|
||
|
|
Running ⇄ Suspended ──────┤
|
||
|
|
│ all steps terminal │ cancel
|
||
|
|
v │
|
||
|
|
Verifying ─────────────────┤ ◄── rests here while verifier
|
||
|
|
│ │ futures are outstanding
|
||
|
|
v │
|
||
|
|
Verified{pass|fail} │
|
||
|
|
│ │
|
||
|
|
v v
|
||
|
|
Grading ──────────────► Cancelled ●
|
||
|
|
│ ◄── may wait for a tournament group to fill
|
||
|
|
│
|
||
|
|
├──► Graded ● ──┐
|
||
|
|
│ ├──► Archived ●
|
||
|
|
└──► Ungraded ● ──┘
|
||
|
|
```
|
||
|
|
|
||
|
|
- **Cancel is reachable from every non-terminal state**, not only `Scheduled`. A
|
||
|
|
run cancelled mid-step is the ordinary case — it is what a user clicking stop
|
||
|
|
does. Cancelling during `Verifying` or `Grading` is rarer and still legal.
|
||
|
|
- **`Verifying` and `Grading` are states the run rests in**, not synchronous
|
||
|
|
branches. Resolving pass/fail inside `verify()` collapsed this in the prior
|
||
|
|
implementation and blocked three separate features at once: async verifiers,
|
||
|
|
mid-run UI, and the snapshot barrier (T4.2).
|
||
|
|
- **`Ungraded` is terminal and sits beside `Graded`, not below it.** Grading can
|
||
|
|
legitimately end with no score. Without a terminal state saying so, those runs
|
||
|
|
rest in `Grading` forever and become permanently irreducible (T4.4).
|
||
|
|
- `Suspended` releases the worker: a run awaiting human approval or a webhook
|
||
|
|
must not hold an executor slot across a human decision.
|
||
|
|
- Concurrency shape: unbounded across runs; **serial** steps within a run;
|
||
|
|
strictly serial attempts within a step; fan-out only for declared `Parallel`
|
||
|
|
branches and for verifiers of one attempt. The serial spine is
|
||
|
|
`(TenantId, RunId)`.
|
||
|
|
|
||
|
|
## Steps
|
||
|
|
|
||
|
|
1. Define the run-state enum and its transition function, exhaustive like T0.2's.
|
||
|
|
Include `Cancelled` as reachable from every non-terminal state.
|
||
|
|
2. Build the executor loop: take the hardcoded three-step workflow, run steps
|
||
|
|
serially, each step producing one or more attempts (T1.4).
|
||
|
|
3. Emit a `WorkEvent` for **every** transition through `EventLog::commit` — run
|
||
|
|
level and attempt level. One commit per transition, not one per run.
|
||
|
|
4. Enter `Verifying` only when every step is terminal. Park there; do not resolve
|
||
|
|
verification inline.
|
||
|
|
5. Enter `Grading` as a resting state likewise; allow it to terminate as
|
||
|
|
`Graded` **or** `Ungraded`.
|
||
|
|
6. Run everything inside a `RunScope` (T1.1) so cancel propagates and no task
|
||
|
|
outlives the run.
|
||
|
|
7. Add `Suspended` with lease release wired as a no-op stub in embedded mode —
|
||
|
|
the state must exist now, since T7.3 depends on it.
|
||
|
|
|
||
|
|
## Acceptance
|
||
|
|
|
||
|
|
- One run completes end to end against the stub model.
|
||
|
|
- `Verifying` and `Grading` are observable as **distinct states in the log**, not
|
||
|
|
skipped or collapsed.
|
||
|
|
|
||
|
|
## Verify
|
||
|
|
|
||
|
|
**Harness:** embedded `redb`, stub model (T1.2), one throwaway verifier, one stub
|
||
|
|
grader. This is the first test that exercises T0.5, T0.6, T0.8, T1.1 and T1.2
|
||
|
|
together — treat it as the P1 integration point.
|
||
|
|
|
||
|
|
**Integration test** — `tests/it_full_run.rs`:
|
||
|
|
1. Spawn one run of the three-step workflow; drive to completion.
|
||
|
|
2. Read the log back and assert the **run-state sequence** contains
|
||
|
|
`Scheduled, Running, Verifying, Grading` and a terminal state, in that order.
|
||
|
|
Assert `Verifying` and `Grading` each appear as their own record — not
|
||
|
|
inferred, not skipped.
|
||
|
|
3. Assert every step produced attempt records and that no state appears out of
|
||
|
|
order against T0.2's table.
|
||
|
|
4. Call `assert_refold_identical` on the finished run.
|
||
|
|
5. Cancel matrix: start a run, cancel it from each of `Scheduled`, `Running`,
|
||
|
|
`Verifying`, `Grading` in turn; assert each reaches `Cancelled`.
|
||
|
|
6. Ordering: launch 20 runs concurrently, assert each run's own records are
|
||
|
|
totally ordered and that no two steps of one run overlap in time.
|
||
|
|
|
||
|
|
**Command:** `cargo test -p executor --test it_full_run`
|
||
|
|
|
||
|
|
**False pass:**
|
||
|
|
- Asserting `Verifying` "happened" by checking a boolean on the run record. That
|
||
|
|
passes against a synchronous `verify()` call, which is the collapse this task
|
||
|
|
exists to prevent. The **log record** is the assertion.
|
||
|
|
- A cancel test that only covers `Scheduled`. That is the one case a broken
|
||
|
|
implementation gets right.
|
||
|
|
- Step 6 with a single run, where serial execution is indistinguishable from
|
||
|
|
accidental parallelism.
|
||
|
|
|
||
|
|
## Traps
|
||
|
|
|
||
|
|
- Making cancel legal only from `Scheduled`. Nobody would ship that lifecycle.
|
||
|
|
- Treating `Verifying` as a function call. It removes the seam T4.2 needs.
|
||
|
|
- Interleaving steps within a run "since they look independent". The serial spine
|
||
|
|
is `(TenantId, RunId)`; parallelism lives between runs and inside declared
|
||
|
|
fan-out only.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
Background (not required to do this task):
|
||
|
|
[rust-agentic-sys.md](../../../rust-agentic-sys.md) §5.2, §5.3 ·
|
||
|
|
[rust-agentic-task.md](../../../rust-agentic-task.md)
|