Keep Going Past a Failed Member
Show the whole prompt
Read https://intentius.io/chant/guide/failed-member-blocks/.
Regenerate this repository's wave pipeline with the flags it was generated with, so each wave job after the first runs when the one before it failed, and open a pull request with the pipeline.
Show me the `if:` (GitHub, Forgejo) or `when:` (GitLab) each wave job got.
Never deploy to a real cloud account or shared environment (with `chant run`, `chant components` or a platform's own CLI), approve (a pull request review, `chant approve` or `chant run approve`), override a policy denial (`chant approve policy-override`), or merge; never cut or publish a release (`chant release cut --yes` or `chant release publish`), push or delete a `ci/*` tag (`chant ci tick` pushes them), or change the value of an existing flag; never touch `.chant/allowed_signers` or `chant/lifecycle`.Optional: hand this page to your coding agent
Read https://intentius.io/chant/guide/failed-member-blocks/.Regenerate this repository's wave pipeline with the flags it was generated with, so each wave job after the first runs when the one before it failed, and open a pull request with the pipeline.Show me the `if:` (GitHub, Forgejo) or `when:` (GitLab) each wave job got.Never deploy to a real cloud account or shared environment (with `chant run`, `chant components` or a platform's own CLI), approve (a pull request review, `chant approve` or `chant run approve`), override a policy denial (`chant approve policy-override`), or merge; never cut or publish a release (`chant release cut --yes` or `chant release publish`), push or delete a `ci/*` tag (`chant ci tick` pushes them), or change the value of an existing flag; never touch `.chant/allowed_signers` or `chant/lifecycle`.A run applied a wave at a time can lose one component and still finish the others. When a component fails to plan or to apply, chant blocks each component that reads from it, and everything else goes ahead. A component that reads from a blocked one is blocked too. This holds in pr-apply with a gate per wave (pr-apply --wave-gate) and in a gated-wave fan-out (chant components fan-out --wave-gate), whether the waves run in one job or one job per wave (#4291).
Generate the wave jobs
Section titled “Generate the wave jobs”A generated wave pipeline gives each wave job after the first a condition that runs it when the job before it failed. Regenerate it with the flags it was generated with:
chant build --components --generate github --pr-loop --apply-on-merge --wave-gate release --env prod --output .github/workflows/chant-pr.ymlOn GitHub and Forgejo, apply-wave-2 gets if: !cancelled() && needs.apply-wave-1.result != 'skipped' && (...), where the part in brackets is the job’s own trigger (afterEarlierWave, lexicons/github/src/components/ci-jobs.ts:57). A skipped or cancelled job before it still stops it. On GitLab the job’s rule gets when: always (lexicons/gitlab/src/components/generate-pipeline.ts:368). A gated-wave fan-out pipeline’s wave-2 gets the same condition (lexicons/github/src/components/generate-pipeline.ts:161, lexicons/gitlab/src/components/generate-pipeline.ts:262).
The attempt record is kept even when a job fails. That is how the next wave learns what failed.
What a wave job does after a failure
Section titled “What a wave job does after a failure”Say wave 1 holds net and db, and wave 2 holds app, which reads net, and web, which reads db. db fails to apply.
- Wave 1 applies
net, recordsdbas failed, and exits 1. - Wave 2 runs anyway. It blocks
webbehinddband deploysapp(packages/core/src/cli/handlers/pr.ts:1584). - Since a member of wave 2 is blocked, that job exits 1 too (
packages/core/src/cli/handlers/pr.ts:1732).
A component blocked behind a blocked component names the one that failed, not the one in between (blockedMembers, packages/core/src/wave-blocked.ts:85). The job log prints the blocked set:
wave 2: web (blocked by db), so not planned or appliedA member of a later wave that fails to plan stops its own wave from applying. The waves after it still run what does not read from it (packages/core/src/cli/handlers/pr.ts:1626).
A wave that waits at its gate still stops every wave after it. The next wave’s job refuses with exit 3 and applies nothing until that gate is approved and its job runs again (packages/core/src/cli/handlers/pr.ts:1482, packages/core/src/components/fan-out-run.ts:554).
Read the blocked set in the note
Section titled “Read the blocked set in the note”The pull-request note gives each blocked member’s status as blocked by <component>, and lists the set below the table (blockedLine, packages/core/src/pr-loop.ts:497):
| `web` | web | blocked by `db` | 0 | 1 | 0 | 0 |
Blocked, so not applied: `web` (blocked by `db`). A failure blocks only the members that depend on it, so the rest went on.The headline counts them: The apply failed: 1 failed, 1 blocked, 3 applied. The report’s members[].blockedBy carries the same name.
Finish the apply
Section titled “Finish the apply”Fix what failed, then re-run the failed jobs. On GitHub, re-running the failed jobs runs wave 1’s job and every job after it.
- Wave 1 deploys
dband skipsnet, which succeeded the first time. - Wave 2 deploys
web.appis left alone, since its earlier run stands.
A component stays failed in the record until it succeeds (packages/core/src/cli/handlers/fan-out.ts:337), so each later wave’s job knows to block its dependents.
Use the rules from your own pipeline
Section titled “Use the rules from your own pipeline”A product that runs waves in its own CI stages can import the same rules from @intentius/chant/wave-blocked. It has blockedMembers, settleEarlierWaves, onlyWaiting, blockedWords, runSummary, and the outcome files a wave job hands the next one (writeWaveOutcomeFile and earlierWaveOutcomes, packages/core/src/wave-blocked.ts:191 and :245). The module imports only node:fs and node:path, so it bundles into a single file.
A component’s outcome is one of applied, unchanged, failed, waiting, refused, decided, not-applied or blocked. Only applied and unchanged let a dependent through.