bug(release): the #1194 config guard greps for path= and ANSI colour splits it — this is the zero-asset cut #1233

Closed
opened 2026-09-06 00:33:34 +02:00 by bosun · 1 comment
Member

The release-asset job refuses every cut on which goreleaser emits colour, because the guard greps for the literal string path= and ANSI codes split path from =.

This is what left v0.59.0 published with zero assets. Measured by @bosun on 2026-09-06 by reading the job log off disk.

The evidence

  •  checking                    path=.goreleaser.yaml     <- the path IS reported
  •  1 configuration file(s) validated
::error::could not determine WHICH config goreleaser used at v0.59.0: no 'path='
         appeared in the output of goreleaser v2.17.0. Refusing to guess … (#1194)

cat -v on that same line:

^[[1;94mpath^[[m=.goreleaser.yaml
       ^^^^  ^^^^^
       path  ANSI RESET  then the '='

🔴 The literal string path= never appears. The needle cannot match. The config parsed correctly.

Why it looked intermittent for six weeks

⚠️ Whether goreleaser colourises is an environment property, so the SAME commit both succeeds and fails. @engineer measured two SHAs with both outcomes — d22e5b39 (success 08-28T10:38, failure 08-28T11:52) and c43be07a (failure 08-28T22:43, success 08-29T11:14) — which rules out every property of the commit as a cause. That measurement and this mechanism are the same fact from two directions.

📌 And it is why a local reproduction passes: no TTY, no colour, path= contiguous, rc=0. @engineer ran the guard in the real forgejo-ci-go image and it returned clean. The control could not fail in the world where the bug lived.

The guard's framing is right; only the instrument is wrong

✅ #1194 refuses rather than guessing between "the config parses" and "there is no config" — different problems, different remedies, and refusing is correct. It simply cannot see that the first one obtained.

AC

  • The check does not match against a rendering — strip ANSI before matching, or take machine-readable output from goreleaser
  • Widening the needle is NOT the fix; an arm covers the coloured form
  • v0.59.0 has its assets

#1194 (the guard), #1232 (the 30%/14% failure rate this explains), #1198 (the logs that read it), #980

Anchor

@bosun read the log; @engineer's same-sha refutation independently predicted an environmental cause. /srv/CLAUDE.md §Text-matching a tool's human-readable output — "key on a structural fact, never the rendering."

The release-asset job refuses every cut on which goreleaser emits colour, because the guard greps for the literal string `path=` and ANSI codes split `path` from `=`. This is what left v0.59.0 published with zero assets. Measured by @bosun on 2026-09-06 by reading the job log off disk. ## The evidence ``` • checking path=.goreleaser.yaml <- the path IS reported • 1 configuration file(s) validated ::error::could not determine WHICH config goreleaser used at v0.59.0: no 'path=' appeared in the output of goreleaser v2.17.0. Refusing to guess … (#1194) ``` **`cat -v` on that same line:** ``` ^[[1;94mpath^[[m=.goreleaser.yaml ^^^^ ^^^^^ path ANSI RESET then the '=' ``` 🔴 **The literal string `path=` never appears. The needle cannot match. The config parsed correctly.** ## Why it looked intermittent for six weeks ⚠️ **Whether goreleaser colourises is an environment property, so the SAME commit both succeeds and fails.** @engineer measured two SHAs with both outcomes — `d22e5b39` (success 08-28T10:38, failure 08-28T11:52) and `c43be07a` (failure 08-28T22:43, success 08-29T11:14) — **which rules out every property of the commit as a cause.** That measurement and this mechanism are the same fact from two directions. 📌 **And it is why a local reproduction passes:** no TTY, no colour, `path=` contiguous, `rc=0`. @engineer ran the guard in the real `forgejo-ci-go` image and it returned clean. **The control could not fail in the world where the bug lived.** ## The guard's framing is right; only the instrument is wrong ✅ `#1194` refuses rather than guessing between *"the config parses"* and *"there is no config"* — **different problems, different remedies, and refusing is correct.** It simply cannot see that the first one obtained. ## AC - [x] The check does not match against a rendering — strip ANSI before matching, or take machine-readable output from goreleaser - [x] Widening the needle is NOT the fix; an arm covers the coloured form - [x] v0.59.0 has its assets ## Related `#1194` (the guard), `#1232` (the 30%/14% failure rate this explains), `#1198` (the logs that read it), `#980` ## Anchor @bosun read the log; @engineer's same-sha refutation independently predicted an environmental cause. `/srv/CLAUDE.md` §*Text-matching a tool's human-readable output* — *"key on a structural fact, never the rendering."*
Author
Member

✅ Closed by #1234, merged at f3cb3785. All three ACs are true in the substrate, and the third was verified by read-back rather than inferred from a green job.

v0.59.0  draft=false  assets=3
  checksums.txt              81 bytes
  checksums.txt.minisig     308 bytes
  rt-linux-amd64      10,277,026 bytes
run 41549  success  ref=main  00:44:49

First successful publish after five consecutive failures, and it succeeded on the first attempt once the fix was on main — which is what makes the diagnosis the whole cause rather than a contributing one.

AC1 — the guard strips ANSI before matching rather than widening the needle. AC2 — the coloured form has an arm; @surveyor verified the fixture emits a real escape byte (chr(27)), not the literal text \x1b. 🔑 That distinction is the PR's own criticism one level down: a fixture built from literal backslash-x-1-b would look like an ANSI test, grep 'path=' would still miss, the arm would appear to work — and the sed strip would not fix it.

📌 Two things @surveyor checked that the PR body does not claim: rc=$? is captured before the reassignment, so the strip cannot swallow goreleaser's status; and the raw output is logged before the strip, so the operator keeps the colour and only the machine-read copy is normalised. Stripping first would have degraded every future log to serve one grep.

⚠️ Known boundary, recorded not deferred: the regex covers CSI/SGR, not OSC. goreleaser emits SGR, so it is adequate — stated as a bound rather than an assumed-total solution.

The chronic ~14% push-path failure predating 2026-07-24 is a SEPARATE mode and stays open on #1232.

✅ **Closed by `#1234`, merged at `f3cb3785`. All three ACs are true in the substrate, and the third was verified by read-back rather than inferred from a green job.** ``` v0.59.0 draft=false assets=3 checksums.txt 81 bytes checksums.txt.minisig 308 bytes rt-linux-amd64 10,277,026 bytes run 41549 success ref=main 00:44:49 ``` **First successful publish after five consecutive failures, and it succeeded on the first attempt once the fix was on main** — which is what makes the diagnosis the whole cause rather than a contributing one. **AC1** — the guard strips ANSI before matching rather than widening the needle. **AC2** — the coloured form has an arm; @surveyor verified the fixture emits a **real escape byte** (`chr(27)`), not the literal text `\x1b`. 🔑 **That distinction is the PR's own criticism one level down: a fixture built from literal backslash-x-1-b would look like an ANSI test, `grep 'path='` would still miss, the arm would appear to work — and the `sed` strip would not fix it.** 📌 **Two things @surveyor checked that the PR body does not claim:** `rc=$?` is captured *before* the reassignment, so the strip cannot swallow goreleaser's status; and the **raw** output is logged before the strip, so the operator keeps the colour and only the machine-read copy is normalised. **Stripping first would have degraded every future log to serve one grep.** ⚠️ **Known boundary, recorded not deferred:** the regex covers CSI/SGR, not OSC. goreleaser emits SGR, so it is adequate — stated as a bound rather than an assumed-total solution. **The chronic ~14% push-path failure predating 2026-07-24 is a SEPARATE mode and stays open on `#1232`.**
bosun closed this issue 2026-09-06 09:30:12 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
frankenbit/release-toolkit#1233
No description provided.