feat: render page content once — serve bodies from cached .Content (render-once D8)#2042
Conversation
✅ Deploy Preview for gethinode-demo ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
Program register (live, with all gate evidence pointers and the wrap-up table): |
…icon call sites Bump mod-fontawesome to v6.1.1, whose icon partial accepts a 'page' argument and dual-writes symbol registrations to the page Scratch and Store (render-once D2). The Font-Awesome upstream snapshot rides along (webfonts change bytes). Thread the owning page through hinode's assets/icon.html call sites so sprite symbols land on the page that emits them, whichever context triggers the render: shortcodes pass .Page, partials their in-scope page. The button and card-icon argument structures gain an optional 'page' argument (Q6 posture: omitted pages fall back to the global page context) so their callers can thread it through. utilities/GetIllustration.html has no rendering page in scope and stays on the global fallback. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Override Hugo's embedded RSS template (v0.164.0) with a byte-compatible copy
that changes only the item description payload: the frontmatter description
when set, else a plainified (entity-decoded, XML-escaped) summary.
Embedding rendered HTML forced a per-output-format content render of every
feed-listed page in the feed page's ambient context, making feed bytes depend
on render order: three feeds differed between otherwise identical builds. With
plain-text descriptions the feeds are deterministic (run-vs-run byte-identical,
former allowlist included) and most RSS-triggered content variant renders
disappear; only feed-listed pages without a frontmatter description still
render content for their summary ('with' short-circuits the fallback).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Threads 'page' into the 9 hinode shortcode UniqueID call sites that omitted it (table.html already threads it). Anchors id counters to the owning page regardless of which rendering context materializes the content, so body ids stay page-local (1..n) under render-once. Folded into the flip slice: the one-time UID renumbering relative to the double-render baseline is this PR's expected diff (see the D8 evidence file). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Body layouts (body, docs/body, minimal/body, list) render .Content instead of re-rendering .RawContent through utilities/ProcessContent, removing one full shortcode/Goldmark pass per page; form/single.html keeps ProcessContent as it renders a fragment. The head stylesheet consumer materializes .Content explicitly and reads the module dependencies from the page Scratch and Store, mirroring footer/scripts.html. The exampleSite drops the deprecated purgeHTMLComments parameter in favour of Hugo's ignoreLogs, and the determinism script no longer tolerates any diff between two builds. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
mod-blocks v2.2.2 and mod-mermaid v5.0.2 register icons and UIDs on the owning page; required for sprite integrity under render-once bodies. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
0134ef5 to
f272b89
Compare
|
Runbook step 1 complete: rebased onto main after the #2041 merge — the stack is gone; this PR is now exactly the 5 D8 commits (D8a icon adoption, D8c plain-text RSS, D8b UniqueID threading, the flip, module bumps). Full gate re-verified on merged main: two builds FULLY byte-identical, |
|
🎉 This PR is included in version 3.3.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
Render-once program — THE FLIP (HELD; stacked — see merge order below)
Part of the Hinode render-once implementation program (design:
gethinode.com
docs/superpowers/specs/2026-07-15-content-render-once-design.md; full gateevidence and diff classifications in the program register + D8 evidence file).
merge those first and this diff reduces to the D8 commits alone:
2f554e0bD8a — mod-fontawesome v6.1.1 + owning page threaded through 52/53 hinode icon sites167e8daaD8c — plain-text RSS descriptions (.Descriptionshort-circuit, else plainifiedsummary) — kills the RSS
.Contentrace AND most per-output-format variant rendersdfcf0fa6D8b — owning page threaded through shortcode UniqueID calls6e6b36d5the flip —body/docs/body/minimal/body/listserve.Content(
form/singlekeeps the fragment path); head dependencies read gains a.Contentguard +Scratch∪Store union; exampleSite
purgeHTMLComments→ignoreLogs; RSS allowlist deletedfrom
scripts/check-build-determinism.sh0134ef59— mod-blocks v2.2.2 + mod-mermaid v5.0.2 (page-threaded releases)Results (exampleSite, hugo v0.164.0, M1 Pro)
allowlist is gone.
wall, medians of 3 warm-stable runs). Cumulative vs the 2026-07-15 pre-program baseline:
−41.8% CPU.
d--nonecount 0; no alt-text leakage.Expected diffs vs pre-flip base (exhaustively classified, nothing unclassified)
<p>wrappers; three privacy pages whitespace residue(RenderString-inline vs
.Contentsemantics — flagged and accepted 2026-07-16).Known residual — DO NOT MERGE until resolved
4 dangling sprite refs on 4 docs/blocks demo pages (cta/about
bi-chevron-right,contact-form
fa-paper-plane, featuredbi-download): mod-blocks components call hinodepartials (button/download/links) without a
pageargument, and the RELEASED hinode schemascannot accept one yet. Completion runbook:
pageinto the remaining indirect call sites(incl.
magazine.html:85) + finishembedthreading; release.scripts/check-build-determinism.sh+ the sprite audit(expected: 0 dangling, fully byte-identical); merge this PR; re-baseline.
Store plumbing (Q1 disproven), drop Scratch dual-writes in module majors, remove
blocks_embedfallback, remove the transitionalwarn-missing-page-argumentsuppression.🤖 Generated with Claude Code