I shipped a working tree earlier and had to tell John "live matches no commit in
the repo" — which is exactly the sentence a deploy should make impossible.
deploy.sh now writes the HEAD short-sha to web root as VERSION, and verifies it
came back. `curl https://partly.party/gutsy/VERSION` answers "what is online right
now" without trusting anyone's memory of the last deploy.
The dirty check is scoped to `git status --porcelain -- web/`, not the whole
tree, because only web/ ships: editing docs or this script does not make the
payload unreproducible, and a stamp that cried wolf on every NOTES edit would get
ignored. A dirty payload ships as `<sha>-dirty` and says so, loudly, rather than
refusing — mid-round lanes need to push a look at something without committing
first, and a deploy tool that blocks that will just get bypassed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
README said "target: partly.party, not wired yet". It's wired.
tools/deploy.sh follows the GAMES doctrine (deploy-map skill): QA gate -> rsync
web/ to VPS staging -> docker cp into forum-nginx -> verify. No build step, so
web/ ships as-is: vanilla ES modules + importmap with three r175 vendored, all
paths relative or resolved from import.meta.url, which is why it runs from a
subdirectory with no base rewrite. 6.6 MB. nginx.conf needed no edit — its
catch-all `root /usr/share/nginx/html` already routes any new directory, which is
how blobbo works. /gutsy (no slash) 301s to /gutsy/.
Excludes web/dev/ (ruling #5: never shipped). Verified live, not assumed: the
lane harnesses 404 through to the arcade index.
THE 200 THAT ISN'T. That same catch-all try_files means ANY missing file returns
the arcade's index.html with HTTP 200. A deploy that lost every module would
still curl 200 on all of them. So every check asserts on CONTENT, never on the
status code — this is the failure deploy-map records as ".bin data URLs serving
arcade HTML". The guard caught itself, too: it originally grepped for
`<title>MonsterRobot`, but the arcade's real title is
`~*~W3LC0M3 2 TH3 M0NST3R R0B0T P4RTY 4RC4D3~*~`, so it could never have fired.
Matched against the live box now.
DURABILITY, and it's John's call. This docker-cp's into the container's own
layer, matching blobbo/glytch: zero downtime, nothing else touched, survives
restarts and reboots (restart: unless-stopped) — but NOT `docker compose up
--force-recreate` or an nginx image bump, which wipe it. Re-running the script is
the fix. The durable alternative is a bind mount in forum/docker-compose.yml like
cratewars/roguelike have, which costs a forum-nginx recreate and brief downtime
across ALL of partly.party, so this script does not take that decision.
ship-check (README says run it before deploying — I ran it after; my miss, and it
came back clean):
1 auth N/A — static files, no endpoint/API/admin surface
2 secrets PASS — nothing secret-shaped in the payload or the diff
3 input/SSRF PASS — the only user string reaching a fetch is ?lvl=, and C
gates it on the CAMPAIGN allowlist BEFORE the load
(levels/index.js:151). Traversal tested live with
`curl --path-as-is` (plain curl normalises ../ away and proves
nothing): /etc/passwd never leaked. DEPOT_BASE in assets.js is
unused — the manifest has zero external URLs.
4 money N/A
5 deploy PASS — verified by content + booted in a real browser:
assets.misses() == [], 15 draws, 69k tris, zero console errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Generated on MODELBEAST flux_local, on-device, $0.00. Lane D's pipeline used
unchanged; **D owns these — ratify, retune or bin them.**
Why A did D's job: the six-biome tint contact sheet could only judge 3 of 6
biomes for real (oral/large_intestine/appendix had no pack and fell back to
procedural), and you cannot ratify a tint against a stand-in. All six are now
textured — the set ART_BIBLE §Biome palettes promises.
- wall_oral_a/b, wall_colon_a/b + normals. Seams 6.35/9.30/14.06/6.37 -> 1.01/
1.08/0.74/1.36 (D's "indistinguishable" band; the shipped pack's weakest is
2.39). Means normalised to ~0.50 by D's derive_maps, untouched.
- appendix wears the colon pack at its own gold tint (TEXTURE_SHARE in
world/index.js) — anatomically it IS colon tissue, and it's ART_BIBLE's
"one texture, two biomes" law for zero bytes. Distinct from the temporary
slug map; keep it when that dies.
- oral_a took three subjects. v1 named an ORGAN ("tongue") and FLUX drew the
organ's silhouette — D's "one urchin of villi" in a field's clothing. v2 named
the tissue but papillae are 3D projections, so perspective gave it a vanishing
point that tiles into starbursts. v3 asks for squamous cell pavement: flat by
construction. Rule for the kit: prompt the SURFACE, not the FEATURE.
Evidence: docs/shots/laneA/round2_oral_prompt_evolution.png
PROVENANCE DEFECT FOUND AND FIXED (-> Lane D):
batch_textures.json recorded, for 4 of 6 walls, the prompt from the framing
experiment D tried and rejected — not the prompt that made the shipped pack.
record() only runs on generation, so reverting a prompt while keeping its image
(exactly what D correctly did: "four winners kept untouched rather than churned")
drifts the record silently. Proved by regenerating esophagus_a at seed 1101 under
both prompts: the code's prompt reproduces the shipped wall, the recorded one
gives the bland wood-grain D described rejecting. Evidence:
docs/shots/laneA/round2_provenance_probe.png. Records re-pointed at the code's
prompt (images untouched — they were never wrong).
New: gen_textures.py --verify-provenance + qa.sh gate 5b, so it cannot rot again.
qa GREEN incl. the new gate; 11/11 provenance verified; all six biomes eyeballed
in engine (docs/shots/laneA/round2_tint_*.png).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Wired B's player/combat + event pump, D's assets, C's level pick into boot.
Fixed qa ESM gate (node --check no-op, found by B) + added spline selfcheck.
TECH: world contract FROZEN v1.1, bus events ratified, colorspace + crest-speed
laws (CREST_FACTOR 1.6 — B proved surfing lost to throttle at 1.0). Stub complies.
Verified integrated build via 60s stepped sim: 9 draws, 0 errors, 0 asset misses;
one known gap (fiction-id spawn resolve) confirmed and assigned as B's top item.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>