Record sandbox workflow lineage across a fork
@elias-ba is already working on this.
Since Jul 8, 2026.
- Dominant language
- Elixir
- Stars
- 296
- Forks
- 86
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 50
Description
As a maintainer of the sandbox merge, I want each sandbox workflow to carry a stable link to the parent workflow it was cloned from, so that merges, deletions, and renames are resolved by identity instead of guessed from names.
Follow-up to #4919 (the fix there is a safe interim) and part of #4852 (Sandbox DevX epic).
The gap
When a sandbox is provisioned, create_sandbox_workflows builds a map of parent workflow id to new sandbox workflow id, uses it only to wire up the clone, and discards it. Each sandbox workflow ends up with a fresh id and no stored link to its origin, so at merge time MergeProjects.merge_project re-matches the two projects by workflow name.
The lineage we need exists at fork time and we throw it away. Working from names alone, the merge cannot tell a workflow added to the parent after the fork from one deleted in the sandbox (the #4919 bug), cannot follow a workflow through a rename, and falls back to name-and-structure heuristics for node and divergence matching. Persisting the origin link fixes these at the root.
Approaches
Ways to persist the link, lightest to most capable:
- Option A — a column on
workflows(recommended). A nullablesource_workflow_idreferencing the origin workflow, set increate_sandbox_workflowsfrom the map it already builds. Smallest change, and it gives per-workflow identity, so it covers both the deletion distinction and rename-following. - Option B — a
workflow_lineagestable. One row per clone (sandbox workflow, origin workflow, forked-at). Same per-workflow identity as A, with room for multi-hop history later, but heavier than this needs today. - Option C — a fork manifest on the sandbox. Just the set of origin workflow ids captured at fork. Lightest, and enough to tell added-after-fork from deleted-in-sandbox, but it carries no per-workflow identity, so it does not help renames or node matching.
Recommendation: Option A. A and B meet the full goal; C is a lighter alternative if only the deletion distinction is wanted.
How the merge uses it
With per-workflow identity (A or B), the merge resolves the parent/sandbox correspondence by the stored link first and falls back to name matching only for sandboxes created before this ships. That retires the workflow_added_after_fork? timestamp guess and lets a rename be matched in place instead of read as a delete plus a create.
Open decisions
- Existing sandboxes have no stored lineage. Decide between a one-time best-effort backfill (by name and fork time) and keeping the name fallback for old sandboxes while new ones get exact lineage.
- How far to take it. The floor is the identity work above. The fuller end is a three-way merge on a recorded fork baseline (base versus sandbox versus current parent), which also makes divergence and conflicts precise and builds on the same lineage. Which to build is a product and priorities call at pickup, not pre-decided here.
Acceptance criteria
- Given a sandbox created after this ships (via A or B), when I open its merge screen, then added-after-fork and deleted-in-sandbox workflows are distinguished without using creation times.
- Given I rename a workflow in the sandbox, when I merge, then it is matched to its origin and updated in place, not shown as a delete plus a create.
- Given an older sandbox with no stored lineage, when I merge, then the name fallback still works and nothing regresses.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.