Today — action/action.yml:365 is the only message the holed gate can emit, and it interpolates the text: input:
$ grep -n 'can no longer be drawn cleanly this year' action/action.yml
365: echo "::error::${INPUT_TEXT} can no longer be drawn cleanly this year"
Running the step verbatim (the extraction diffs against action.yml:255-381 with only a trailing blank line between them) against the 0.6.3 tracker:
$ runact.sh f_text INPUT_TEXT=VYNCINT INPUT_YEAR=2026 INPUT_START_WEEK=6 INPUT_FAIL_ON=holed
::error::VYNCINT can no longer be drawn cleanly this year
--- exit 1 ---
$ runact.sh f_tpl INPUT_TEMPLATE=dragon INPUT_YEAR=2026 INPUT_FAIL_ON=holed
::error:: can no longer be drawn cleanly this year
--- exit 1 ---
$ runact.sh f_mtx INPUT_MATRIX=heart.art INPUT_YEAR=2026 INPUT_START_WEEK=35 INPUT_FAIL_ON=holed
::error:: can no longer be drawn cleanly this year
--- exit 1 ---
INPUT_TEXT is empty by construction for the other three sources — the step refuses more than one. The report the same step parsed two lines earlier already holds the name:
$ for n in f_text f_tpl f_mtx; do jq -r '.text + " | " + .headline' run-$n/temp/mossaic/report.json; done
VYNCINT | VYNCINT · 2026 — 1 of 75 bright, 25 holes that cannot be unlit
Dragon | Dragon · 2026 — 2 of 146 bright, 31 holes that cannot be unlit
heart | heart · 2026 — 0 of 56 bright, 1 hole that cannot be unlit
Why it is worth fixing — fail-on: holed exists so an unattended daily cron can shout once, on the day the year stops being drawable, and that shout is the entire product of the run: it is what lands in the Actions log, the run summary and the failure notification. For a picture — the case where holed is most likely, since a picture uses the whole week and every dark day inside it is a hole waiting to happen — the shout arrives as a sentence with a hole where the noun should be, in a red annotation on a scheduled run somebody may be watching across several repositories. Pictures are first-class here: action/README.md:83 documents "Tracking a picture (uses: template: dragon)". Every other error in the script names its subject ("no such file: %s", "unknown fail-on value '%s'"). Closed #9 fixed the same shape of bug in the neighbouring fail-on: behind gate, which makes this the untouched half rather than a duplicate.
Fix — use the report instead of the input. The step already has ${report_dir}/report.json open and already shells out to jq for verdict, today_short and today_kind; add one more:
subject="$(jq -r .text "${report_dir}/report.json")"
…
echo "::error::${subject} can no longer be drawn cleanly this year"
.text is VYNCINT for text, Dragon for a template and heart for a matrix — verified on all three. .headline would work too and would carry the hole count with it.
Done when — fail-on: holed names the picture for template:, matrix: and image: as well as the text for text:.
The coverage half, as a follow-on rather than part of a first patch: nothing in this repository executes action/action.yml — ci.yml:157's zizmor lint is a static reader and the only one — so its ~300 lines of bash have never run here, which is why a one-line interpolation bug can sit in the file's only failure path. A job that runs the composite action against the checked-in art/vyncint-2026.json for text: and one picture source, including a case that trips fail-on, would have caught this and needs no token and no network.
Today — action/action.yml:365 is the only message the
holedgate can emit, and it interpolates thetext:input:Running the step verbatim (the extraction diffs against action.yml:255-381 with only a trailing blank line between them) against the 0.6.3 tracker:
INPUT_TEXTis empty by construction for the other three sources — the step refuses more than one. The report the same step parsed two lines earlier already holds the name:Why it is worth fixing —
fail-on: holedexists so an unattended daily cron can shout once, on the day the year stops being drawable, and that shout is the entire product of the run: it is what lands in the Actions log, the run summary and the failure notification. For a picture — the case whereholedis most likely, since a picture uses the whole week and every dark day inside it is a hole waiting to happen — the shout arrives as a sentence with a hole where the noun should be, in a red annotation on a scheduled run somebody may be watching across several repositories. Pictures are first-class here: action/README.md:83 documents "Tracking a picture (uses:template: dragon)". Every other error in the script names its subject ("no such file: %s", "unknown fail-on value '%s'"). Closed #9 fixed the same shape of bug in the neighbouringfail-on: behindgate, which makes this the untouched half rather than a duplicate.Fix — use the report instead of the input. The step already has
${report_dir}/report.jsonopen and already shells out to jq forverdict,today_shortandtoday_kind; add one more:.textisVYNCINTfor text,Dragonfor a template andheartfor a matrix — verified on all three..headlinewould work too and would carry the hole count with it.Done when —
fail-on: holednames the picture fortemplate:,matrix:andimage:as well as the text fortext:.The coverage half, as a follow-on rather than part of a first patch: nothing in this repository executes action/action.yml — ci.yml:157's zizmor lint is a static reader and the only one — so its ~300 lines of bash have never run here, which is why a one-line interpolation bug can sit in the file's only failure path. A job that runs the composite action against the checked-in
art/vyncint-2026.jsonfortext:and one picture source, including a case that tripsfail-on, would have caught this and needs no token and no network.