Skip to content

Preserve artifact authority and dynamic ancestry across continuation #1142

Closed

Description

@aviggiano

Suggested labels: bug, priority:P0, recovery, artifacts

Problem

Continuation can lose manifests, verification markers, or dynamic fan-out membership. A later output replacement can also invalidate authority for a consumer that was already admitted. Downstream verification then rejects artifacts that were previously accepted.

Generic reproduction

  1. Run a workflow with dynamic fan-out followed by aggregation.
  2. Interrupt the controller after some dynamic nodes verify successfully.
  3. Resume and regenerate one upstream output.
  4. Observe missing ancestors, missing verification authority, or dependency authority changed after admission.

Expected behavior

Verified generations are immutable. Consumers retain the exact generation admitted for their attempt, and continuation reconstructs the same dynamic ancestry.

Proposed fix

  • Store each artifact generation in an immutable attempt directory.
  • Publish the current verified generation through an atomic pointer.
  • Never delete the last verified manifest before its replacement verifies.
  • Persist dynamic fan-out membership in the durable graph.
  • Add a repair command that rebuilds manifests and verification indexes from immutable records.

Acceptance criteria

  • Controller loss during dynamic fan-out can be resumed through final aggregation.
  • A consumer's admitted authority cannot change mid-attempt.
  • All successful dynamic ancestors survive continuation.
  • Failed replacement does not destroy the prior verified generation.

This issue intentionally omits the audited repository and all audit results.

Activity

  1. added
    bugSomething isn't working
    In ProgressClaimed and actively worked on; has an assignee. Remove if work stops.
    on Sep 25, 2026
  2. aviggiano commented on Sep 29, 2026

    @aviggiano
    CollaboratorAuthor

    Resolved by #1163 (with #1169 and #1192 for the recovery side).

    The verified failure paths were in loadOrCreateDynamicExpansion, which treated the published expansion manifest as a cache to re-prove on every render:

    • a source that re-ran after a reset made every later render fail ("source missing", then DYNAMIC_EXPANSION_CHANGED forever);
    • a stale .expansion.lock left by a killed process blocked every render.

    #1163 makes the published manifest the lock-free authority for fan-out membership: the source is read only when the manifest is created, and the lock is removed. After a reset regenerates a source, the fan-out keeps its published items. An explicit --retry-failed of the source itself still re-expands.

    Deliberately not built: immutable per-attempt generation directories, an atomic current-generation pointer and a repair command (as drafted in #1154). Reviewers found that store checked a copy no consumer reads, while weakening the existing fail-closed admission check.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    In ProgressClaimed and actively worked on; has an assignee. Remove if work stops.bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions