Skip to content

Block a partial publish when a build fails - #42

Merged
ptr727 merged 1 commit into
developfrom
feature/block-partial-publish
Aug 3, 2026
Merged

Block a partial publish when a build fails#42
ptr727 merged 1 commit into
developfrom
feature/block-partial-publish

Conversation

@ptr727

Copy link
Copy Markdown
Owner

The one behavioral defect the audit found, and it is live today.

WORKFLOW.md D4.5 requires that a build failure block every publish target. This repo's WORKFLOW.md was missing the guarantee entirely, and the pipeline did not satisfy it.

The defect

build-docker:
needs: [get-version, validate, validate-release] # no build-executableif: ${{ !cancelled() && ... }} # cancellation only

The image builds from source and consumes no executable artifact, so the two builds were independent and nothing forced an ordering. On a real publish where build-executable fails:

JobBeforeResult
build-executablefails-
github-releaseneeds it, so it skipsno tag, no release
build-dockeruntouched, runsmulti-arch image pushed, latest moves

An image shipped with no release behind it. That is exactly the partial publish D4.5 exists to prevent.

The fix

build-docker becomes the terminal publish target: it needsbuild-executable, and its if gains !failure().

The distinction that matters is failed versus skipped. A failed upstream build must stop the push; a skipped one must not, because validate is skipped on every smoke run and that run still has to build the image. !failure() draws exactly that line. The explicit get-version and validate-release result checks stay, so a job that somehow did not run cannot feed empty version inputs into a build.

Reasoning, since the failure path is not reachable from a PR

Smoke never publishes, so no pull request can exercise a failing real publish. The behavior is established from the needs graph rather than by observation:

Casefailure()build-dockergithub-release
smoke PR (validate skipped)falseruns, push: falseskipped (!inputs.smoke)
real publish, all greenfalseruns, pushesruns
real publish, build-executable failstrueskippedskipped
real publish, validate failstrueskippedskipped
real publish, validate-release failstrueskippedskipped

The smoke row is the one that would break if !failure() were the wrong guard, and this PR's own CI run is that row.

Cost

On smoke, build-docker now waits for build-executable instead of running beside it, adding roughly the executable build's duration to PR feedback. Correctness over a subset of the wall clock.

D4.5 lands here, not in #40

The doc-refresh PR deliberately left it out. Stating the guarantee before implementing it would have replaced a silent gap with a false claim, so the contract and the code that satisfies it land together.

Verification

  • actionlint clean.
  • dotnet husky run clean, editorconfig-checker clean, hub prose gate clean on the changed lines.
  • The smoke path is exercised by this PR's own checks.

Last of four in the round. Follows #39, #40 and #41. If #40 merges first this may need a trivial rebase - both touch WORKFLOW.md D4, two lines apart.

🤖 Generated with Claude Code

WORKFLOW.md D4.5 requires that a build failure block every publish target.
This repo's WORKFLOW.md was missing the guarantee entirely, and the
pipeline did not satisfy it.
build-docker needed only [get-version, validate, validate-release] and
guarded solely on cancellation. The image builds from source and consumes
no executable artifact, so the two builds were independent and nothing
forced an ordering. On a real publish where build-executable failed,
github-release skipped, so no tag and no release were cut, while
build-docker was untouched and pushed the multi-arch image anyway, moving
`latest`. An image shipped with no release behind it.
build-docker becomes the terminal publish target: it needs
build-executable, and its `if` gains `!failure()`. The distinction that
matters is failed versus skipped. A failed upstream build must stop the
push, and a skipped one must not, because `validate` is skipped on every
smoke run and that run still has to build the image. The explicit
get-version and validate-release result checks stay, so a job that somehow
did not run cannot feed empty version inputs into a build.
The cost is on smoke, where build-docker now waits for build-executable
instead of running beside it, adding roughly the executable build's
duration to PR feedback. Correctness over a subset of the wall clock.
WORKFLOW.md gains D4.5 in the same commit rather than in the doc-refresh
PR ahead of it, so the contract and the code that satisfies it land
together instead of the file claiming a guarantee the pipeline breaks.
The failure path is not reachable from a pull request, since smoke never
publishes, so it is established from the needs graph rather than by
observation. actionlint passes.
Audit run 2026-08-03T16:52:36Z, hub 1ed0cc8, against develop@39c896b.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CopilotAI review requested due to automatic review settings August 3, 2026 17:31
@codecov

codecovBot commented Aug 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 43.37%. Comparing base (39c896b) to head (3d4b882).

Additional details and impacted files
@@ Coverage Diff @@## develop #42 +/- ##
========================================
Coverage 43.37% 43.37% ========================================
Files 28 28 Lines 3896 3896 Branches 306 306 ========================================
Hits 1690 1690 Misses 2154 2154 Partials 52 52 

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

CopilotAI approved these changes Aug 3, 2026

CopilotAI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟢 Ready to approve

The workflow dependency/guard changes correctly prevent Docker publishing on upstream build failure without breaking the smoke (skipped-validate) path described in the PR.

This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.

Pull request overview

This PR closes a real release/publish correctness gap by ensuring Docker publishing cannot proceed when an upstream build job fails, aligning the workflow behavior with WORKFLOW.md’s D4.5 contract.

Changes:

  • Document the “no partial publish” guarantee (D4.5) in WORKFLOW.md.
  • Update the release workflow so build-docker depends on build-executable and is gated by !failure() (while still allowing skipped smoke-only validation).
File summaries
FileDescription
WORKFLOW.mdAdds D4.5 to explicitly require that any failed enabled build blocks all publish targets (including Docker).
.github/workflows/build-release-task.ymlMakes build-docker depend on build-executable and adds !failure() to prevent Docker pushes when any upstream dependency failed, while preserving smoke behavior when validate is skipped.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Lite

We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.

@ptr727
ptr727 merged commit 252f5c5 into developAug 3, 2026
14 checks passed
@ptr727
ptr727 deleted the feature/block-partial-publish branch August 18, 2026 17:19
Sign up for freeto 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.

2 participants

@ptr727