# T10.6 — `plan-draft` workflow + `Suspended`-approval flow | Field | Value | |---|---| | Phase | P10 — Orchestration | | Size | M — 1 to 3 days | | Status | Not started | | Flags | — | | Spec | inlined below | | Blocks | — | ## Goal Front door (b): a free-text problem statement produces a draft `WorkflowDef`, parked in `Suspended` for human review, resumed through the identical loader front door (a) uses. ## Facts (inlined — no spec read needed) - `Suspended` is an exact fit, verified against source: "a run awaiting human approval or a webhook must not hold an executor slot" (T1.3), lease released outright with no heartbeat while parked (T7.3). - `plan-draft` is itself an ordinary poimen workflow: a `Model` step producing a `WorkflowDef` draft, no new kernel machinery. - The draft is validated against T3.9's capability registry **before** a human ever sees it — an unresolved verifier/judge/model id in the draft fails here, at draft time, not after approval. - Approval feeds the (possibly human-edited) draft through the **same** `WorkflowFormat`/builder + T3.1 canonicalization as door (a) — this is what keeps both doors on one IR without new proof machinery. ## Steps 1. Define the built-in `plan-draft` workflow: one `Model` step (problem statement → draft `WorkflowDef`), one validation step (registry check via T3.9). 2. On draft ready, transition the `plan-draft` run to `Suspended`, releasing its lease (T7.3). 3. `/v1/plans/{id}/approve` (T10.4 route): load the (possibly edited) draft, run it through the exact loader door (a)'s `WorkflowFormat`/builder uses, canonicalize (T3.1), resume — matching T1.3's resume-from-`Suspended` semantics. 4. `/v1/plans/{id}/reject`: cancel from `Suspended` (legal transition per T1.3's cancel-from-any-non-terminal rule). 5. Test: submit a problem statement, assert `Suspended`, edit the draft, approve, assert the resulting `WorkflowVersion` hash matches hand-authoring the same edited YAML directly. ## Acceptance - A submitted problem statement produces a run parked in `Suspended` with no held executor slot — lease released, per T7.3's own test shape. - Approving a draft (edited or not) produces a `WorkflowVersion` byte-identical to loading the same content by hand through door (a). ## Verify **Harness:** stub model for the `plan-draft` step, embedded `redb`, T7.3's lease-release assertion pattern reused. **Integration test** — `tests/it_plan_draft_approval.rs`: 1. `POST /v1/problems` with a free-text statement; assert the run reaches `Suspended`. 2. Assert the lease is released and no heartbeat is emitted while `Suspended` — reuse T7.3's assertion (its step 8). 3. Fetch the draft; edit one step; `POST /v1/plans/{id}/approve` with the edited draft. 4. Assert the resulting `WorkflowVersion` hash equals hashing the same edited content loaded directly via `WorkflowFormat`/builder — front-door equivalence, extends T3.10. 5. `POST /v1/plans/{id2}/reject` on a second draft; assert it reaches `Cancelled`, not stuck in `Suspended`. 6. Draft referencing an unregistered verifier id; assert `plan-draft`'s validation step fails **before** ever reaching `Suspended` — the human never sees an unloadable plan. **Command:** `cargo test -p orchestration plan_draft_approval` **False pass:** - Skipping step 4's hash comparison and only checking "run resumed" — a subtly different canonicalization from door (a) would still resume, just diverge from what T3.1's guarantee promises. - Not testing reject — an approval-only test suite misses that `Suspended` must also support "no." ## Traps - Having `/approve` construct a `WorkflowDef` directly in the HTTP handler instead of routing through the same loader as door (a) — this is exactly the two-IR-drift bug T3.10 exists to prevent, reintroduced one layer up. - Skipping the registry validation step "since a human will catch it." The whole point of validating before `Suspended` is that load errors are cheap pre-human, expensive post-human. --- Background (not required to do this task): [../INDEX.md](../INDEX.md) (customization contract ~line 19-58) · [T1.3-run-executor.md](T1.3-run-executor.md) · [T7.3-leases-and-fencing.md](T7.3-leases-and-fencing.md) · [T3.10-front-door-equivalence.md](T3.10-front-door-equivalence.md)