From 81b7b6f3089b1ad613ff62d42739d78ca08ad710 Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Wed, 2 Sep 2026 15:53:40 -0400 Subject: [PATCH] =?UTF-8?q?ci:=20smoke-web=20never=20ran=20=E2=80=94=20a?= =?UTF-8?q?=20job's=20`if:`=20cannot=20read=20the=20env=20context?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Run 5290 dispatched a refresh. Everything worked: the guard fired, the build published the candidate, the promote pointed :latest at it. And `smoke-web` reported conclusion "skipped", with no steps and no log. Its condition was `if: env.IS_REFRESH == 'true'`. The env context is available to STEP conditions and step bodies but never to a job's own `if:`, and an unresolvable context there evaluates to empty rather than erroring. So the gate skipped itself, silently, on the one run that existed to exercise it. Second silent-skip of this family today, after #3414. Same shape both times: something evaluated false, nothing failed, and the run reported success. It is worth naming the pattern — on this pipeline, "green" and "ran" are different claims, and the steps' own conclusions are the only place the difference shows. Fixed by keying off a job output rather than re-deriving the trigger: build-web now exposes the reuse step's `promote` decision as `outputs.candidate` and smoke-web consumes it. That is better than duplicating the expression: it is the same single decision the build, the XPI download and the promote all take already — build.yml's own "one decision drives everything downstream" — and it asserts the thing smoke-web actually depends on, that a candidate was published, rather than restating the reason one would be. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01TTjbZZ6JirCMSaJzQV1RhA --- .forgejo/workflows/build.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.forgejo/workflows/build.yml b/.forgejo/workflows/build.yml index a1c115f..5d3398a 100644 --- a/.forgejo/workflows/build.yml +++ b/.forgejo/workflows/build.yml @@ -452,6 +452,18 @@ jobs: # to. Same source of truth; no double-store. build-web: + # Consumed by smoke-web's job-level `if:`. It cannot read `env` — the env + # context is available to STEP `if:` and step bodies, never to a job's own + # condition, and an unresolvable context there is empty rather than an + # error. `smoke-web` skipped silently on run 5290 for exactly that reason. + # + # Keying off the reuse step's own output is better than re-deriving the + # trigger anyway: it is the same single decision the build, the XPI + # download and the promote all take (build.yml's "one decision drives + # everything downstream"), and it says the thing smoke-web actually needs + # to know — a candidate was published — rather than restating why. + outputs: + candidate: ${{ steps.reuse.outputs.promote }} # A plain `needs` — no `always()`. That expression existed to let a # SKIPPED sign-extension through on a tag push while still blocking a # FAILED one. With no tag trigger, sign-extension always runs, so the @@ -1123,8 +1135,8 @@ jobs: # time anyone saw this job run would also be the first time it could stop a # publish. smoke-web: - if: env.IS_REFRESH == 'true' needs: [build-web] + if: needs.build-web.outputs.candidate == 'true' runs-on: python-ci container: image: git.fabledsword.com/bvandeusen/ci-python:3.14