Artifact versioning & backtrack
Every phase of a running project promotes its producer's output to a pipeline artifact — a versioned, append-only record. This page covers the version model and the three backtrack levers built on it: retrigger, revert, and edit sessions.
The version model
An artifact row carries phase_slug, version (1, 2, 3, …), schema_slug, the content, provenance (produced_by_subtask_id, produced_by_attempt_id, produced_via — the attempt reason), and supersession pointers:
- Exactly one version per phase is current (
superseded: false); the rest aresuperseded: true, linked viasupersedes_artifact_id/superseded_by_artifact_id. - Versions are never deleted or rewritten. Re-running a phase appends the next version; reverting flips the current pointer.
GET /v1/projects/{id}/artifacts?current_only=true (the default) returns just each phase's current version; current_only=false returns the full history. The portal's project page renders one card per phase with a version bar across the history.
Stale phases
When a phase's artifact changes (retrigger or revert), downstream phases that consumed the old version are out of date. What happens to them is the cascade mode:
| Mode | Downstream phases |
|---|---|
lazy (default) |
Marked stale — visible, not re-run. You decide what to re-run and when. |
strict |
Auto-invalidated and auto-retriggered. |
none |
Untouched — pinned against the old version. |
default |
Each phase's own cascade_on_upstream_change template setting. |
Stale is a first-class task status. The portal shows an amber Stale badge on affected phases (tasks table, task page, artifact card) and a Has stale phases chip in the project header, mirrored by the project's has_stale_phases field. A stale phase is terminal — retrigger it when you're ready.
Retrigger a phase
Portal: the Retrigger button on a phase's artifact card or task page (shown only for terminal phases). REST:
POST /v1/projects/{project_id}/phases/{phase_slug}/retrigger
{ "addendum_brief": "Tighten the hook in scene 1.", "cascade": "lazy" }
Both body fields are optional. The addendum brief is threaded into the re-run's prompt on top of the original instructions; the new attempt lands with attempt_reason: cascade_retrigger (or manual_retry/manual_rework on the retry paths) and its output becomes the phase's next artifact version.
Only terminal phases (succeeded / failed / skipped / stale) can be retriggered — a pending / running / blocked / review phase is already queued or mid-flight, and resetting it would stomp in-flight attempts. The API answers 409 in that case. The response lists affected_phase_slugs, marked_stale, auto_retriggered, and a history-based cost_estimate_usd.
Revert an artifact
Portal: Revert to this version in the artifact card's version bar (on superseded versions). REST:
POST /v1/projects/{project_id}/phases/{phase_slug}/revert-artifact
{ "target_version": 2, "cascade": "lazy", "reason": "v3 lost the vintage filter" }
The revert is a pointer flip, append-only: the target version becomes current again, newer versions stay in history, and downstream phases get the cascade treatment (lazy default = marked stale). Guards:
- 409 while the phase is
running/blocked/review— an in-flight promote would race the pointer flip. - 409 when the target version is already current.
- 404 for an unknown version.
Edit sessions
For scope changes that span phases — “swap scene 3's location to a rooftop garden” — use an edit session instead of hand-picking retriggers. Portal: the Edit with AI button in the project header. REST:
POST /v1/projects/{project_id}/edit-sessions
{ "instruction": "Swap scene 3's location to a rooftop garden", "cascade_mode": "lazy" }
This appends an edit_session task with three steps:
Planner (agent) — drafts a plan of concrete actions (retriggers, reverts) with rationale, cost and risk.
approve_plangate (human) — you review the plan on its subtask page. Decisions:approved,rejected,request_changes(send it back to the planner with a comment), oredit_plan(approve your ownrevised_planobject).POST /v1/projects/{project_id}/edit-sessions/{task_id}/approve { "decision": "approved" }Enact (system) — executes the approved plan with the session's cascade mode.
The create call returns the spawned task_id plus the planner/gate/enact subtask ids. 409 when the plan gate is already resolved; 404 when the task isn't an edit-session task of this project. The project's brief stays immutable throughout — edit sessions are the sanctioned way to change scope mid-flight.
SDK coverage
Retrigger, revert, and edit sessions are REST-only for now — the SDKs' projects namespace doesn't wrap them yet. projects.listArtifacts / list_artifacts returns current-only artifacts (the SDK doesn't pass current_only=false).
Next
- Portal → Projects — where the version bar and buttons live.
- Gates & approvals — the plan-approval gate in detail.
- Cost & budgets — what a retrigger costs before you pull the trigger.