lichen.page.review from the reviewed point 0b92cb61 to stack eb5a1653, as one PR per subsystem (review set)

full 11: SSGs, rebuilds and the preview build #74

targeting full/10-scripts from full/11-ssg
Open opened by and assigned to notplants-bot.bsky.social
targeting full/10-scripts from full/11-ssg

A site's builds: the rebuild lane and the static site generators (lichen-ssg, Hugo, mdBook, and the new script generator). Since 09-23 the lane has become the site's one build path with three targets (the published site, a preview with drafts that publishes nothing, and a check), lichen-ssg runs shortcodes and build hooks, and a site may be built by its own script. The code also moved from the lichen-cms crate to lichen-site with the rename.


AST-verified changes

  • The crate rename lichen-cms → lichen-site (PER-SITE-PROCESS P2c-1, d7c4a668) carried every file here. Checked (run id not recorded): "Rename move check with rn6 at f3e7470b..d7c4a668: ok (4365 items, 113 renamed, 1874 carried, 0 visibility)"; adversary rerun (A11324): "d7c4a668 equal=true 0-err 113-renamed 1874-carried 0-vis". Allowed: lichen_cms → lichen_site rewrites, Cargo.toml and static files as other files, rustfmt rewraps; string literals changed in a separate commit (8eef92b4). rebuild.rs changed so much after that git shows it as a deletion under crates/lichen-cms/ and an addition under crates/lichen-site/, both here; ssg/mdbook.rs reads as a rename again since FULL-SITE-PROCESS moved its process-group code out.
  • ssg/mod.rs renamed to ssg.rs (OPERATOR-REVIEW-FIXES U1, N8, f6a10c32). Checked over 8b30050a..f6a10c32 (run id not recorded): "3004 items, 48 moved, 69 carried, 19 renamed, 2 visibility as mapped, 233 module declarations"; adversary rerun notify-abab368a, the same counts.
  • The publication renames of OPERATOR-REVIEW-REVISIONS R7 (d52675cd), in rebuild.rs, ssg/lichen.rs, ssg/script.rs and ssg/ssg_trait.rs: Target::Published → Dist, Made::Published → DistInstalled, publish_staged → install_dist, BuildKind::Publish → Site, and others. Checked by substituting the names back: run notify-392a0b96, "names substituted back AST EQUAL, control RED"; adversary (A11506): "rename AST-equal (control RED)".

Roughly 600 of this PR's 2,890 changed lines are code these moves carried verbatim, nearly all of it the old rebuild.rs reappearing under lichen-site; the rest is the lane's targets, the script generator and the shortcodes in lichen-ssg.

On this forge the 7 renamed files here show as a whole deletion and a whole addition, so its diff reads 6,048 changed lines; with rename detection (git diff -M full/10-scripts full/11-ssg) it is 2,890.


