probe(756): DO NOT MERGE — does a failing continue-on-error step skip the if:-less guard? #766

Closed
timothy wants to merge 3 commits from probe756/coe-invariant into main
Owner

Scratch probe for ersatztv#756. DO NOT MERGE.

The #756 guard deliberately carries NO if:, relying on the default success(). That rests on one invariant: the guard is skipped only when an earlier step FAILED, and that already fails the job — so guard-skipped implies job-red, and every green path runs the guard.

There is one path where that could be false: a step with continue-on-error: true that FAILS. If this runner counts that as a failure for success() while still concluding the job successful, then the guard is SKIPPED on a GREEN job — and the whole change is a no-op on that path.

This makes the test job's last continue-on-error step (Report peak container memory) exit 1.

  • Invariant HOLDS → the guard still runs, finds all twelve markers, and Build & test (.NET) is GREEN.
  • Invariant BROKEN → the guard is skipped and the job is green with nothing checked. Then the guard needs an explicit condition instead.
**Scratch probe for ersatztv#756. DO NOT MERGE.** The #756 guard deliberately carries NO `if:`, relying on the default `success()`. That rests on one invariant: *the guard is skipped only when an earlier step FAILED, and that already fails the job* — so guard-skipped implies job-red, and every green path runs the guard. There is one path where that could be false: a step with `continue-on-error: true` that FAILS. If this runner counts that as a failure for `success()` while still concluding the job successful, then the guard is SKIPPED on a GREEN job — and the whole change is a no-op on that path. This makes the `test` job's last `continue-on-error` step (`Report peak container memory`) exit 1. - **Invariant HOLDS** → the guard still runs, finds all twelve markers, and `Build & test (.NET)` is GREEN. - **Invariant BROKEN** → the guard is skipped and the job is green with nothing checked. Then the guard needs an explicit condition instead.
timothy added 3 commits 2026-08-10 22:16:21 +02:00
A run: body the runner declines to interpolate is DROPPED and the job still
concludes success (#751). In review-verdict.yml that is fail-CLOSED; in
docker-build.yml's `test` and `migrations` — the other two required contexts on
main — it is fail-OPEN: the required check goes green having done no work.

Every consequential run: step now records that it began, and a trailing guard
fails the job when the expected set is incomplete. Per STEP, not per job as
proposed: a job-start marker only proves step 1 ran, and the dangerous drop is
`Test` or the migration replay.

Refs #756
Adds ci.required-job-step-execution-markers, updates
ci.workflow-run-body-no-expressions (whose rule: named #756 as the open
residual and whose scope paragraph was tracking REQUIRED contexts rather
than one file), and documents the guard in docs/ci-cd.md.

Decisions-Edit: yes
Refs #756
probe(756): DO NOT MERGE - does a failing continue-on-error step skip the if:-less guard?
PR Gates / CI image pin matches docker/ci (pull_request) Successful in 16s
PR Gates / Docs update reminder (pull_request) Successful in 18s
PR Gates / decisions lifecycle (pull_request) Failing after 17s
review-verdict/h10 Awaiting review verdict for 1d34a73
Review verdict / Set review-verdict status (pull_request_target) Successful in 8s
PR Gates / Script tests (pytest) (pull_request) Successful in 2m7s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 9m29s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 6m51s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Skipped
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (pull_request) Successful in 6m36s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 10s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 8s
1d34a73ff0
Author
Owner

Probe result — the invariant HOLDS

Job test, run 1913 / job 8075.

  • The deliberately-failing advisory step is in the log: PROBE: failing this continue-on-error step deliberately, and ❌ Failure - Main Report peak container memory — the only ❌ in the job.
  • The guard still ran: All 12 expected step(s) executed: detect revalidate restore npm-ci check-api lint typecheck web-test web-build strip-scanner build dotnet-test.
  • Job conclusion: success.

So a failing continue-on-error step does NOT flip success() on this runner. The if:-less guard is not a no-op on that path, and guard skipped ⇒ job red survives its most plausible counterexample.

Bonus: this is also the test job's full twelve-key positive control on the build lane, which #765 could not provide (its test job was the negative case). Between the two probes all three directions are now measured on the correct lane.

Note: this branch also carries a few docs/ edits that a dirty-tree git checkout -b swept onto it by accident. They belong to #756's own branch and have been re-applied there; nothing here is intended to merge.

Closing unmerged.

## Probe result — the invariant HOLDS Job `test`, run 1913 / job 8075. - The deliberately-failing advisory step is in the log: `PROBE: failing this continue-on-error step deliberately`, and `❌ Failure - Main Report peak container memory` — the only ❌ in the job. - **The guard still ran**: `All 12 expected step(s) executed: detect revalidate restore npm-ci check-api lint typecheck web-test web-build strip-scanner build dotnet-test`. - Job conclusion: **success**. So a failing `continue-on-error` step does NOT flip `success()` on this runner. The `if:`-less guard is not a no-op on that path, and *guard skipped ⇒ job red* survives its most plausible counterexample. Bonus: this is also the `test` job's full twelve-key **positive control** on the build lane, which #765 could not provide (its `test` job was the negative case). Between the two probes all three directions are now measured on the correct lane. Note: this branch also carries a few `docs/` edits that a dirty-tree `git checkout -b` swept onto it by accident. They belong to #756's own branch and have been re-applied there; nothing here is intended to merge. Closing unmerged.
timothy closed this pull request 2026-08-10 22:37:26 +02:00

Pull request closed

This pull request cannot be reopened because the branch was deleted.
Sign in to join this conversation.