An audit found the guard could miss commits it exists to catch.
1. SIGPIPE. Three inner checks used `printf ... | grep -q` under
`set -euo pipefail`. When grep -q matches early it exits, printf dies of
SIGPIPE, pipefail turns the pipeline non-zero, the `if` goes false, and the
offending commit is silently not reported — the guard then prints its
success line. This file already documents the hazard in a comment and had
fixed it for the two outer pre-filters; the three inner ones were left as
pipes. Now here-strings, like the rest.
Demonstrated on a synthetic revert-style commit (an AI trailer quoted near
the top, then a 200KB body): the pipe form MISSES it, the here-string form
detects it. A trailer in the conventional last position happens to survive
the pipe form, because grep must read to the end before matching — which is
why this never showed up in practice.
2. `chatgpt` was in BAD_NAME and BAD_ANY but not BAD_TRAILER, so a
Co-authored-by naming ChatGPT with an email outside anthropic.com/openai.com
was not caught. Confirmed by test, then added.
Verified before pushing this time: the amended script flags an AI-authored
commit, a large-body early trailer, and a ChatGPT trailer, and scans
claude_guide's full 345-commit history with zero false positives — that repo
has 46 commits with Claude or Anthropic in the subject, none of which are
identity or trailer hits.
A wedged Chrome/mdPress step held a harness runner for 27 minutes yesterday
(normal run: ~4 min) and ignored `gh run cancel`; it only stopped because that
job happened to carry timeout-minutes: 30. An audit found 66 of the 101 jobs
across the cluster had no timeout at all — the same hang there would have held
a runner for GitHub's 6-hour default.
Values come from measured run history, not guesses. Across ~120 successful
runs the slowest workflow tops out at 10 min (Update Preview Publications),
CI at 6.5, Update Preview PDF at 4.8:
30 min — jobs that run Chrome/mdPress/pandoc (3x the observed max, and the
value harness already used)
15 min — release, publish, deploy, check-link, chaincode-tests
10 min — dependabot auto-merge
Every value has at least 6x headroom over its job's observed maximum, so this
should never turn a slow-but-working run into a failure.
Verified: all 72 workflow files still parse, and all 101 jobs now carry an
integer timeout in range.
The guard added earlier could never trigger. tools/render_mermaid.py has no
nonzero exit path — its own docstring said "Exits 0 even if some/all fail
(non-fatal)" — so `if ! render_mermaid.py ...; then exit 1; fi` never ran its
body, and a build that rendered zero diagrams still passed. Reproduced by
running the script with no Chrome on PATH: it printed the fallback warning and
exited 0.
Adds a --strict flag that exits 1 when Chrome is missing or any diagram fails
to render, and passes it from every workflow invocation. The default stays
lenient so local mobile-reader builds keep working, which is what the exit-0
behaviour was actually for.
Verified both directions: with no Chrome, --strict exits 1 and the default
exits 0; against the real book with Chrome, --strict renders every diagram and
exits 0.
Follows the devDependency removal. The build has been mdPress-only since
1.7.0 and nothing referenced these:
- .vuepress/ (config.js + .gitignore). The mirror it configured is still
live, but no workflow in this repo builds or deploys it, so this was a
recipe nobody ran. Local .vuepress/dist/ (400 files of Feb-2026 build
output, never tracked) was removed from the working tree too — with its
.gitignore gone it would otherwise have shown up as untracked noise.
- docker-compose.yml: the vuepress-offline service, plus the now-unused
&mdpress-offline anchor that existed only to feed it.
- README: the 'docker run ... :vuepress' one-liner. That tag was last
pushed 2022-06-25, so readers following it got a four-year-old snapshot
of the book. 'mdpress serve' immediately above it still works.
- CODEOWNERS, .zhlintignore and check_project_rules.py entries for the
deleted directory, and the check-link allowlist entry for the mirror
(no content links to it).
The CHANGELOG entry recording the original CI removal is left alone — it
is history.
Verified: npm test passes (3 + 35), check_project_rules passes 202 files,
docker-compose.yml still parses with no dangling YAML aliases.
Renders Mermaid to SVG via the workflow's Chrome, pandoc --mathml, assembles a
single self-contained responsive HTML reader, and attaches <repo>-<tag>.html to
the GitHub Release next to the PDF. Non-blocking (continue-on-error).