Issue #3252: [Backend] Workflow run durable lineage contract - #3334
Issue #3252: [Backend] Workflow run durable lineage contract#3334louis4li wants to merge 2 commits into
Conversation
Add typed committed lineage facts for retry, fork, and sub-workflow relationships and project them into run activity/read-model contracts. Closes #3252 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 04b7817ac7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // Implement (issue #3252): | ||
| // Behavior: child workflow runs expose their parent/root run lineage as typed bind facts. | ||
| // Why this shape: the child actor commits lineage from the call-site handoff instead of deriving it from runtime topology. | ||
| InitialLineage = BuildChildInitialLineage(pending, _ownerActorIdAccessor()), |
There was a problem hiding this comment.
Forward child lineage through the bind handler
When a workflow_call binds its child, this field is placed on the incoming BindWorkflowRunDefinitionEvent, but HandleBindWorkflowRunDefinition forwards the request into BindWorkflowRunDefinitionAsync, whose signature and newly constructed committed bind event omit InitialLineage. Consequently every sub-workflow child commits an unavailable lineage instead of its parent/root relationship; pass the typed lineage through the handler into the committed event.
AGENTS.md reference: AGENTS.md:L74-L74
Useful? React with 👍 / 👎.
| next.TerminalNotificationAttempt = 0; | ||
| next.TerminalNotificationDeliveryStatus = WorkflowRunTerminalNotificationDeliveryStatus.Unspecified; | ||
| next.TerminalNotificationRetryCallbackId = string.Empty; | ||
| next.Lineage = evt.InitialLineage?.Clone() ?? CreateUnavailableLineage("Run lineage is unavailable for this run."); |
There was a problem hiding this comment.
Preserve lineage during dynamic definition replacement
For a forked or sub-workflow run that executes ReplaceWorkflowDefinitionAndExecuteEvent, ReplaceWorkflowDefinitionBypassingBindingAsync emits a bind event without InitialLineage; this fallback therefore replaces the already committed ancestry with an unavailable lineage, and the following execution-start event retains that loss. Preserve current.Lineage when a rebind omits an explicit replacement so changing the workflow definition cannot erase the run's durable lineage.
AGENTS.md reference: AGENTS.md:L74-L74
Useful? React with 👍 / 👎.
| lineage?.Clone() ?? new WorkflowRunLineage | ||
| { | ||
| Availability = WorkflowRunLineageAvailability.Unavailable, |
There was a problem hiding this comment.
Classify legacy actor states as legacy-unavailable
When an actor state committed before the new protobuf field is projected after deployment, state.Lineage is null and this fallback writes ordinary Unavailable into the current-state document. Because the query mapper only emits LegacyUnavailable when the document field itself is absent, reprojecting or advancing such an old run permanently misclassifies it as a new run with explicitly unavailable lineage; the projector's null-state fallback should retain the legacy-unavailable distinction.
AGENTS.md reference: AGENTS.md:L85-L85
Useful? React with 👍 / 👎.
Review of PR #3334 - round 1Verdict: rework Verdict rationaleThe PR adds a typed FindingsF1 - Sub-workflow child lineage is dropped before the child run commits its bind event
What's good
REVIEW_VERDICT:rework:sub-workflow child lineage is dropped before authoritative commit |
Preserve sub-workflow child lineage through the authoritative bind commit path. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Review of PR #3334 — round 2Verdict: pass Verdict rationaleThe PR now satisfies issue #3252's durable lineage requirements against the diff: lineage is modeled as additive typed protobuf fields, committed by FindingsNo blocking findings. What's good
Round comparison
REVIEW_VERDICT:pass:durable typed lineage contract is preserved through bind and projection |
Issue
Closes #3252 — [Backend] Workflow run durable lineage contract
Implementation summary
See
.implement-loop/runs/implement-issue-3252.md.Stacked-PR position
feat/2026-08-07_issue-3251(previous issue's branch)feat/2026-08-07_issue-3252🤖 Generated by codex-implement-loop. Reviewer is a Claude subagent (see PR comments for round-N review reports).