script/lint exits 0 on render-target collisions, so the signal is printed but not enforced #25

Open
opened 2026-08-09 12:07:07 +02:00 by clawbot · 1 comment
Collaborator

Problem

#9 fixed script/check so that script/lint actually runs. But the signal it
recovers is printed and then ignored, because Hugo exits 0 on a duplicate
render-target warning.

Demonstrated during the review of PR #24, on a scratch copy of the site with
two pages rendering to the same permalink:

  • script/test (hugo --minify) — prints nothing, exit 0.
  • script/lint (hugo --minify --printPathWarnings) — prints
    WARN Duplicate target paths: /collide/index.html (2), and exits 0.
  • script/check with the collision present — exit 0.

So a real render-target collision does not fail make check, does not fail the
pre-commit hook, and does not fail CI. It scrolls past in the build log.

This is worth stating plainly: #9's rationale was mildly overstated, and I
wrote it.
I described script/lint as "a real check" whose signal was "being
discarded". The accurate version is that the signal moves from discarded to
printed-and-ignored. That is a genuine improvement — you cannot act on output
that never runs — but it is not yet a gate, and #9's issue text implied it was.
Correcting the record here rather than leaving the overstatement standing.

Why this matters for a Hugo site

A duplicate render target means two pieces of content silently overwrite each
other in public/. One of them does not get published, and nothing fails. On a
site whose entire purpose is publishing a small number of pages, losing one
silently is exactly the failure you want a gate to catch. It has not bitten
this repo yet only because the site is currently a single page.

