Skip to content

Commit 7e07b17

Browse files
TMHSDigitalclaude
andauthored
fix(gallery): gate committed gallery drift in CI and prune stale pages (#211)
Found in a review of the Pages site: - docs/gallery/ is committed but regenerated at deploy, so a stale commit shipped fine and drifted silently. Validate now regenerates it and fails on any diff. - build_gallery.py never removed the page folder of a renamed or removed entry, so the old page stayed published. It now deletes folders that hold only a generated index.html and match no entry. - signpost-preview.webp and wall-torch-preview.webp in docs/gallery/assets were referenced by nothing and still published. - The tag filter offered both "render" and "rendering", and both "transform" and "transforms". Merged into the majority spelling. Signed-off-by: TMHSDigital <154358121+TMHSDigital@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1 parent bd42346 commit 7e07b17

6 files changed

Lines changed: 32 additions & 10 deletions

File tree

‎.github/workflows/validate.yml‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,20 @@ jobs:
142142
- name: Check falsifiers declare the budget they target
143143
run: python3 tests/check_falsifier_targets.py
144144

145+
- name: Check committed gallery matches its generator
146+
# docs/gallery/ is committed, but pages.yml regenerates it at deploy, so a
147+
# stale commit ships fine and drifts silently. Regenerate and require no diff.
148+
run: |
149+
python3 scripts/build_gallery.py
150+
drift=$(git status --porcelain -- docs/gallery)
151+
if [ -n "$drift" ]; then
152+
echo "::error::docs/gallery/ is stale. Run 'python scripts/build_gallery.py' and commit the result."
153+
echo "$drift"
154+
git --no-pager diff --stat -- docs/gallery
155+
exit 1
156+
fi
157+
echo "docs/gallery/ matches scripts/build_gallery.py output."
158+
145159
- name: Validate template Python syntax
146160
run: |
147161
echo "Checking template Python syntax..."
-6.85 KB
Binary file not shown.
-20.4 KB
Binary file not shown.

‎docs/gallery/index.html‎

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -323,13 +323,11 @@ <h1>Examples and Showcase</h1>
323323
<button class="chip" data-tag="parenting" type="button">parenting</button>
324324
<button class="chip" data-tag="performance" type="button">performance</button>
325325
<button class="chip" data-tag="properties" type="button">properties</button>
326-
<button class="chip" data-tag="render" type="button">render</button>
327326
<button class="chip" data-tag="rendering" type="button">rendering</button>
328327
<button class="chip" data-tag="sequencer" type="button">sequencer</button>
329328
<button class="chip" data-tag="shape-keys" type="button">shape-keys</button>
330329
<button class="chip" data-tag="showcase" type="button">showcase</button>
331330
<button class="chip" data-tag="sky" type="button">sky</button>
332-
<button class="chip" data-tag="transform" type="button">transform</button>
333331
<button class="chip" data-tag="transforms" type="button">transforms</button>
334332
<button class="chip" data-tag="uv" type="button">uv</button>
335333
<button class="chip" data-tag="world" type="button">world</button>
@@ -712,7 +710,7 @@ <h2><a href="custom-normals-shade/">custom-normals-shade</a></h2>
712710
<a class="card-link" href="custom-normals-shade/">View example<span class="sr-only"> custom-normals-shade</span> <span aria-hidden="true">&rarr;</span></a>
713711
</div>
714712
</article>
715-
<article class="card" data-tags="world sky render">
713+
<article class="card" data-tags="world sky rendering">
716714
<a class="card-media" href="sky-texture-sun-elevation/" tabindex="-1" aria-hidden="true">
717715
<img src="assets/sky-texture-sun-elevation-hero.webp" alt="sky-texture-sun-elevation — World ShaderNodeTexSky driving Background Color — the sky contract across 4.5 LTS and 5.1." loading="lazy" decoding="async" />
718716
</a>
@@ -745,7 +743,7 @@ <h2><a href="mesh-hygiene-audit/">mesh-hygiene-audit</a></h2>
745743
<a class="card-link" href="mesh-hygiene-audit/">View example<span class="sr-only"> mesh-hygiene-audit</span> <span aria-hidden="true">&rarr;</span></a>
746744
</div>
747745
</article>
748-
<article class="card" data-tags="transform parenting game-pipeline">
746+
<article class="card" data-tags="transforms parenting game-pipeline">
749747
<a class="card-media" href="prop-origin-transform/" tabindex="-1" aria-hidden="true">
750748
<img src="assets/prop-origin-transform-hero.webp" alt="prop-origin-transform — Street pedestal origin-to-base-center + data-API scale apply + matrix_parent_inverse for a flanged conduit accessory." loading="lazy" decoding="async" />
751749
</a>
@@ -811,7 +809,7 @@ <h2><a href="modular-kit-snap/">modular-kit-snap</a></h2>
811809
<a class="card-link" href="modular-kit-snap/">View example<span class="sr-only"> modular-kit-snap</span> <span aria-hidden="true">&rarr;</span></a>
812810
</div>
813811
</article>
814-
<article class="card" data-tags="uv game-pipeline render">
812+
<article class="card" data-tags="uv game-pipeline rendering">
815813
<a class="card-media" href="lightmap-uv-channel/" tabindex="-1" aria-hidden="true">
816814
<img src="assets/lightmap-uv-channel-hero.webp" alt="lightmap-uv-channel — A market cart carrying the two-channel UV contract for baked lighting: UV0 untouched, UVLight packed with no overlaps and a respected margin." loading="lazy" decoding="async" />
817815
</a>
@@ -833,7 +831,7 @@ <h2><a href="socket-attach-points/">socket-attach-points</a></h2>
833831
<a class="card-link" href="socket-attach-points/">View example<span class="sr-only"> socket-attach-points</span> <span aria-hidden="true">&rarr;</span></a>
834832
</div>
835833
</article>
836-
<article class="card" data-tags="mesh attributes game-pipeline render">
834+
<article class="card" data-tags="mesh attributes game-pipeline rendering">
837835
<a class="card-media" href="vertex-color-ao/" tabindex="-1" aria-hidden="true">
838836
<img src="assets/vertex-color-ao-hero.webp" alt="vertex-color-ao — A stone well carrying baked ambient occlusion in a colour attribute, with the bake held to the closed-form hemisphere integral rather than to a captured value." loading="lazy" decoding="async" />
839837
</a>

‎examples/gallery.json‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@
432432
"tags": [
433433
"world",
434434
"sky",
435-
"render"
435+
"rendering"
436436
]
437437
},
438438
{
@@ -469,7 +469,7 @@
469469
"hero": "docs/gallery/assets/prop-origin-transform-hero.webp",
470470
"preview": "examples/prop-origin-transform/preview.webp",
471471
"tags": [
472-
"transform",
472+
"transforms",
473473
"parenting",
474474
"game-pipeline"
475475
]
@@ -551,7 +551,7 @@
551551
"tags": [
552552
"uv",
553553
"game-pipeline",
554-
"render"
554+
"rendering"
555555
]
556556
},
557557
{
@@ -579,7 +579,7 @@
579579
"mesh",
580580
"attributes",
581581
"game-pipeline",
582-
"render"
582+
"rendering"
583583
]
584584
},
585585
{

‎scripts/build_gallery.py‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1059,6 +1059,16 @@ def main() -> int:
10591059
encoding="utf-8",
10601060
)
10611061

1062+
# A renamed or removed entry would otherwise leave its old page published
1063+
# forever. Only folders this generator wrote qualify: a lone index.html
1064+
# and nothing else, so assets/, contact-sheets/ and asset-sheets/ are safe.
1065+
names = {ex["name"] for ex in examples}
1066+
for d in sorted(p for p in OUT_DIR.iterdir() if p.is_dir() and p.name not in names):
1067+
if [c.name for c in d.iterdir()] == ["index.html"]:
1068+
(d / "index.html").unlink()
1069+
d.rmdir()
1070+
print(f"Removed stale page {d.relative_to(REPO)}")
1071+
10621072
n_showcase = sum(1 for ex in examples if "showcase" in (ex.get("tags") or []))
10631073
print(
10641074
f"Wrote {OUT_DIR / 'index.html'} + {len(examples)} detail pages "

0 commit comments

Comments
 (0)