Files
poimen/tasks/T3.6-version-pinning-at-spawn.md

3.8 KiB

T3.6 — Version pinning at spawn

Field Value
Phase P3 — Workflow as data
Size S — under 1 day
Status Not started
Flags
Spec inlined below
Blocks

Goal

VersionSelector::Latest resolves exactly once, at run spawn, and the resolved hash is recorded.

Facts (inlined — no spec read needed)

  • SubWorkflow pins by VersionSelector: Exact(hash) or Latest.
  • Latest resolves once, at run spawn, and the resolved hash is recorded. A run whose sub-workflow version can change mid-execution is a run whose results attribute to nothing.
  • The same rule applies to the top-level workflow: the run records the exact WorkflowVersion it executed, and a version published mid-run does not affect it.
  • Related failure the type system prevents: a placeholder that type-checks is invisible. A hardcoded "current" version hash compiled, passed tests, and made every result unattributable — which is why WorkflowVersion has no Default (T0.1).
  • Versions are never edited in place; a new version is a new hash with a parent pointer.

Steps

  1. At spawn, resolve the top-level workflow and every reachable SubWorkflow selector to concrete hashes.
  2. Record the resolved set on the run's spawn event — the top-level version plus a map of (WorkflowId → WorkflowVersion) for sub-workflows.
  3. Make the interpreter (T3.5) read only from that recorded map. It must have no path back to the registry's current Latest.
  4. Resolve Latest against the registry once; if a new version is published afterwards, nothing re-reads it.
  5. Test: start a run, publish a new version of the same workflow mid-run, assert the running run's recorded version is unchanged and it finishes on the pinned one.

Acceptance

  • Publishing a new version mid-run does not change the running run's recorded version.

Phase gate

P3 closes when a user-authored YAML workflow runs with no framework recompile.

Verify

Harness: a workflow registry that can publish a new version while a run is in flight, plus a run long enough to straddle the publish (stub latency on a mid-run step).

Integration testtests/it_version_pinning.rs:

  1. Register workflow W v1, containing a SubWorkflow pinned Latest.
  2. Spawn a run; park it mid-execution before the sub-workflow step.
  3. Publish W v2 and a new version of the sub-workflow.
  4. Release the run.
  5. Assert the run's recorded top-level WorkflowVersion is v1.
  6. Assert the sub-workflow executed is the version resolved at spawn, not the newly published one — check the recorded resolution map, then check which version actually ran (they must agree).
  7. Assert the spawn event carries the full (WorkflowId → WorkflowVersion) map, not a selector.
  8. Registry-access audit: assert the interpreter makes zero registry lookups after spawn — instrument the registry with a call counter.

Command: cargo test -p executor version_pinning

False pass:

  • Parking the run after the sub-workflow step, so nothing could have re-resolved. The park point must precede the step.
  • Asserting only step 5. The top-level version is usually recorded correctly; the lazy-resolution bug lives in the sub-workflow path. Steps 6 and 8 are the test.
  • Step 6 checking the recorded map only. A map that is recorded and then ignored passes — assert what actually ran.

Traps

  • Resolving Latest lazily at the point the sub-workflow is entered. It is the natural implementation and it makes long runs non-attributable.
  • Storing the selector rather than the resolved hash on the run record.

Background (not required to do this task): rust-agentic-sys.md §4.4, §12.2, §19 · rust-agentic-task.md