Skip to content

fix: cancellation-aware failure semantics in finalize and on_failure handlers#76

Merged
joshua-temple merged 1 commit into
mainfrom
feat/cancellation-aware-finalize
Jun 10, 2026
Merged

fix: cancellation-aware failure semantics in finalize and on_failure handlers#76
joshua-temple merged 1 commit into
mainfrom
feat/cancellation-aware-finalize

Conversation

@joshua-temple

Copy link
Copy Markdown
Collaborator

Problem

Two correctness gaps in generated orchestrate workflows:

  1. The finalize failure guard tested only result == 'failure'. Under the default cancel-in-progress: true, a run superseded by a newer push ends in cancelled, not failure. The guard and finalize treated that as a non-event, so a deploy that progressed partway before being cancelled could leave the manifest stuck at a stale value, a state-integrity hole.
  2. A callback configured with on_failure: continue had no way to emit job-level continue-on-error, so a tolerated failure still painted the whole run red.

Change

  • The abort-callback failure guard now matches both outcomes via contains(fromJSON('["failure", "cancelled"]'), needs.<job>.result).
  • Callbacks with on_failure: continue emit continue-on-error: true on their jobs.<id> block.

Resulting semantics

  • success: callbacks succeed, finalize records state, run is green.
  • failure (abort callback): finalize still runs (if: always() && needs.setup.result == 'success'), records the state actually reached, then the failure guard fails the run.
  • cancelled (predecessor cancelled mid-flight): always() makes finalize fire so the reached state is recorded; the guard treats cancelled like failure. The per-deploy manifest write stays gated on == 'success', so a cancelled deploy is never recorded as deployed.
  • continue callback fails: continue-on-error keeps the run green; the callback is excluded from the abort guard but still appears in the summary and state.

A cancelled setup leaves finalize gated off, which is correct: no state was produced yet.

The retry-shim condition stays == 'failure' on purpose, a cancelled run is being torn down, not retried. Promote/external rollback gating is unchanged (out of scope; a cancelled promote should not auto-rollback).

Tests

New internal/generate/cancellation_test.go: finalize gate on cancelled predecessors, failure guard matches cancelled, on_failure: continue emits continue-on-error scoped to the right job, default case unchanged. Existing on-failure-continue golden assertions updated for the new condition form. Full suite green (go test ./...), go build ./... and gofmt -l clean.

Closes #38

…handlers

Signed-off-by: Joshua Temple <joshua.temple@stablekernel.com>
@joshua-temple
joshua-temple force-pushed the feat/cancellation-aware-finalize branch from a4047d1 to 1e8874c Compare June 10, 2026 09:08
@joshua-temple
joshua-temple merged commit e713741 into main Jun 10, 2026
4 checks passed
@joshua-temple
joshua-temple deleted the feat/cancellation-aware-finalize branch June 10, 2026 09:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: cancellation-aware failure semantics in finalize and on_failure handlers

1 participant