Skip to content

feat(workflows): add always_run node opt-out for resume caching (closes #1391)#1730

Merged
Wirasm merged 2 commits into
coleam00:devfrom
truffle-dev:feat/workflow-always-run-1391
May 21, 2026
Merged

feat(workflows): add always_run node opt-out for resume caching (closes #1391)#1730
Wirasm merged 2 commits into
coleam00:devfrom
truffle-dev:feat/workflow-always-run-1391

Conversation

@truffle-dev
Copy link
Copy Markdown
Contributor

@truffle-dev truffle-dev commented May 20, 2026

Summary

  • Problem: When a DAG workflow auto-resumes, every node that completed successfully in the prior run is skipped, and downstream consumers read the cached output. That is wrong when a node's exit code does not capture output validity — typically a producer that writes a file or side-effect the consumer parses on each run. A bash producer that exits 0 but writes garbage stays "successfully cached" across every resume, with no escape short of renaming the node.
  • Why it matters: Issue Auto-resume cache traps workflows on "successful" producer with bad output — only escape is renaming the node #1391 documents the trap: there is no per-node knob to say "this node is a side-effecting producer whose success status does not validate its output, re-run it on resume." Users hit it with download scripts, code generators, and any bash node whose downstream consumer parses the file.
  • What changed: New optional always_run: boolean field on every DAG node. When true, the node re-executes on resume even when priorCompletedNodes says it completed — both the resume pre-populate and the per-node skip-check honor the flag.
  • What did NOT change: Default behavior is unchanged (skip on prior success). Normal cached nodes in the same run still skip. The flag is per-node and opt-in. No schema migration, no DB change, no impact on fresh-run scheduling.

UX Journey

Before

Workflow author          Resume                   Producer node
───────────────          ──────                   ─────────────
bash node writes file ─▶ priorCompletedNodes      first run: writes garbage, exits 0
consumer parses file     has producer.id          ↓
                         ↓                        marked completed
                         skips producer           ↓
                         feeds cached output ───▶ next resume: skipped FOREVER
                                                  ❌ consumer reads stale file
                                                  only escape: rename the node

After

Workflow author          Resume                   Producer node
───────────────          ──────                   ─────────────
bash producer node ────▶ priorCompletedNodes      always_run: true on producer
  always_run: true       has producer.id          ↓
consumer parses file     ↓                        always re-executes on resume
                         pre-populate skips it    ↓
                         skip-check skips it ──▶  writes fresh file
                                                  ✅ consumer reads fresh output
                         normal nodes still skip

Architecture Diagram

Before

executeDagWorkflow
  │
  ├─▶ buildTopologicalLayers
  │
  ├─▶ priorCompletedNodes pre-populated into nodeOutputs (all completed nodes)
  │
  └─▶ per-node executor
        └─ if priorCompletedNodes.has(node.id) → skip, emit node_skipped_prior_success

After

executeDagWorkflow
  │
  ├─▶ buildTopologicalLayers
  │
  ├─▶ priorCompletedNodes pre-populated [~] — filters out always_run nodes
  │
  └─▶ per-node executor
        ├─ if priorCompletedNodes.has(node.id) AND node.always_run [+]
        │    → emit dag.node_always_run_resume_forced, fall through to normal execution
        └─ if priorCompletedNodes.has(node.id) AND NOT node.always_run
             → skip, emit node_skipped_prior_success (existing behavior)

Connection inventory:

From To Status Notes
dagNodeBaseSchema DagNode types [~] adds always_run?: boolean to all variants
dag-node transform base spread [~] passes through always_run when defined
executeDagWorkflow pre-populate nodeOutputs [~] excludes always_run nodes from pre-populate
per-node skip-check always_run gate [+] new log event when always_run forces re-run
consumers reading $producer.output fresh-run path unchanged — downstream sees re-run output via normal layer ordering

Label Snapshot

  • Risk: risk: low
  • Size: size: S
  • Scope: workflows
  • Module: workflows:dag-executor, workflows:schemas

Change Metadata

  • Change type: feature
  • Primary scope: workflows

Linked Issue

Validation Evidence

bun run type-check    # all 10 packages clean
bun run lint          # 0 errors, 0 warnings
bun run format:check  # all files use Prettier code style
bun run test          # full workflows suite green, 3 new dag-executor tests + 1 new loader test

New tests cover:

  • always_run node re-runs even when present in priorCompletedNodes (no node_skipped_prior_success event)
  • mixed run: always_run re-executes; sibling normal node still skips
  • downstream consumer reads fresh producer output, not the pre-populated cached value
  • schema parses always_run: true and leaves it undefined when omitted

Security Impact

  • New permissions/capabilities? No
  • New external network calls? No
  • Secrets/tokens handling changed? No
  • File system access scope changed? No

Compatibility / Migration

  • Backward compatible? Yes — field is optional, defaults to off, no existing workflow YAML needs to change.
  • Config/env changes? No
  • Database migration needed? No

Human Verification

  • Verified the schema accepts always_run: true on a real two-node YAML (fetch-data bash producer + process-data consumer); the parsed AST exposes the field; consumer reads fresh output post-resume.
  • Confirmed default behavior unchanged by running the existing dag-executor resume tests (138 pass, 0 fail) alongside the new always_run tests.
  • Sanity-checked that the pre-populate exclusion does not strand downstream consumers: when an always_run producer is in a later layer, the consumer still resolves through the normal post-execution nodeOutputs.set(...) write.

What was not verified beyond CI:

  • End-to-end resume run via the CLI (archon workflow run ... --resume) was not exercised — the dag-executor unit tests directly drive the same code path via priorCompletedNodes.

Side Effects / Blast Radius

  • Affected subsystems: only packages/workflows/src/dag-executor.ts resume pre-populate + skip-check, packages/workflows/src/schemas/dag-node.ts schema field.
  • Potential unintended effects: none expected for default-off behavior. If an author sets always_run: true on a node whose downstream consumer depends on idempotency, the consumer must tolerate re-execution — same contract as any producer node.
  • Guardrails: new structured log event dag.node_always_run_resume_forced surfaces every time the flag fires, so operators can see resume behavior in workflow logs.

Rollback Plan

  • Fast rollback: revert the commit. Resume falls back to current behavior (always skip cached nodes). Authors who set always_run would see the field ignored — Zod still parses it (optional unknown field), no runtime error.
  • Observable failure symptoms: if a node's resume behavior changes unexpectedly, grep workflow logs for dag.node_always_run_resume_forced to identify which node opted out.

Risks and Mitigations

  • Risk: A node author sets always_run: true on a destructive node (e.g. rm -rf <dir>) and triggers it on every resume.
    • Mitigation: documented in the authoring guide as "opt out of resume caching" with an example showing the producer/consumer use case. The flag is per-node, explicit, and visible in the YAML.
  • Risk: Pre-populate exclusion accidentally strands downstream consumers that depend on the cached value being present before the producer re-runs.
    • Mitigation: downstream nodes are by definition in a later topological layer than the producer; nodeOutputs.set(...) writes the fresh value before the consumer's substituteNodeOutputRefs call. Test 3 in the new suite asserts this end-to-end.

Summary by CodeRabbit

  • New Features

    • Added an always_run node option to opt a node out of resume caching so it is re-executed on workflow resume.
  • Behavior

    • Resuming workflows now forces always_run nodes to rerun and emits a dedicated workflow event when prior outputs are reset.
  • Documentation

    • Added guidance and examples on opting out of resume caching and when to use always_run.
  • Tests

    • Added tests validating parsing, resume behavior, event emission, and downstream output propagation.

Review Change Stack

Closes coleam00#1391.

Adds an optional `always_run: boolean` field on every DAG node. When
`true`, the node re-executes on resume even if it completed in the
prior run. The resume pre-populate filters out always_run node IDs,
and the per-node skip-check is gated by `!node.always_run`.

Use case: producers whose exit code does not validate their output
(bash that writes a file the consumer parses, code generators, fetch
scripts). Today a successful-but-garbage producer stays cached across
every resume; the only escape is renaming the node.

Default is unchanged. Normal cached nodes in the same run still skip.
Emits a new `dag.node_always_run_resume_forced` log event so operators
can see the flag firing.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 20, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1c7ca70d-623a-4a56-a6f0-c72d855a78ed

📥 Commits

Reviewing files that changed from the base of the PR and between 9b3a433 and 9a8f1c4.

📒 Files selected for processing (3)
  • packages/workflows/src/dag-executor.test.ts
  • packages/workflows/src/dag-executor.ts
  • packages/workflows/src/store.ts

📝 Walkthrough

Walkthrough

This PR adds an optional always_run: boolean DAG node field that opts a node out of resume caching; always_run: true nodes are excluded from resume pre-population, emit a node_always_run_reset event, and are re-executed on workflow resume so downstream consumers receive fresh outputs.

Changes

always_run Resume Opt-Out Feature

Layer / File(s) Summary
Schema definition and YAML parsing
packages/workflows/src/schemas/dag-node.ts, packages/workflows/src/loader.test.ts
dagNodeBaseSchema adds optional always_run: boolean with documentation; dagNodeSchema transform propagates it to node objects. Loader test verifies YAML parsing captures always_run: true on the specified node.
Executor resume logic and tests
packages/workflows/src/dag-executor.ts, packages/workflows/src/dag-executor.test.ts, packages/workflows/src/store.ts
Resume pre-population omits always_run nodes so they are not treated as already completed. Per-layer logic forces re-execution for always_run nodes, logs dag.node_always_run_resume_forced, emits node_always_run_reset with prior_output, and continues normal evaluation; non-always_run nodes remain skipped and emit node_skipped_prior_success. Tests validate forced rerun, mixed-graph behavior, downstream prompt/output freshness, and baseline setup. WORKFLOW_EVENT_TYPES gains 'node_always_run_reset'.
User documentation
packages/docs-web/src/content/docs/guides/authoring-workflows.md
Node options table updated with always_run. New "Opting Out of Resume Caching" section explains when cached-success replay is unsafe for side-effect producers and shows a YAML example demonstrating downstream nodes reading fresh artifacts on resume.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

  • coleam00/Archon#1391: Implements the always_run: true escape hatch proposed to avoid the auto-resume cache trap when a producer exits 0 but produces bad/stale artifacts.

Possibly related PRs

  • coleam00/Archon#1530: Also modifies DAG resume/caching logic in executeDagWorkflow; related to when nodes are skipped and how resume state is applied.
  • coleam00/Archon#1646: Refactors resume-state hydration and touches the workflow resume pipeline that this PR further extends with always_run handling.

"🐰 I hop through runs, refusing cached rest,
Mark always_run true — I’ll prove I'm the best.
Fresh artifacts served, no stale crumbs in sight,
Resume with true running — the workflow feels right!"

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately describes the feature implementation — adding an always_run node opt-out for resume caching — and references the specific issue (#1391) being addressed.
Description check ✅ Passed The PR description comprehensively follows the template structure with all required sections: Summary (4 bullets), UX Journey (Before/After), Architecture Diagram with Connection inventory, Labels, Change Metadata, Linked Issue, Validation Evidence, Security Impact, Compatibility, Human Verification, Side Effects, Rollback Plan, and Risks/Mitigations.
Linked Issues check ✅ Passed The code changes fully satisfy the core objectives from #1391: a per-node always_run boolean field forces re-execution on resume [dag-node.ts, dag-executor.ts], excludes always_run nodes from pre-population [dag-executor.ts], emits audit event node_always_run_reset for forensics [store.ts], includes tests validating re-execution + fresh output [dag-executor.test.ts, loader.test.ts], and docs explanation in authoring guide [docs-web].
Out of Scope Changes check ✅ Passed All changes align with the linked issue scope: schema extension (dag-node.ts), executor logic (dag-executor.ts), event types (store.ts), tests (dag-executor.test.ts, loader.test.ts), and docs (authoring-workflows.md). No unrelated refactoring, infrastructure, or subsystem modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
packages/workflows/src/dag-executor.test.ts (1)

4807-4851: ⚡ Quick win

Assert the forced-resume log event for always_run nodes.

This validates rerun semantics, but it doesn’t verify the promised dag.node_always_run_resume_forced emission. Adding that assertion will catch observability regressions alongside behavior regressions.

Suggested test assertion
   it('re-runs node flagged always_run even when present in priorCompletedNodes', async () => {
     const store = createMockStore();
     const mockDeps = createMockDeps(store);
     const platform = createMockPlatform();
     const workflowRun = makeWorkflowRun();
+    mockLogFn.mockClear();

     const priorCompletedNodes = new Map([['producer', 'cached stale output']]);

     await executeDagWorkflow(
       mockDeps,
@@
     const skippedEvent = eventCalls.find(
       (call: unknown[]) =>
         (call[0] as { event_type: string }).event_type === 'node_skipped_prior_success' &&
         (call[0] as { step_name: string }).step_name === 'producer'
     );
     expect(skippedEvent).toBeUndefined();
+
+    const forcedResumeLogs = mockLogFn.mock.calls.filter((call: unknown[]) =>
+      call.some(
+        arg => typeof arg === 'string' && arg.includes('dag.node_always_run_resume_forced')
+      )
+    );
+    expect(forcedResumeLogs.length).toBeGreaterThan(0);
   });

As per coding guidelines, "Use structured logging with Pino; event naming format: {domain}.{action}_{state} with standard states: _started, _completed, _failed, _validated, _rejected".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/workflows/src/dag-executor.test.ts` around lines 4807 - 4851, The
test it('re-runs node flagged always_run even when present in
priorCompletedNodes', ...) currently checks behavior but does not assert the
structured log/event emission for forced resume; update the test to assert that
store.createWorkflowEvent was called with an event having event_type
'dag.node_always_run_resume_forced' and step_name 'producer' (alongside the
existing skippedEvent check and mockSendQueryDag assertions) so the test
verifies the dag.node_always_run_resume_forced emission from the code paths that
rerun always_run nodes.
packages/docs-web/src/content/docs/guides/authoring-workflows.md (1)

575-576: 💤 Low value

Consider clarifying "same run" phrasing for precision.

The phrase "Normal cached nodes in the same run are still skipped" is potentially ambiguous in the context of resume behavior. Readers might wonder whether "same run" refers to the resume run or to same-run (non-resume) caching behavior.

✏️ Suggested clearer phrasing
-On resume, `fetch-data` re-runs regardless of prior success, so `process-data` reads a freshly produced file. Normal cached nodes in the same run are still skipped — `always_run` is per-node.
+On resume, `fetch-data` re-runs regardless of prior success, so `process-data` reads a freshly produced file. Other nodes without `always_run` are still skipped as normal — the flag is per-node.

Alternative:

-On resume, `fetch-data` re-runs regardless of prior success, so `process-data` reads a freshly produced file. Normal cached nodes in the same run are still skipped — `always_run` is per-node.
+On resume, `fetch-data` re-runs regardless of prior success, so `process-data` reads a freshly produced file. Non-`always_run` nodes in the resumed workflow remain skipped — the flag is per-node.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/docs-web/src/content/docs/guides/authoring-workflows.md` around
lines 575 - 576, Update the sentence "Normal cached nodes in the same run are
still skipped — `always_run` is per-node." to explicitly state that "same run"
refers to the resumed execution (the resume run), e.g. replace with wording
like: "During a resume, cached nodes that were up-to-date at the start of the
resume run are still skipped — `always_run` applies per node." Locate and change
the sentence following the explanation that "`fetch-data` re-runs regardless of
prior success" so readers understand "same run" means the resume run rather than
the original run.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/docs-web/src/content/docs/guides/authoring-workflows.md`:
- Around line 575-576: Update the sentence "Normal cached nodes in the same run
are still skipped — `always_run` is per-node." to explicitly state that "same
run" refers to the resumed execution (the resume run), e.g. replace with wording
like: "During a resume, cached nodes that were up-to-date at the start of the
resume run are still skipped — `always_run` applies per node." Locate and change
the sentence following the explanation that "`fetch-data` re-runs regardless of
prior success" so readers understand "same run" means the resume run rather than
the original run.

In `@packages/workflows/src/dag-executor.test.ts`:
- Around line 4807-4851: The test it('re-runs node flagged always_run even when
present in priorCompletedNodes', ...) currently checks behavior but does not
assert the structured log/event emission for forced resume; update the test to
assert that store.createWorkflowEvent was called with an event having event_type
'dag.node_always_run_resume_forced' and step_name 'producer' (alongside the
existing skippedEvent check and mockSendQueryDag assertions) so the test
verifies the dag.node_always_run_resume_forced emission from the code paths that
rerun always_run nodes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 87c9efac-1536-44e1-91ff-055c8622b34c

📥 Commits

Reviewing files that changed from the base of the PR and between 5283ea9 and 9b3a433.

📒 Files selected for processing (5)
  • packages/docs-web/src/content/docs/guides/authoring-workflows.md
  • packages/workflows/src/dag-executor.test.ts
  • packages/workflows/src/dag-executor.ts
  • packages/workflows/src/loader.test.ts
  • packages/workflows/src/schemas/dag-node.ts

@Wirasm
Copy link
Copy Markdown
Collaborator

Wirasm commented May 20, 2026

Review Summary

Verdict: blocking-issues

This PR adds always_run: true to opt individual workflow nodes out of resume caching. The feature intent and schema additions are sound, and the documentation is well-written. However, a critical logic error in the skip guard causes the always_run re-execute path and the normal skip path to both fire for the same node — which means the feature won't behave as documented until that bug is fixed. Additionally, the JSONL workflow log is missing an audit entry for always_run nodes, making it impossible to reconstruct resume decisions from logs.

Blocking issues

  • packages/workflows/src/dag-executor.ts:2644-2651: The always_run condition is nested inside the normal skip block, causing both re-execute and skip paths to fire for the same node. Move the always_run re-execute case before the skip block and invert the guard:

    // always_run nodes re-execute even when in priorCompletedNodes
    if (priorCompletedNodes?.has(node.id) && node.always_run) {
      getLog().info({ nodeId: node.id }, 'dag.node_always_run_resume_forced');
      continue;  // ← re-execute and exit, don't fall into skip block
    }
    
    // normal skip path — only for nodes NOT flagged always_run
    if (priorCompletedNodes?.has(node.id) && !node.always_run) {
      // existing skip logic...
    }

    Also ensure the pre-population loop (lines 2596-2602) excludes always_run nodes so downstream $nodeId.output consumers get fresh output, not stale cached data:

    if (priorCompletedNodes?.has(node.id) && !node.always_run) {
      nodeOutputs.set(node.id, { ... });
    }
  • packages/workflows/src/dag-executor.ts:2634-2657: The always_run re-execute path doesn't call logNodeSkip() to write an audit entry to the JSONL workflow log. All other skip paths do this — always_run is the only one that omits it. Add:

    await logNodeSkip(logDir, workflowRun.id, node.id, 'always_run').catch(
      (err: Error) => {
        getLog().warn({ err, nodeId: node.id }, 'dag.node_skip_log_write_failed');
      }
    );
    getWorkflowEventEmitter().emit({
      type: 'node_skipped',
      runId: workflowRun.id,
      nodeId: node.id,
      nodeName: node.command ?? node.id,
      reason: 'always_run',
    });

Suggested fixes

  • packages/workflows/src/schemas/dag-node.ts:543: always_run is added to base but not to the per-variant returns (BashNode, ScriptNode, CommandNode, PromptNode). Add it explicitly to each return path, or add a comment noting it flows from base.

  • packages/workflows/src/dag-executor.test.ts: Add a test for always_run: true in a parallel layer with a non-always_run sibling — assert the always_run node re-executes while the sibling is skipped. Also add a test for explicit always_run: false in priorCompletedNodes to verify the skip path fires correctly.

  • packages/docs-web/src/content/docs/guides/authoring-workflows.md: The example comment could reference the bug it fixes — add (see #1391) after "download.sh exit code doesn't validate the JSON".

Minor / nice-to-have

  • packages/workflows/src/dag-executor.ts:2647: Remove See #1391. from the comment — the surrounding text explains the intent without it, and PR numbers become opaque over time.

  • dag-executor.test.ts:4816-4823: Once the logNodeSkip() fix above is applied, update the test re-runs node flagged always_run to assert the always_run reason event IS present (or filter it out for separate testing).

Compliments

  • The always_run exclusion comment in the pre-population loop is a model of useful documentation — it captures a subtle invariant (downstream consumers must see fresh output) that isn't obvious from the code alone.
  • The schema approach of adding always_run to dagNodeBaseSchema and flowing it through via base spread is clean and avoids duplicating the field across six node type constructors.
  • The dag.node_always_run_resume_forced log event name follows the established convention perfectly.

Reviewed via maintainer-review-pr workflow (Pi/Minimax). Aspects run: code-review, error-handling, test-coverage, comment-quality, docs-impact.

The always_run resume-forced path only wrote a structured log line.
The prior_success skip path writes a DB workflow_event, so resume
forensics could see skipped nodes but not nodes that were reset from
the skip list. Add a symmetric node_always_run_reset event with the
prior output so operators can reconstruct resume decisions from the
workflow_events table.

Drop the trailing PR reference from the comment — surrounding text
explains intent.
@truffle-dev
Copy link
Copy Markdown
Contributor Author

Blocking issues

  1. dag-executor.ts:2644-2651always_run and skip paths firing together. They cannot — the two checks are separate if statements at the same nesting level with mutually exclusive guards:

    if (priorCompletedNodes?.has(node.id) && node.always_run) {
      getLog().info(...)  // log + reset event, no return
    }
    if (priorCompletedNodes?.has(node.id) && !node.always_run) {
      ...                 // skip block ending in `return`
    }

    For any given node, node.always_run and !node.always_run cannot both be true, so at most one branch fires. When always_run fires, the function falls through to the trigger-rule check and normal execution — the skip block's return is unreachable for that node. The suggested continue rewrite would actually break the feature: inside layer.map(async (node) => ...), continue is a syntax error, and a return there would short-circuit the always_run node before it executes.

    No change.

  2. dag-executor.ts:2634-2657 — missing audit entry for always_run. Valid concern on the DB side, with one wrinkle: emitting node_skipped with reason 'always_run' (or calling logNodeSkip(... 'always_run')) is semantically wrong — the node is being re-executed, not skipped. The downstream consumers in packages/cli/src/commands/workflow.ts and packages/core/src/db/workflow-events.ts treat node_skipped* rows as "this node did not run."

    Added a distinct node_always_run_reset workflow event so resume forensics can see the opt-out without conflating it with a skip. The node's own node_started / node_completed events still fire as normal after that. (9a8f1c47)

Suggested fixes

  1. schemas/dag-node.ts:543always_run not in per-variant returns. It does flow through — every variant return spreads ...base (lines 576, 579, 583, 593, 602, 605, 609), and base includes always_run at line 546. The loader test at loader.test.ts:680-702 parses YAML with always_run: true and asserts workflows[0].nodes[0].always_run === true. The TypeScript variant types declare always_run via dagNodeBaseSchema, so it's typed on every node.

  2. Test for parallel sibling. Already covered at dag-executor.test.ts:4853 ("still skips non-always_run nodes in the same priorCompletedNodes set") — producer (always_run: true) and cached have no depends_on so they share the first parallel layer, and the test asserts the producer re-runs while the sibling emits node_skipped_prior_success. The explicit always_run: false case is the default behavior covered by every other resume test in the suite.

  3. authoring-workflows.md — add (see #1391) to the example. Skipping. Issue numbers go opaque to users six months out; the example already states why the comment matters ("download.sh exit code doesn't validate the JSON").

Minor

  1. Remove See #1391. from the comment. Done. (9a8f1c47)

  2. Update the re-runs node flagged always_run test after the audit fix. Done in the same commit — now asserts the node_always_run_reset event IS emitted with the prior_output payload, in addition to the existing assertion that node_skipped_prior_success is NOT. (9a8f1c47)

@Wirasm Wirasm merged commit 8028521 into coleam00:dev May 21, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Auto-resume cache traps workflows on "successful" producer with bad output — only escape is renaming the node

2 participants