Skip to content

feat(operation): resumable-conduct Tier 0 (step_index + resolved-steps manifest)#258

Merged
xmap merged 2 commits into
mainfrom
worktree-resumable-conduct-tier0
Jun 20, 2026
Merged

feat(operation): resumable-conduct Tier 0 (step_index + resolved-steps manifest)#258
xmap merged 2 commits into
mainfrom
worktree-resumable-conduct-tier0

Conversation

@xmap

@xmap xmap commented Jun 20, 2026

Copy link
Copy Markdown
Owner

Tier 0 of resumable Procedure conduct: two additive provenance foundations. No behavior change to conduct / halt / the Procedure FSM.

step_index on every conducted step entry (jsonb payload key, no migration; the runner already had index, the gap was the _record hop) so a recorded outcome maps back to its position in the conducted sequence.

ResolvedStepsRecorded pins the fully-resolved step list (after recipe + pseudoaxis + constituent resolution) at conduct start, so a future resume replays it verbatim instead of re-deriving it (which could silently skip or mis-target a step). Serialized via conductor.step_to_payload (inverse of step_from_wire). Emitted inline from the conduct handler via a pure helper, NOT a dedicated slice: the slice-contract fitness would force an operator route + MCP tool on an event that must only ever fire automatically at conduct, so this mirrors how RecipeExpansionRecorded is emitted from within a flow. Provenance-only: no-op evolver arm, no state fold.

Design and gate-review r1 detail live in project_resumable_conduct_design.md. Tier 1 (resume itself: pre-effect in-flight marker, Suspended/Resumed FSM, execute_from) is future and trigger-gated.

Green locally: pyright, tach, 26450 architecture tests, ruff. New unit tests cover the manifest helper (Defined emits / non-Defined silent), step_to_payload round-trip through step_from_wire, and end-to-end emission before conduct.

🤖 Generated with Claude Code

xmap and others added 2 commits June 20, 2026 19:10
The Conductor walks a step list but its journal entries never recorded
which position each step held: the enumerate index reached the in-memory
ConductorFailure but stopped before _record, so a recorded outcome could
not be mapped back to its place in the conducted sequence.

Persist the zero-based position as a `step_index` key on the step payload
(rides the existing jsonb body, no column or migration). This is the
first foundation for an honest resume: a future ConductManifestPinned
event will pin the conducted list, and resume will use step_index to map
each recorded outcome back onto that manifest. Additive only; no behavior
change to conduct, halt, or the FSM.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A conduct's final step list is derived fresh each time from recipe
re-expansion, pseudoaxis expansion, and live Plan.wires / partition-rule
/ calibration. Recomputing it on a future resume could yield a DIFFERENT
list and silently skip or mis-target a step. So record the resolved list
the moment a conduct begins, before any step executes: a future resume
will replay this pinned list verbatim instead of re-deriving it.

New ResolvedStepsRecorded provenance event on the Procedure stream,
serialized via conductor.step_to_payload (inverse of step_from_wire, so
the list round-trips back to Steps). Distinct from RecipeExpansionRecorded
(registration-time, pre-pseudoaxis, hashed); this is conduct-time,
post-pseudoaxis, full list. Provenance-only: no-op evolver arm, no state
fold (mirrors RecipeExpansionRecorded).

Emitted inline from the conduct_procedure orchestration handler via a
pure, unit-testable helper, NOT a dedicated command slice: the slice
contract would force an operator route + MCP tool on an event that must
only ever fire automatically at conduct. This mirrors how
RecipeExpansionRecorded is emitted from within an existing flow. The
helper records only while the Procedure is Defined and returns [] for any
other state, leaving start_procedure to surface the lifecycle failure so
the conduct route keeps its failures-in-body contract.

naming-r3: ResolvedStepsRecorded reuses the established steps/expansion
vocabulary (no "manifest"), matching the RecipeExpansionRecorded sibling.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@xmap xmap enabled auto-merge (squash) June 20, 2026 19:54
@github-actions

Copy link
Copy Markdown

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  apps/api/src/cora/operation
  conductor.py
  apps/api/src/cora/operation/aggregates/procedure
  events.py
  evolver.py
  apps/api/src/cora/operation/features/conduct_procedure
  handler.py
  manifest.py
Project Total  

This report was generated by python-coverage-comment-action

@xmap xmap merged commit a4f5eb4 into main Jun 20, 2026
16 checks passed
@xmap xmap deleted the worktree-resumable-conduct-tier0 branch June 20, 2026 20:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant