Node state-transition model: execution_id stamping + derived statuses - #263
Merged
Conversation
Pino de Candia (pinodeca)
force-pushed
the
node-transition-model
branch
from
June 23, 2026 16:24
68283e0 to
44c171e
Compare
Pino de Candia (pinodeca)
added a commit
that referenced
this pull request
Jun 23, 2026
Adds docs/node-state-model.md, a design proposal consolidating the node-status work for issues #240 (skipped downstream nodes) and #171 (race-loser nodes left running/pending). Defines instance and node lifecycle states, legal transitions, a coarse status set plus nullable status_reason, loop iteration-scoping/reset semantics, and prior-art alignment with Airflow/Temporal/BPMN/Step Functions. The #240 skipped-node work shipped earlier in PR #249; this PR (#263) defines the consolidated model and will add the remaining implementation (cancelled, status_reason, race-loser reconciliation, loop reset) after review. Design only; implementation to follow on this PR.
Pino de Candia (pinodeca)
force-pushed
the
node-transition-model
branch
from
June 27, 2026 13:30
73d219d to
7ab6b3f
Compare
Pino de Candia (pinodeca)
changed the base branch from
main
to
copilot/fix-loop-restart-issue
June 27, 2026 13:30
Pino de Candia (pinodeca)
force-pushed
the
copilot/fix-loop-restart-issue
branch
from
June 27, 2026 13:51
3a4255f to
b26327a
Compare
Pino de Candia (pinodeca)
force-pushed
the
node-transition-model
branch
from
June 28, 2026 15:18
7ab6b3f to
27a7cf8
Compare
Pino de Candia (pinodeca)
changed the base branch from
copilot/fix-loop-restart-issue
to
main
June 28, 2026 15:18
Pino de Candia (pinodeca)
force-pushed
the
node-transition-model
branch
2 times, most recently
from
June 28, 2026 21:18
36adea3 to
f508143
Compare
Pino de Candia (pinodeca)
force-pushed
the
node-transition-model
branch
2 times, most recently
from
June 28, 2026 21:42
bfe179b to
e88ad3e
Compare
This was referenced Jun 28, 2026
Pino de Candia (pinodeca)
force-pushed
the
node-transition-model
branch
3 times, most recently
from
June 29, 2026 20:27
0f21033 to
bb71981
Compare
Add status_details metadata to df.nodes and stamp each node transition with deterministic execution lineage. Use the lineage to fence stale loop-generation writes while preserving older-schema write compatibility. Move df.instance_nodes() and df.explain() to a shared read-time inference model. It reports skipped branches and superseded loop-body nodes without adding new physical node statuses. Keep df.instance_nodes(text, integer) callable for old schemas and upgraded callers as a shape-compatible adapter. It no longer queries execution history and returns one row per node with execution_id = 1. Update the 0.2.3 to 0.2.4 migration, user/API docs, SQL skill guidance, and E2E coverage for the inferred-status model.
Pino de Candia (pinodeca)
force-pushed
the
node-transition-model
branch
from
June 29, 2026 21:01
bb71981 to
7b1bfda
Compare
This was referenced Jun 29, 2026
This was referenced Jun 29, 2026
This was referenced Jul 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements read-time node-status inference for
pg_durableso thatdf.instance_nodes()anddf.explain()report structure-aware statuses for eachnode, including branches that were never taken and nodes superseded by later loop
iterations.
The implementation keeps the physical node statuses as
pending,running,completed, andfailed. Derived statuses such asskipped, and loopre-entry-as-
pending, are computed from graph structure plus each node'sstatus_details.execution_idlineage.What changed
Schema
df.nodes.status_detailsJSONB column holding the worker-written{"execution_id": "<instance::generation[::...]>"}stamp. The column is addedfor fresh installs in
src/lib.rsand for existing installs through the0.2.3 -> 0.2.4upgrade script.Write path
lineage.
older-generation executions cannot overwrite newer node state.
.socompatible with older schemas that do not yet havedf.nodes.status_detailsby probing for the column at runtime.Read path
df.instance_nodes(instance_id)returns one row per node with stored physicalstatus plus
status_details,inferred_status, andinferred_status_from_ancestor_id.inferred_statusis derived by walking the graph from the root:skipped;pendingbecause it will re-run;df.explain(instance_id)uses the same inference helper so the tree view agreeswith
df.instance_nodes().df.instance_nodes(text, integer)remains callable for old schemas and upgradedcallers as a shape-compatible adapter. It no longer queries execution history,
ignores
last_n_executions, and returns one row per node withexecution_id = 1.Tests & docs
tests/e2e/sql/53_inferred_status.sqlcovering untakendf.if()arms,failed
df.then()downstream nodes, clean sequences, anddf.explain()output.USER_GUIDE.md,docs/api-reference.md, and thepg-durable-sqlskillfor the inferred-status model and the new primary
df.instance_nodes()shape.Related issues
abandoned RACE arm now reads as
skippedviainferred_status; the physicaldf.nodes.statusremains unchanged.df.then()now reads asskipped.Upgrade & migration
0.2.3 -> 0.2.4script addsdf.nodes.status_detailsand recreatesdf.instance_nodes()so upgraded schemas match fresh installs.0.2.xschemas beforeALTER EXTENSION UPDATE: write/read paths avoid referencingstatus_detailswhen the column is absent, and the old two-argument
df.instance_nodes()symbolremains callable.
stamps in activity inputs, and duroxide compares recorded activity inputs by
exact equality during replay.