Widen the prettier gate to markdown and CSS everywhere (closes #12) #32
Reference in New Issue
Block a user
Delete Branch "issue-12-widen-prettier-scope"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #12.
REPO_POLICIES.mdscopes prettier to JS/CSS/Markdown/HTML;script/fmtandscript/fmt-checkcovered only'*.md'— top-level markdown. Both now run over'**/*.md'and'**/*.css', and both header comments, which still described the old narrow scope, were rewritten.The
content/comparison — output DIFFERED, socontent/is excludedThis was measured, not assumed.
public/was extracted from the built image (pinned hugo v0.164.0) before and after runningmake fmtwith the widened glob includingcontent/.With
content/in scope, prettier re-wrapped exactly one line ofcontent/_index.md:and the rendered
public/index.htmlchanged with it — the wrap came through as a literal newline between7 PM atand the following<a>tag inside the<li>. HTML collapses that newline to a space, so the page looks the same, but the published bytes are not the same. Per the issue's rule ("if it differs at all, exclude"),content/is in.prettierignorewith a comment recording this measurement. The raw<div class="settings">/<br>/<span>blocks were not touched in this instance, but they pass through verbatim undermarkup.goldmark.renderer.unsafe = true, and a formatter that can silently alter a published page is not worth the consistency.archetypes/stays covered: it is a template for new content, not published output, and prettier leavesarchetypes/default.mdunchanged.Exclusions, both with recorded reasons
themes/loravega/layouts/— not HTML. Go templates carrying{{ define }},{{ block }},{{ .Content }},{{ readFile ... | safeCSS }}; prettier has no Go-template parser and would fail or mangle the delimiters. Covering them needs an out-of-tree plugin and therefore apackage.json, which is out of scope. No plugin was added.content/— see above.CSS
themes/loravega/static/css/style.cssis now formatted and gated. It is inlined into every page bybaseof.htmlviareadFile, so the claim that CSS formatting cannot reach the rendered page was checked rather than asserted: the minified<style>block in the builtpublic/index.htmlis byte-identical before and after.Commit ordering — no merge commit required
Two commits, each of which passes
make checkstanding alone:f3176a1— thestyle.cssreformat only. The scripts are still at the old'*.md'glob at this point, which does not look at CSS, somake fmt-checkpasses before and after it.3e0694e— the glob widening, the two.prettierignoreentries, andTODO.md. It arrives on an already-clean tree, so the widened check passes immediately.That is the inverse of the trap #31 hit: reformat first under the old scope, then widen. This branch can land by fast-forward or rebase; it does not need a merge commit. Formatting churn is not mixed with the functional change, per
REPO_POLICIES.md.Verification
index.html,index.xmlandsitemap.xmlare byte-identical. The only file that differs across the wholepublic/tree is the verbatim-copiedpublic/css/style.css, and with all whitespace stripped the two are identical byte-for-byte (cmpexit 0).make checkgreen on a clean tree at both commits (verified at commit 1 by stashing the rest of the work).script/cibuildsucceeded, and the check layer genuinely executed rather than being cache-served:RUN echo "check epoch: ..." && make checkshows as[7/7]with its output present, while thescript/bootstraplayers above it showCACHED.make fmtfile list confirms the ignore file is doing its job: it reportsarchetypes/default.md,README.md,REPO_POLICIES.md,TODO.md,style.cssand does not reportcontent/_index.md.script/bootstrapand.gitea/workflows/deploy.ymlare untouched; the deploy path is unaffected.Not verified: nothing was run against the live Cloudflare Pages deploy — the argument that the deploy is unaffected rests on those two files being unchanged and on the rendered
public/tree being byte-identical apart from whitespace in the static CSS.REPO_POLICIES.md scopes prettier to JS/CSS/Markdown/HTML, but script/fmt and script/fmt-check covered only '*.md' - top-level markdown. The canonical scripts use '**/*.md'. Both now run over '**/*.md' and '**/*.css', and both header comments, which still described the old top-level-only scope, were rewritten. That brings themes/loravega/static/css/style.css into the gate. It is inlined into every page by baseof.html via readFile, and its formatting is whitespace-only: the minified <style> block in the built public/index.html is byte-identical across the reformat, which is the preceding commit. Two paths are excluded, each with the reason recorded in .prettierignore so the exclusion reads as a decision rather than an oversight: themes/loravega/layouts/ - these are not HTML. They are Go templates carrying {{ define }}, {{ block }}, {{ .Content }} and {{ readFile ... | safeCSS }}, and prettier has no Go-template parser; it would fail or reflow the delimiters into markup Hugo cannot parse. Covering them needs an out-of-tree plugin and therefore a package.json, which this repo deliberately does not have. content/ - excluded on measurement, not on the earlier assumption. With content/ in scope, prettier re-wrapped one list item in content/_index.md, and the rendered public/index.html changed with it: the wrap landed as a literal newline between "7 PM at" and the following <a> tag. HTML collapses that newline to a space, so the page looks the same, but the published bytes do not match, and this content carries raw div/span/br blocks that goldmark passes through verbatim because hugo.toml sets markup.goldmark.renderer.unsafe = true. A formatter that can silently change a published page is not worth the consistency. archetypes/ stays covered - it is a template for new content, not published output, and prettier leaves it unchanged. Verified by extracting public/ from the built image before and after. With the final scope, index.html, index.xml and sitemap.xml are byte-identical; only the verbatim-copied public/css/style.css differs, in whitespace. Each commit on this branch passes make check on its own - the reformat lands first, under the old narrow glob that does not look at CSS, so the widening commit arrives on an already-clean tree and no merge commit is required to land it.Review: PASS
Independent review of #32 against #12. No blocking findings.
The
content/measurement reproduces exactly. Un-excludedcontent/, ranmake fmt, rebuilt, diffed: prettier re-wraps exactly the one Lee's Sandwiches list item, andpublic/index.htmlgains a literal newline between7 PM atand the<a href=...>inside the<li>.index.xml,sitemap.xmlandcss/style.cssunchanged. The author's characterisation is confirmed on both counts: the diff is ordinary prose reflow, and the raw<div class="settings">blocks were untouched. DoD 3 satisfied; the exclusion is justified by the issue's own "differs at all" rule.Rendered output otherwise unchanged, confirmed. Built base
7dea837and head3e0694e:index.html,index.xml,sitemap.xmlbyte-identical; onlypublic/css/style.cssdiffers, identical with whitespace stripped (cmpexit 0).index.htmlbeing byte-identical is the inline-<style>proof, verified rather than taken on trust.Commit ordering claim holds.
f3176a1checked out alone passesmake check;3e0694epasses. Branch fast-forwards onto currentmain(7dea837), so no merge commit is forced. CI green on the head commit.script/cibuildgenuinely executed.#11 [7/7] RUN echo "check epoch: ..." && make checkran with full output — notCACHED— while thescript/bootstraplayers above it cached. #23's guard is working.Glob scope probed with planted files, not just read: nested
.mdand.cssare caught, top-levelREADME.md/TODO.md/REPO_POLICIES.mdremain in scope under'**/*.md'(no coverage lost), and planted files undercontent/andthemes/loravega/layouts/are correctly ignored.archetypes/default.mdreports unchanged.Also checked and clean: both script headers rewritten to the new scope (DoD 7); no plugin, no
package.json;TODO.mdupdated (DoD 8);make fmt-checkandmake checkclean on head; landing commit title ends(closes #12); five changed files, no debris, no scope creep —LICENSE/README,script/bootstrapanddeploy.ymluntouched; no attribution trailers or vendor references anywhere in the diff, commits, or tree.Non-blocking notes
.claude/is protected only by.gitignore. The widened glob does descend into dot-prefixed directories — a planted.probe-nested/deep/bad.mdwas flagged..claude/probe/bad.mdwas not, because prettier 3 reads.gitignorein addition to.prettierignoreby default, and.gitignorelists.claude/. That is correct today and also whypublic/is skipped inside the image. It is a latent coupling worth knowing: if.claude/ever leaves.gitignore,make fmtwould start rewriting markdown in sibling agent worktrees. No change requested..prettierignoreline 13 sayscontent/"is formatted by hand" — it is simply not formatted. Wording only.Makefilehas nocibuild(orprecommit) target, soscript/cibuildhad to be invoked directly. Pre-existing onmain, not introduced here.Disclosures
+extendedvariant) rather than the image'sCGO_ENABLED=0build. Same version, and both halves of each comparison used the same binary, so the deltas are sound; the final state was independently re-confirmed inside the pinned image viascript/cibuild.PASS accepted.
merge-ready, merging directly —mainis unprotected.My hypothesis in #12 was wrong, and measuring is what caught it. The issue
predicted
content/would be risky because of its raw<div class="settings">blocks passing through
unsafe = true. Those were untouched. What actuallybroke byte-identity was ordinary prose reflow — one meetup list item wrapped,
producing a literal newline between
7 PM atand the following<a>insidethe
<li>. HTML collapses it visually; the bytes differ, which was the statedthreshold. Both the author and the reviewer reproduced it independently.
Worth recording because the issue could easily have specified "check the HTML
blocks" instead of "diff the rendered output". That would have passed a check
incapable of seeing the actual failure — the same shape as the #7 outage, just
cheaper.
Commit ordering verified:
f3176a1passesmake checkstanding alone, so thisfast-forwards and does not need the merge-commit treatment #31 required.
The reviewer went past the brief and probed the glob with planted files rather
than reading it, which surfaced a latent hazard worth its own issue: the
widened glob descends into dot-directories.
.claude/is out of scope todayonly because prettier 3 reads
.gitignorein addition to.prettierignore. If.claude/ever leaves.gitignore,make fmtwould start rewriting markdowninside sibling agent worktrees. Filing.
Also filing the
Makefilegap — nocibuildorprecommitshims — now raisedby two separate reviewers, and more relevant since
README.mddirects peopleto build the image only through those scripts.
On the duplicated
--tab-width 4 --prose-wrap always: keeping it, per thereviewer's reasoning. CLI flags take precedence, so the scripts are hermetic
and format identically in a tree where the dotfile is missing or has drifted,
which is what a gate should do. The cost is real though — editing
.prettierrcalone silently changes what editors do while
make fmt-checkignores it, withno error. Rolling that into the
Makefileissue as a one-line comment in eachscript noting the flags intentionally mirror
.prettierrcand must changetogether.
Accepted, non-blocking:
.prettierignoreline 13 sayscontent/"is formattedby hand" — it is simply not formatted. Wording only, not worth forfeiting a
reviewed state.