What changed

  • The lane (rebuild.rs): a request names a target: the published site, the preview (drafts, future-dated and expired pages, its base URL the preview route) or a check that publishes nothing. Requests for one target coalesce, a build whose revision moved while it ran is redone, and only the published target publishes and records failures. "Changed" is the tree's revision (lichen-flat-file's change counter), so writes to the site's metadata, which do not advance it, never trigger a build. After a publication whose scripts ran, a PublishedHook commits what they wrote without advancing the revision (operator note N1). Over the owner's storage limit no build runs (SHB-STORAGE1).
  • The preview (preview.rs, 9b's design record): the whole site as an editor sees it, built into a private folder the lane holds; its routes are in #35.
  • lichen-ssg (ssg/lichen.rs): runs shortcodes and the build's before and after hooks; a failing shortcode leaves its place empty in a publish and is reported, and with strict_scripts a failing shortcode or hook refuses the publish. A page that is live and fails refuses a site build; one that was never live is left out and reported.
  • The script generator (ssg/script.rs, SSG-BUILD-OVERRIDE B2): a site whose ssg = "script" is built by its own build/ssg.<lua|js|py>, called only where it has something to say.
  • Hugo and mdBook (ssg/hugo.rs, ssg/mdbook.rs): Hugo's previews build drafts with the preview's base URL, and Hugo gets the site child's prepared environment (CHILD-ENV-CLEAR); mdBook runs in an mdBook child of its own (FULL-SITE-PROCESS unit 1c, scripts::engine::build_book), confined to what the build may touch: its book's commands are that child's children, in its process group, and past the time bound it is killed with them.
  • The generator trait (ssg/ssg_trait.rs): SSGKind::Script, a BuildKind (site or preview), and a staged build that carries its check report and whether scripts ran.
  • The default layout (templates.rs): the no-JavaScript editor's Tera templates are gone (REPLACE-TERA R1b), so lichen-ssg renders with the site's templates and its own default layout.html, now include_str!'d from ssg/templates/layout.html (operator note N7) instead of an embedded templates folder.

Files (crates/lichen-site/src/)

  • rebuild.rs — the lane. Read this first. Its 09-23 copy, crates/lichen-cms/src/rebuild.rs (−485), is deleted here.
  • ssg/ssg_trait.rs — the generator trait and the staged build.
  • ssg/lichen.rs — lichen-ssg.
  • ssg/script.rs — new: the script generator.
  • ssg/mdbook.rs — mdBook, renamed from crates/lichen-cms/src/ssg/mdbook.rs; the build itself is the engine child's (#26).
  • ssg/hugo.rs, ssg/overlay.rs (create_content_overlay_in) — Hugo and the shared preview overlay.
  • preview.rs — the preview's build and its base URL.
  • templates.rs — the default layout.
  • ssg.rs — the module list.

Moved in: the lichen-cms rebuild.rs deletion above, with the file it became (git pairs them only below its default similarity); preview.rs (the starting map put it in site core; it is the lane's preview target).

Lives elsewhere

  • Shortcodes, the script runners, the engine child mdBook runs in, and the no-JavaScript render: #26.
  • A publish's build and what is deployed: #24, #25.
  • The preview's and check's routes (api/preview.rs, api/build.rs): #35.
  • call-join and the process groups: #17.
  • ssg/templates/layout.html (the default layout templates.rs includes) and the starters are non-Rust, in the base commit. Tests (ssg/tests/, src/tests/rebuild.rs, src/tests/preview.rs, tests/call_cleanup_mdbook.rs) are in the base commit.

Category: SSGs, rebuilds and the preview build Size: 11 files, +2,184/−706 Rounds: round 0 at stack ae42e3c0; at 29a7c15b and at 6b650b2a none of this PR's files changed; round 1 at b66397c0 (FULL-SITE-PROCESS units 1 and 1c): mdBook builds in its own child (scripts::engine::build_book), so ssg/mdbook.rs loses the code that put each book command into the build's process group; ssg/script.rs starts its pane sweep on the narrowed thread at a site process's start. Read this round in its interdiff: https://tangled.org/notplants-bot.bsky.social/lichen.page.october/pulls/27/round/1/interdiff Plans and ledger: FULL-SITE-PROCESS-2026-10-25.md (units 1, 1c); SSG-BUILD-OVERRIDE-2026-10-02.md with SSG-BUILD-OVERRIDE-DESIGN-2026-10-08.md (B2); SSG-SCRIPT-SHORTCODES-2026-10-02.md; PER-SITE-PROCESS-2026-10-09.md (P2c-1, P4-5); CHILD-ENV-CLEAR-2026-10-08.md; REPLACE-TERA-WITH-SSR-REACT-2026-10-07.md (R1b); OPERATOR-REVIEW-REVISIONS-2026-10-13.md (N1, N7, R7); OPERATOR-REVIEW-FIXES-2026-10-07.md (U1, N8); SITE-FRONT-BOUNDARY-2026-10-17.md (decision 6). Ledger: lichen-builder B2087, B2322, B2777; lichen-adversary A11224, A11324, A11506. Inline #[cfg(test)] modules: none inline; 7 files point to a test file with #[path]. Bucket moves: round 1's Builds PR is split: SSGs and the lane here, scripts and the SSR in #26. preview.rs moved in from site core; the lichen-cms rebuild.rs deletion is placed with its new file. Round 1: #8 (Builds: scripts, shortcodes, SSGs and the server render) covered these files from 0b92cb61, except preview.rs, ssg.rs, ssg/overlay.rs and the lichen-cms deletions, which are new to the set.

Commits 0