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
Owner

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
Owner

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.