There is also a build-noise interaction: the site already emits an unrelated
taxonomy WARN (#13). Two classes of ignorable warning train everyone to
ignore the third.

Options

Option A — --panicOnWarning on script/lint (recommended, but see the
caveat).
Hugo's documented mechanism for making warnings fatal. One flag,
correct semantics, no bespoke parsing. Caveat: it makes ALL warnings fatal,
not just collisions.
That means #13 (the taxonomy layout warning) and #18
(the languageCode deprecation) must be fixed first, or the gate goes red
immediately. It also means a future Hugo release that adds a new warning
category can break the build — arguably correct behaviour, but it should be a
conscious choice.

Option B — grep the lint output for the specific warning and fail on it.
Narrower: fails only on duplicate target paths, leaves other warnings advisory.
Costs a bespoke shell pipeline in script/lint that has to keep matching
Hugo's message text — brittle across Hugo upgrades in a way Option A is not.

Option C — leave it advisory and rely on humans reading build output. Not
recommended; that is the status quo and the reason this issue exists.

My recommendation: Option A, sequenced after #13 and #18. It is the
supported mechanism and it makes the whole warning class meaningful rather than
carving out one message. The dependency on #13 and #18 is a feature — it forces
the existing warning backlog to zero before warnings become enforcing, which is
the only order in which "warnings are fatal" is a livable policy.

Definition of done

  1. A render-target collision causes make check to exit non-zero.
  2. Demonstrated the way it was found: construct a collision on a scratch copy
    (do not commit colliding content), show make check failing, remove it,
    show make check passing. Paste both.
  3. If Option A: #13 and #18 are closed first, and make check is confirmed
    green on the real site with the flag active before the flag is merged.
  4. script/lint's header comment describes the new behaviour accurately —
    it currently claims it "is a real check", which this issue shows is only
    half true today.
  5. script/cibuild succeeds, with the check layer confirmed genuinely executed
    and not CACHED (see #23).
  6. TODO.md updated in the same commit.

Depends on

  • #13 (taxonomy warning) and #18 (languageCode deprecation) if Option A is
    chosen. Both must be closed first or the gate fails on day one.
  • Interacts with #23: verifying this needs a genuinely-executed check layer.

Out of scope

  • Fixing #13 or #18 themselves.
  • Making script/test strict. script/test is the plain production build and
    should stay the fast path; enforcement belongs in script/lint.
## Problem #9 fixed `script/check` so that `script/lint` actually runs. But the signal it recovers is **printed and then ignored**, because Hugo exits 0 on a duplicate render-target warning. Demonstrated during the review of PR #24, on a scratch copy of the site with two pages rendering to the same permalink: - `script/test` (`hugo --minify`) — prints nothing, exit 0. - `script/lint` (`hugo --minify --printPathWarnings`) — prints `WARN Duplicate target paths: /collide/index.html (2)`, and **exits 0**. - `script/check` with the collision present — **exit 0**. So a real render-target collision does not fail `make check`, does not fail the pre-commit hook, and does not fail CI. It scrolls past in the build log. This is worth stating plainly: **#9's rationale was mildly overstated, and I wrote it.** I described `script/lint` as "a real check" whose signal was "being discarded". The accurate version is that the signal moves from *discarded* to *printed-and-ignored*. That is a genuine improvement — you cannot act on output that never runs — but it is not yet a gate, and #9's issue text implied it was. Correcting the record here rather than leaving the overstatement standing. ## Why this matters for a Hugo site A duplicate render target means two pieces of content silently overwrite each other in `public/`. One of them does not get published, and nothing fails. On a site whose entire purpose is publishing a small number of pages, losing one silently is exactly the failure you want a gate to catch. It has not bitten this repo yet only because the site is currently a single page. There is also a build-noise interaction: the site already emits an unrelated taxonomy `WARN` (#13). Two classes of ignorable warning train everyone to ignore the third. ## Options **Option A — `--panicOnWarning` on `script/lint` (recommended, but see the caveat).** Hugo's documented mechanism for making warnings fatal. One flag, correct semantics, no bespoke parsing. **Caveat: it makes ALL warnings fatal, not just collisions.** That means #13 (the taxonomy layout warning) and #18 (the `languageCode` deprecation) must be fixed first, or the gate goes red immediately. It also means a future Hugo release that adds a new warning category can break the build — arguably correct behaviour, but it should be a conscious choice. **Option B — grep the lint output for the specific warning and fail on it.** Narrower: fails only on duplicate target paths, leaves other warnings advisory. Costs a bespoke shell pipeline in `script/lint` that has to keep matching Hugo's message text — brittle across Hugo upgrades in a way Option A is not. **Option C — leave it advisory and rely on humans reading build output.** Not recommended; that is the status quo and the reason this issue exists. **My recommendation: Option A, sequenced after #13 and #18.** It is the supported mechanism and it makes the whole warning class meaningful rather than carving out one message. The dependency on #13 and #18 is a feature — it forces the existing warning backlog to zero before warnings become enforcing, which is the only order in which "warnings are fatal" is a livable policy. ## Definition of done 1. A render-target collision causes `make check` to exit non-zero. 2. Demonstrated the way it was found: construct a collision on a scratch copy (do **not** commit colliding content), show `make check` failing, remove it, show `make check` passing. Paste both. 3. If Option A: `#13` and `#18` are closed first, and `make check` is confirmed green on the real site with the flag active before the flag is merged. 4. `script/lint`'s header comment describes the new behaviour accurately — it currently claims it "is a real check", which this issue shows is only half true today. 5. `script/cibuild` succeeds, with the check layer confirmed genuinely executed and not `CACHED` (see #23). 6. `TODO.md` updated in the same commit. ## Depends on - #13 (taxonomy warning) and #18 (`languageCode` deprecation) if Option A is chosen. Both must be closed first or the gate fails on day one. - Interacts with #23: verifying this needs a genuinely-executed check layer. ## Out of scope - Fixing #13 or #18 themselves. - Making `script/test` strict. `script/test` is the plain production build and should stay the fast path; enforcement belongs in `script/lint`.
sneak was assigned by clawbot 2026-08-09 17:34:31 +02:00
Author
Collaborator

Both prerequisites are now clear, so this is unblocked and needs your call.

  • #18 (languageCode deprecation) — closed, merged in PR #27.
  • #13 (taxonomy warning) — fixed in PR #29, under review. Build output is
    warning-free.

So the noise floor is genuinely zero and Option A would no longer fail the
build on day one. My recommendation is unchanged: Option A,
--panicOnWarning on script/lint.

Assigning to you because the caveat in the issue body is the whole decision and
it is not mine to make: --panicOnWarning makes every Hugo warning fatal,
not just render-target collisions.
The upside is that a silent
page-overwriting collision can never ship. The cost is that a future Hugo
release which introduces a new warning category will break the build until
someone fixes it — including on main, and including the deploy path. That is
arguably correct behaviour, but it is a standing commitment to keeping the
warning backlog at zero forever, and this repo has just spent real effort
getting it there.

Option B (grep for the specific warning) avoids that commitment at the cost of
a brittle text match. Option C is the status quo.

Not blocking on this — moving to #23 next. Answer whenever; the work is a small
change to script/lint once you pick.

Both prerequisites are now clear, so this is unblocked and needs your call. - #18 (`languageCode` deprecation) — closed, merged in PR #27. - #13 (taxonomy warning) — fixed in PR #29, under review. Build output is warning-free. So the noise floor is genuinely zero and Option A would no longer fail the build on day one. My recommendation is unchanged: **Option A**, `--panicOnWarning` on `script/lint`. Assigning to you because the caveat in the issue body is the whole decision and it is not mine to make: **`--panicOnWarning` makes every Hugo warning fatal, not just render-target collisions.** The upside is that a silent page-overwriting collision can never ship. The cost is that a future Hugo release which introduces a new warning category will break the build until someone fixes it — including on `main`, and including the deploy path. That is arguably correct behaviour, but it is a standing commitment to keeping the warning backlog at zero forever, and this repo has just spent real effort getting it there. Option B (grep for the specific warning) avoids that commitment at the cost of a brittle text match. Option C is the status quo. Not blocking on this — moving to #23 next. Answer whenever; the work is a small change to `script/lint` once you pick.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/lora.vegas#25