A private build ran 11ty with FORGE_WWW=$out FORGE_PUBLIC_WWW=$FORGE_WWW in one command's assignments, and the second saw the first, so the public root it shipped assets against was its own scratch directory. It then swapped those assets into www/assets, carrying over nothing the public pages had linked: every page whose CSS bundle no private page renders lost its styles at the next private build, the reviews list first, and a full build didn't bring them back while those pages were unchanged. The public root is now named before the assignments. The new scenario checks every stylesheet public pages link after public, private and full builds; it fails without the fix.
- commit
- b3db93038c62d33b856ecbd52a28c7bc3028fc05
- parent
- 93e7cb4184d710b4dd2389c7f2ebd41c7147c081
- author
- cat <admin@dev.site>
- ci
- ✓ passed in 81s, signed by cat
- kind
- fix risk score 1.1 of 3, Jev's estimate
- review
- #8 Keep public pages' stylesheets through a private build
ci attestation
forge-attestation 1 type ci commit b3db93038c62d33b856ecbd52a28c7bc3028fc05 tree 80d811f4395c321700fb6035d734e9a80e2cae63 script .forge/ci 38df37c0d5a6382f60569079a0dd821094e37e4a result pass exit 0 started 2026-10-18T23:48:49Z duration 81s runner (not shown here; refs/notes/ci has it) system Darwin 25.5.0 arm64 env host log sha256:fefe2ab06c4b817cb8fd63f8ef8fad93aa47fa6f1c0559ae4c1000bf29dfe979 242 lines |remote: review #4: /dami/greet/reviews/4/ |pushed wip/i18n |216a1b1 running .forge/ci: greet.sh: say what it is | | sh: /bin/sh | | ok greet |216a1b1 pass in 0s, signed |pushed main |remote: review #4: /dami/greet/reviews/4/ |pushed wip/i18n |4acafda running .forge/ci: wave at the world | | sh: /bin/sh | | FAIL greet : got 'hello, world o/', want 'hello, world' |4acafda fail in 0s, signed |forge: 1 commit(s) did not pass |remote: review #6: /dami/greet/reviews/6/ |pushed ana/wave |0277854 running .forge/ci: update the test for the wave | | sh: /bin/sh | | ok greet |0277854 pass in 0s, signed |remote: review #6: /dami/greet/reviews/6/ |pushed ana/wave |warning: You appear to have cloned an empty repository. |site home: deployed 6483129 -> /sites/ana/dotfiles/home/ |created ana/notes |remote: review #1: /ana/notes/reviews/1/ |pushed ana/todo |landing #1 A todo list: ana/todo -> main |1fab8cf running .forge/ci: web, server and Python versions of greet | | sh: /bin/sh | | ok greet |1fab8cf pass in 0s, signed |pushed main |f69ad0f running .forge/ci: messages: notes for the later regions | | sh: /bin/sh | | ok greet |f69ad0f pass in 0s, signed |remote: review #7: /dami/greet/reviews/7/ |pushed dami/regions |created dami/forge |warning: You appear to have cloned an empty repository. |site guide: deployed ff0c892 -> /sites/dami/forge/guide/ |(node:18657) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time |(Use `node --trace-warnings ...` to show where the warning was created) |built ana/dotfiles in 0s -> /Users/dami/Library/Caches/forge/ci/35f7a65d0235/demo/root/.forge/www |(node:18781) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time |(Use `node --trace-warnings ...` to show where the warning was created) |built ana/notes in 1s -> /Users/dami/Library/Caches/forge/ci/35f7a65d0235/demo/root/.forge/www |(node:18929) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time |(Use `node --trace-warnings ...` to show where the warning was created) |built dami/forge in 0s -> /Users/dami/Library/Caches/forge/ci/35f7a65d0235/demo/root/.forge/www |(node:19063) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time |(Use `node --trace-warnings ...` to show where the warning was created) |built dami/greet in 2s -> /Users/dami/Library/Caches/forge/ci/35f7a65d0235/demo/root/.forge/www |(node:19739) ExperimentalWarning: stripTypeScriptTypes is an experimental feature and might change at any time |(Use `node --trace-warnings ...` to show where the warning was created) |built - in 0s -> /Users/dami/Library/Caches/forge/ci/35f7a65d0235/demo/root/.forge/www |226 of 226 pages render the same without 11ty |guide: 4 files, links ok |ok
Signature: good, cat
| M | bin/ | 7 | ++++++- |
| A | test/ | 31 | ++++++++++++++++++++++++++++++ |
@@ -2493,7 +2493,12 @@ build_private() {
24932493 t0=$(date +%s)24942494 write_graph "$FORGE_ROOT/$only.git"24952495 private_www2496- (cd "$FORGE_HOME" && FORGE_PRIVATE=1 FORGE_ONLY=$only FORGE_WWW=$out FORGE_LIVE_WWW=$FORGE_PRIVATE_WWW FORGE_PUBLIC_WWW=$FORGE_WWW \2496+ # The public root, named before FORGE_WWW=$out below: in one command's2497+ # assignments, whether a later one sees an earlier one differs between2498+ # shells, and the build's assets must carry over the public pages'2499+ # bundles, or a private build would drop them from www/assets.2500+ public=$FORGE_WWW2501+ (cd "$FORGE_HOME" && FORGE_PRIVATE=1 FORGE_ONLY=$only FORGE_WWW=$out FORGE_LIVE_WWW=$FORGE_PRIVATE_WWW FORGE_PUBLIC_WWW=$public \24972502 FORGE_BUILD_STARTED=$((t0 * 1000)) FORGE_BUILD_REASON=${FORGE_BUILD_REASON:-manual} \24982503 "$FORGE_HOME/node_modules/.bin/eleventy" --config=eleventy.config.ts --quiet --output="$out")24992504 mkdir -p "$FORGE_WWW"@@ -0,0 +1,31 @@
1+# A private repo's build ships its assets into the public www/assets too,2+# so it must carry over every bundle the public pages link: here the3+# reviews page of a public repo, whose CSS bundle no private page renders.4+# Each page's stylesheets must exist after every kind of build.5+. "$(dirname "$0")/../lib.sh"6+user dami7+repo dami/pub8+repo --private dami/sec9+clone dami dami/pub "$T/w/p"10+at "$T/w/p" commit "first"11+push_as dami "$T/w/p" origin main12+at "$T/w/p" git switch -q -c dami/x13+at "$T/w/p" commit "x"14+push_as dami "$T/w/p" origin dami/x15+clone dami dami/sec "$T/w/s"16+at "$T/w/s" commit "first"17+push_as dami "$T/w/s" origin main18+# Every stylesheet the public pages link is in www/assets.19+styles() {20+ for f in $(grep -rhoE 'href="/assets/[^"]+\.css"' "$FORGE_WWW/dami/pub" "$FORGE_WWW/index.html" | sed 's/href="\/assets\///; s/"//' | sort -u); do21+ [ -f "$FORGE_WWW/assets/$f" ] || fail "$1: a public page links /assets/$f, which isn't there"22+ done23+}24+build dami/pub25+styles "after the public build"26+build dami/sec27+styles "after a private build"28+build29+styles "after a full build"30+build dami/sec31+styles "after another private build"