[lane A] Complete the biome texture set (oral + colon) + a provenance gate

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>
This commit is contained in:
jing 2026-07-16 17:44:58 +10:00
parent ecf43940ec
commit 3a6dbc30a3
19 changed files with 229 additions and 5 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 896 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 832 KiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 633 KiB

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1001 KiB

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

View File

@ -12,6 +12,48 @@
"steps": 4, "steps": 4,
"tile": null "tile": null
}, },
"wall_colon_a": {
"gen_seconds": 9.1,
"guidance": 3.5,
"kb": 69,
"kb_n": 188,
"kind": "wall",
"mean_after": 0.495,
"mean_before": 0.234,
"model": "flux2-klein-4b",
"prompt": "scanning electron microscope micrograph, monochrome, high detail organic tissue, dark background, dramatic rim lighting, seamless tiling texture, colonic mucosa, smooth undulating folds, scattered biofilm patches",
"seam_after": 0.74,
"seam_before": 14.06,
"seed": 1501,
"size": 1024,
"steps": 4,
"tile": [
3,
20
],
"tile_mode": "blend"
},
"wall_colon_b": {
"gen_seconds": 9.0,
"guidance": 3.5,
"kb": 180,
"kb_n": 313,
"kind": "wall",
"mean_after": 0.497,
"mean_before": 0.271,
"model": "flux2-klein-4b",
"prompt": "scanning electron microscope micrograph, monochrome, high detail organic tissue, dark background, dramatic rim lighting, seamless tiling texture, colonic wall coated in thick bacterial biofilm, lumpy microbial mats and mucus sheets covering the whole surface, filling the entire frame edge to edge",
"seam_after": 1.36,
"seam_before": 6.37,
"seed": 1502,
"size": 1024,
"steps": 4,
"tile": [
4,
15
],
"tile_mode": "blend"
},
"wall_esophagus_a": { "wall_esophagus_a": {
"gen_seconds": 9.1, "gen_seconds": 9.1,
"guidance": 3.5, "guidance": 3.5,
@ -21,7 +63,8 @@
"mean_after": 0.495, "mean_after": 0.495,
"mean_before": 0.216, "mean_before": 0.216,
"model": "flux2-klein-4b", "model": "flux2-klein-4b",
"prompt": "scanning electron microscope micrograph, monochrome, high detail organic tissue, dark background, dramatic rim lighting, seamless tiling texture, flat top-down macro swatch filling the entire frame edge to edge, uniform repeating coverage, no single central subject, nothing else visible, human esophageal mucosa, longitudinal ribbed folds, wet ridges", "prompt": "scanning electron microscope micrograph, monochrome, high detail organic tissue, dark background, dramatic rim lighting, seamless tiling texture, human esophageal mucosa, longitudinal ribbed folds, wet ridges",
"prompt_corrected": "2026-07-16 Lane A: record held the REJECTED framing experiment's prompt (LANE_D_NOTES \u00a7prompt-kit); the shipped image was proved to come from this one. Evidence: docs/shots/laneA/round2_provenance_probe.png",
"seam_after": 1.14, "seam_after": 1.14,
"seam_before": 3.7, "seam_before": 3.7,
"seed": 1101, "seed": 1101,
@ -54,6 +97,48 @@
], ],
"tile_mode": "blend" "tile_mode": "blend"
}, },
"wall_oral_a": {
"gen_seconds": 9.2,
"guidance": 3.5,
"kb": 108,
"kb_n": 230,
"kind": "wall",
"mean_after": 0.49,
"mean_before": 0.168,
"model": "flux2-klein-4b",
"prompt": "scanning electron microscope micrograph, monochrome, high detail organic tissue, dark background, dramatic rim lighting, seamless tiling texture, oral mucosa, cobblestone pavement of flat polygonal squamous epithelial cells, tightly packed cell borders, wet glistening surface, filling the entire frame edge to edge",
"seam_after": 1.01,
"seam_before": 6.35,
"seed": 1001,
"size": 1024,
"steps": 4,
"tile": [
5,
12
],
"tile_mode": "blend"
},
"wall_oral_b": {
"gen_seconds": 9.1,
"guidance": 3.5,
"kb": 220,
"kb_n": 363,
"kind": "wall",
"mean_after": 0.498,
"mean_before": 0.322,
"model": "flux2-klein-4b",
"prompt": "scanning electron microscope micrograph, monochrome, high detail organic tissue, dark background, dramatic rim lighting, seamless tiling texture, tooth enamel surface, hard mineralized crystalline texture, fine cracks and wear pits",
"seam_after": 1.08,
"seam_before": 9.3,
"seed": 1002,
"size": 1024,
"steps": 4,
"tile": [
3,
20
],
"tile_mode": "blend"
},
"wall_smallint_a": { "wall_smallint_a": {
"gen_seconds": 9.2, "gen_seconds": 9.2,
"guidance": 3.5, "guidance": 3.5,
@ -84,7 +169,8 @@
"mean_after": 0.496, "mean_after": 0.496,
"mean_before": 0.24, "mean_before": 0.24,
"model": "flux2-klein-4b", "model": "flux2-klein-4b",
"prompt": "scanning electron microscope micrograph, monochrome, high detail organic tissue, dark background, dramatic rim lighting, seamless tiling texture, flat top-down macro swatch filling the entire frame edge to edge, uniform repeating coverage, no single central subject, nothing else visible, intestinal crypts of Lieberkuhn, honeycomb of round pits, packed glandular openings", "prompt": "scanning electron microscope micrograph, monochrome, high detail organic tissue, dark background, dramatic rim lighting, seamless tiling texture, intestinal crypts of Lieberkuhn, honeycomb of round pits, packed glandular openings",
"prompt_corrected": "2026-07-16 Lane A: record held the REJECTED framing experiment's prompt (LANE_D_NOTES \u00a7prompt-kit); the shipped image was proved to come from this one. Evidence: docs/shots/laneA/round2_provenance_probe.png",
"seam_after": 1.32, "seam_after": 1.32,
"seam_before": 10.5, "seam_before": 10.5,
"seed": 1302, "seed": 1302,
@ -105,7 +191,8 @@
"mean_after": 0.496, "mean_after": 0.496,
"mean_before": 0.216, "mean_before": 0.216,
"model": "flux2-klein-4b", "model": "flux2-klein-4b",
"prompt": "scanning electron microscope micrograph, monochrome, high detail organic tissue, dark background, dramatic rim lighting, seamless tiling texture, flat top-down macro swatch filling the entire frame edge to edge, uniform repeating coverage, no single central subject, nothing else visible, gastric mucosa, pitted craters, gastric pits, glistening mucus", "prompt": "scanning electron microscope micrograph, monochrome, high detail organic tissue, dark background, dramatic rim lighting, seamless tiling texture, gastric mucosa, pitted craters, gastric pits, glistening mucus",
"prompt_corrected": "2026-07-16 Lane A: record held the REJECTED framing experiment's prompt (LANE_D_NOTES \u00a7prompt-kit); the shipped image was proved to come from this one. Evidence: docs/shots/laneA/round2_provenance_probe.png",
"seam_after": 0.87, "seam_after": 0.87,
"seam_before": 12.16, "seam_before": 12.16,
"seed": 1201, "seed": 1201,
@ -126,7 +213,8 @@
"mean_after": 0.497, "mean_after": 0.497,
"mean_before": 0.25, "mean_before": 0.25,
"model": "flux2-klein-4b", "model": "flux2-klein-4b",
"prompt": "scanning electron microscope micrograph, monochrome, high detail organic tissue, dark background, dramatic rim lighting, seamless tiling texture, flat top-down macro swatch filling the entire frame edge to edge, uniform repeating coverage, no single central subject, nothing else visible, stomach rugae, thick heavy folded ridges, deep valleys between folds", "prompt": "scanning electron microscope micrograph, monochrome, high detail organic tissue, dark background, dramatic rim lighting, seamless tiling texture, stomach rugae, thick heavy folded ridges, deep valleys between folds",
"prompt_corrected": "2026-07-16 Lane A: record held the REJECTED framing experiment's prompt (LANE_D_NOTES \u00a7prompt-kit); the shipped image was proved to come from this one. Evidence: docs/shots/laneA/round2_provenance_probe.png",
"seam_after": 1.08, "seam_after": 1.08,
"seam_before": 17.85, "seam_before": 17.85,
"seed": 1202, "seed": 1202,

View File

@ -67,6 +67,54 @@ WALLS = {
"wall_smallint_b": dict( "wall_smallint_b": dict(
p="intestinal crypts of Lieberkuhn, honeycomb of round pits, packed glandular openings", p="intestinal crypts of Lieberkuhn, honeycomb of round pits, packed glandular openings",
seed=1302, tile=[6, 10]), seed=1302, tile=[6, 10]),
# ── oral + colon: added round 2 by LANE A, on D's behalf, using D's pipeline unchanged ──
# Why A: the six-biome tint contact sheet (web/dev/laneA_world.html?lvl=biomes) could only
# eyeball 3 of 6 biomes for real — oral and large_intestine had no pack and fell back to
# procedural, and you cannot ratify a tint against a stand-in. These complete the set that
# ART_BIBLE §Biome palettes promises. **D owns them: ratify, retune or bin them.**
# Seeds follow D's anatomical-order convention (11xx esophagus … 13xx smallint); oral sits
# before esophagus at 10xx, and colon takes 15xx because 14xx was already the matcap.
#
# NOTE for D + F: ART_BIBLE §FLUX prompt kit has NO oral entry (it lists esophageal,
# stomach, small intestine, colon). colon_a below is the bible's line VERBATIM; the other
# three subjects are new text, and the mouth ones are therefore an ART_BIBLE *gap* I filled
# rather than a spec I followed — see LANE_A_NOTES §→ Lane D for the proposed amendment.
"wall_oral_a": dict(
# Third subject, and the reason is worth more than the texture (PIPELINE §Textures.2:
# "≤2 attempts, then pick a different prompt" — so this is a different prompt, not a
# third tweak):
# v1 "…soft wet TONGUE surface" -> a perfect SEM dome. Naming an ORGAN summons
# its silhouette: "tongue" is a thing with a shape, so FLUX drew the thing and
# arranged the papillae on it. That's D's "one urchin of villi" in a field's
# clothing, and it's why the edge-to-edge clause alone couldn't save it.
# v2 "…mucosa … flat top-down macro" -> full coverage, but the papillae still
# radiated from a centre. The real culprit was never the framing: **papillae are
# 3D projections, so any honest render of them has perspective, and perspective
# has a vanishing point** — a radial rosette that tiles into starbursts.
# v3 (this): ask for a subject that is FLAT BY CONSTRUCTION. Squamous epithelium is
# what oral mucosa actually is at SEM scale — a pavement of polygonal cells, no
# projections, nothing to foreshorten. It also reads clinical/bright (ART_BIBLE
# "tutorial-readable") and collides with nothing else in the pack.
# Rule for the kit, generalising D's: prompt the tissue's SURFACE, not its FEATURES.
p="oral mucosa, cobblestone pavement of flat polygonal squamous epithelial cells, "
"tightly packed cell borders, wet glistening surface, filling the entire frame edge to edge",
seed=1001, tile=[5, 12]),
"wall_oral_b": dict(
# Deliberately NOT tissue: enamel is the one hard, mineral, non-organic surface in the
# whole game, it reads instantly as "mouth", and it gives L1's molar crush-cycles
# (GDD/Lane C) a wall of their own. No framing clause — a surface, not a subject.
p="tooth enamel surface, hard mineralized crystalline texture, fine cracks and wear pits",
seed=1002, tile=[3, 20]),
"wall_colon_a": dict(
p="colonic mucosa, smooth undulating folds, scattered biofilm patches", # bible, verbatim
seed=1501, tile=[3, 20]),
"wall_colon_b": dict(
# A COATING, not folds — that's what keeps it clear of stomach_b's rugae and of
# smallint_b's crypt honeycomb, and it is what "dark swamp" (ART_BIBLE) actually is.
p="colonic wall coated in thick bacterial biofilm, lumpy microbial mats and mucus "
"sheets covering the whole surface, filling the entire frame edge to edge",
seed=1502, tile=[4, 15]),
} }
# matcap: NOT tileable, NOT seam-blended — a lit sphere cropped to a square (see derive_maps) # matcap: NOT tileable, NOT seam-blended — a lit sphere cropped to a square (see derive_maps)
MATCAPS = { MATCAPS = {
@ -131,10 +179,45 @@ def record(slug, fn, secs):
json.dump(log, open(BATCH, "w"), indent=2, sort_keys=True) json.dump(log, open(BATCH, "w"), indent=2, sort_keys=True)
def verify_provenance():
"""Assert the recorded prompt still equals what this script emits, per asset.
Added round 2 by Lane A after finding 4 of 6 walls had drifted (see LANE_A_NOTES §-> Lane D).
The failure is invisible and the script's own docstring is the thing it breaks
("regeneration must always be possible"): record() only runs when you GENERATE, so if you
change a prompt and keep the old image exactly what D's rejected framing experiment
correctly did, keeping four winners rather than churning them the JSON keeps the prompt
that was never shipped. Nothing warns you. Re-generating from it silently yields a
different texture (proved: docs/shots/laneA/round2_provenance_probe.png).
Fixing a drift is a judgement call, so this reports and never rewrites:
- the image is the one you want => the RECORD is stale: re-point it at the code prompt.
- the record is what you want => regenerate the image (--local) and it self-heals.
"""
log = json.load(open(BATCH)) if os.path.exists(BATCH) else {}
drift, missing = [], []
for slug in sorted(PROMPTS):
if slug not in log:
missing.append(slug)
elif log[slug].get("prompt") != prompt_of(slug):
drift.append(slug)
for s in missing:
print(f" no record {s:22s} (never generated, or provenance lost)")
for s in drift:
print(f" DRIFT {s:22s} recorded prompt != prompt this script would send")
ok = not drift
print(f"provenance: {len(PROMPTS) - len(drift) - len(missing)}/{len(PROMPTS)} verified, "
f"{len(drift)} drifted, {len(missing)} unrecorded")
return ok
if __name__ == "__main__": if __name__ == "__main__":
only = sys.argv[sys.argv.index("--only") + 1] if "--only" in sys.argv else "" only = sys.argv[sys.argv.index("--only") + 1] if "--only" in sys.argv else ""
todo = {s: prompt_of(s) for s in PROMPTS if (not only or only in s)} todo = {s: prompt_of(s) for s in PROMPTS if (not only or only in s)}
if "--verify-provenance" in sys.argv:
sys.exit(0 if verify_provenance() else 1)
if "--harvest" in sys.argv: if "--harvest" in sys.argv:
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import derive_maps import derive_maps

View File

@ -47,6 +47,18 @@ if [ -f pipeline/validate_manifest.py ]; then
python3 pipeline/validate_manifest.py && green "manifest valid" || red "manifest errors" python3 pipeline/validate_manifest.py && green "manifest valid" || red "manifest errors"
fi fi
# 5b. Asset provenance: does batch_textures.json still record the prompt that made the pack?
# Added by Lane A (round 2) after finding 4 of 6 walls recorded the prompt from Lane D's
# REJECTED framing experiment — regenerating from provenance produced a visibly different
# texture (docs/shots/laneA/round2_provenance_probe.png). record() only runs on generation, so
# reverting a prompt while keeping its image drifts silently and forever. This is the gate.
# Stdlib only, no GPU, no network. -> F: yours to keep or drop, flagged in LANE_A_NOTES.
if [ -f pipeline/gen_textures.py ]; then
python3 pipeline/gen_textures.py --verify-provenance >/dev/null 2>&1 \
&& green "texture provenance" \
|| red "texture provenance drift — run: python3 pipeline/gen_textures.py --verify-provenance"
fi
# 6. vendor present (the game must run offline) # 6. vendor present (the game must run offline)
[ -f web/vendor/three.module.js ] && green "vendor: three r175 present" || red "web/vendor/three.module.js missing" [ -f web/vendor/three.module.js ] && green "vendor: three r175 present" || red "web/vendor/three.module.js missing"

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 364 KiB

View File

@ -47,6 +47,22 @@
}, },
"models": {}, "models": {},
"textures": { "textures": {
"wall_colon_a": {
"normal": "gen/wall_colon_a_n.webp",
"tile": [
3,
20
],
"url": "gen/wall_colon_a.webp"
},
"wall_colon_b": {
"normal": "gen/wall_colon_b_n.webp",
"tile": [
4,
15
],
"url": "gen/wall_colon_b.webp"
},
"wall_esophagus_a": { "wall_esophagus_a": {
"normal": "gen/wall_esophagus_a_n.webp", "normal": "gen/wall_esophagus_a_n.webp",
"tile": [ "tile": [
@ -63,6 +79,22 @@
], ],
"url": "gen/wall_esophagus_b.webp" "url": "gen/wall_esophagus_b.webp"
}, },
"wall_oral_a": {
"normal": "gen/wall_oral_a_n.webp",
"tile": [
5,
12
],
"url": "gen/wall_oral_a.webp"
},
"wall_oral_b": {
"normal": "gen/wall_oral_b_n.webp",
"tile": [
3,
20
],
"url": "gen/wall_oral_b.webp"
},
"wall_smallint_a": { "wall_smallint_a": {
"normal": "gen/wall_smallint_a_n.webp", "normal": "gen/wall_smallint_a_n.webp",
"tile": [ "tile": [

View File

@ -66,7 +66,16 @@ export async function createWorld(levelData, { rng, quality = 'high', assets = n
// (`assets.misses()`), so a drifted slug announces itself instead of silently falling back // (`assets.misses()`), so a drifted slug announces itself instead of silently falling back
// forever — which is what made this dangerous in round 1. // forever — which is what made this dangerous in round 1.
const TEXTURE_SLUG = { small_intestine: 'smallint', large_intestine: 'colon' }; const TEXTURE_SLUG = { small_intestine: 'smallint', large_intestine: 'colon' };
const slug = (biomeId) => TEXTURE_SLUG[biomeId] ?? biomeId;
// NOT temporary, and not the same thing as the slug map above: this is the ART_BIBLE's
// "one texture can serve two biomes at different tints" law, used deliberately. The appendix
// is anatomically an outpouching of the colon — it is the same tissue — so it wears the colon
// pack under its own gold tint and costs zero bytes. Keep this when the slug map dies.
const TEXTURE_SHARE = { appendix: 'large_intestine' };
const slug = (biomeId) => {
const b = TEXTURE_SHARE[biomeId] ?? biomeId;
return TEXTURE_SLUG[b] ?? b;
};
/** One wall's full texture set, all optional and independently so. */ /** One wall's full texture set, all optional and independently so. */
function texturesFor(biomeId) { function texturesFor(biomeId) {