GROOM_STAGE_SPEC.md

systems/GROOM_STAGE_SPEC.md

THE GROOM STAGE SPEC — hair as a standing factory stage, not a one-off

What this is. The build spec for GROOM as a standing stage of the character factory chain, per

Josh's factory-enhancement roster item 3: *"GROOM as a standing stage: per-age hair states carrying

the ruled color curve, with physics/wind — not a one-off for the protagonist."*

(docs/spine/DECISIONS_PENDING_JOSH.md L4710-4711, THE FACTORY ENHANCEMENT ROSTER.) The emphasis in

that line is the whole point: one head has a groom today, and a factory that stamps every living

asset needs a stage.

Authority. PROPOSAL-TIER, and it rules nothing. Canon, the CVD and Josh's rulings bind every

line. Where this spec and canon disagree, canon wins and this spec is the defect. It says HOW hair

gets built; the colour curve, the keystone ages, and the ear-visibility law were already ruled and

this spec quotes them rather than restating them.

Honest tier. Everything below about current state is a measured read off a landed record. **No

groom asset in this project is graded acceptable.** The stage-map verdict for grooms and cloth is

PARTIAL / MISSING (docs/pipeline_review/AAA_WORKFLOW_CORRESPONDENCE_2026-08-06.md L58), and this

spec inherits that register unchanged.

---

0. THE UNBLOCK TRIGGER — superseded in place 2026-08-10 (director-rows wave, roadmap C-01)

**This section originally read "nothing in this spec executes yet / every execution step below is

BLOCKED" behind two blockers. Blocker 1 is DISCHARGED BY EVENTS; blocker 2 stands. Execution has in

fact landed, and it went FURTHER than this spec's card-atlas route:** the card cap is RETIRED and

REPLACED by a 68,000-strand Alembic groom on the V2.1 head — a UE5 Groom asset with 6,800 guides,

ShadingModel = Hair, measured passes on crown root coverage (1.0000 within 4 mm), eye clearance,

and strand definition (build/3d/best_a14/groom/GROOM_REBUILD_RECORD.md, landed canon 49e97ae8 /

game 0542b95; charter S11 row). What remains OWED on that landed groom — the GroomBinding async-build crash, the exposure

control that never takes, and the colour bar behind it — is charter S11's register and is a claimed

in-flight wave tonight (bee8d8d5), not this spec's blocker. A doc still reading "blocked" while a

strand groom is landed is the drift class the living-source law exists to kill; hence this

supersession. The card-atlas harness below remains valid as the per-LOD CARD representation route

(cards vs strands is a per-LOD choice, CRAFT_TEXTURE_LOOKDEV_GROOM.md:363-368).

PICK = S2 numpy landmark-NRICP) and its blend-proof release blocker closed as an

instrument-reference defect, proven by four controls

(build/3d/cage/blend_fix/BLEND_G4_REFERENCE_FINDING.json, landed 869ba32f). The original

scalp-partition caution is preserved as history below and needs no further observance.

chain has not proven first (prep/reads exempt)"*

(docs/HANDOFF_2026-08-05_ACCOUNT_SWITCH.md L1003-1005). The groom stage proves itself on

CHAR_0001 at the graded keystone ages, then cascades.

A third, softer dependency, named honestly: the per-age COLOUR VALUES (§4.3) come from the

graded keystone plates. The keystones currently read FAIL on every age

(build/3d/characters/CHAR_0001_AGE_KEYSTONES.json /keystones/*/verdict). This spec therefore

carries the colour curve's shape and its ruled words as data, and refuses to invent the numbers.

What is NOT blocked, and is what this wave landed: this spec, the card-atlas bake harness

running on a synthetic strand fixture (GAME:Tools/groom/card_atlas_bake.py), the per-age hair

state data file (GAME:Tools/groom/hair_age_states.json), and their proofs. **None of them

generate a character.**

Superseded §0 text (2026-08-10, preserved verbatim)

## 0. THE UNBLOCK TRIGGER — nothing in this spec executes yet
**This spec is SCAFFOLDING. Every execution step below is BLOCKED until both of the following
land, in this order.**
- BLOCKER 1 — THE CAGE VERDICT. The groom's roots live on the cage's scalp. The cage-source
bake-off is the standing chain's stage-2 gate and the next architecture verdict due
(docs/spine/DECISIONS_PENDING_JOSH.md L4642-4644), and the ratified architecture is ONE BARE
MESH PARTITIONED into anatomical regions, *"each region with its own proportions, physical
values …, record, UV block, and material slot"* (L4630-4633). **The scalp is one of those
regions and the hairline is its boundary.** The groom stage consumes the winning cage's head
partition — scalp region extent, its UV block, and its material slot — and must not presume
which cage wins. The bench deciding it is build/3d/cage/CAGE_BENCH_SPEC.md (READ-ONLY to this
lane).

---

1. THE BUDGET RATIONALE — why this stage is not an extravagance

The teacher's own number sizes the debt. Square Enix's lead character artist Dai Suzuki on *FFVII

Remake* Cloud: his hair *"was an extremely high-priority element and in fact accounted for half of

the total polygon count for the whole model"*

(docs/pipeline_review/AAA_WORKFLOW_CORRESPONDENCE_2026-08-06.md L181-183, citing the GamesRadar

report of Suzuki's remarks). Against the published model numbers — 1997 Cloud ≈ 900 polygons,

*Remake* Cloud ≈ 110,000, *Rebirth* Cloud ≈ 220,000 (dossier L178-180) — that is roughly 55,000

polygons of hair on the model whose appeal is our ruled bar.

The dossier draws the conclusion this spec is built on: the FF7R hair figure *"makes converting the

pivot's 2,558 strand shells to cards a budget-legitimate priority rather than an extravagance, and

makes 73 bald creature rows a larger deficit than their triangle count suggests"* (dossier L233-235).

And its groom verdict is blunter still: *"The groom hole is the AAAAA-blocking one"* (dossier L517).

THE BUDGET LINE ITSELF IS NOT DECLARED HERE. Roster item 5 arms per-asset triangle and material

budgets as gate teeth this same wave (DECISIONS_PENDING_JOSH.md L4715-4717), and the sibling Lane

B owns that declaration (docs/HANDOFF_2026-08-05_ACCOUNT_SWITCH.md L1032-1037). This spec states

its cost by spec-class name onlysteam_deck_minimum / mid_range_pc / high_end_pc /

ultra (_source/01_Tier_1_Foundation/T1_Build_Pipeline_Contracts [ACTIVE v1.0].md §1.7, L166 and

L185-188) — and its obligation is to declare per-LOD counts INTO Lane B's gate, never to mint a

parallel number beside it.

---

2. WHAT ALREADY EXISTS — reused, replaced, and the hole

2.1 REUSED — the card emitter is real and it is the stage's seed

One head carries a real card groom, and its record is specific: 1,488 cards, 262 excluded by the

ear window, 192 whorl-fill cards roofing the crown gap, a scalp cap under them, 29,760 verts /

26,784 tris total (build/3d/characters/CHAR_0001_HEAD_AUTHORED_RECORD.json /geometry/hair and

/geometry/counts/hair). The emitter is build/3d/characters/char_head_author.py L882-1036, and it

already encodes four hard-won corrections that this stage inherits rather than rediscovers:

tangent × world-up, which for a strand running down the back of a head is a horizontal plane, and

*"the check render printed flat plates lying across the skull like shelves."* The binormal is now

tangent × SURFACE NORMAL, sampled at the root and carried along the strand (L890-895).

3.4 mm root lift was *"a visible gap at portrait distance"* (L897-899).

produced *"a flat-topped slab protruding from the crown with a straight top edge and hard vertical

sides"* — a card seen edge-on, standing proud of the skull. Whorl cards now run 1.52× width at

0.34× lift (L942-951).

finding was *"THE HAIR IS A CAP, NOT A HAIRSTYLE"*; the fix was a real parting lane at

PART_ANG = 0.42 rad with two deliberately unequal lobes, plus length variance widened to roughly

±34% *"so a few strands always overshoot the mass"* (L954-963, L1000-1004).

ear the single elven marker; hair that hides it deletes the marker."* The card field carries an

explicit angular exclusion around the ear, and the exclusion is a counted number in the record

(262) rather than an intention (L901-905). §6.3 is where this collides with the hood, and the

collision is designed rather than accidental.

The atlas emitter is equally real. build/3d/characters/char_head_textures.py L442-527 (hair_atlas)

authors six strand clumps across U with real alpha, a normalised root/mid/tip ramp, darkening-only

strand separation, and baked root occlusion. Its own numbers on the landed atlas: `opaque_texels

363,585, clipped_fraction 0.0, value_separation_p90_minus_p10 0.3084`

(CHAR_0001_HEAD_AUTHORED_RECORD.json /textures/hair_atlas_stats). **The clipped-fraction figure

is the stage's most transferable lesson** and §2.3 makes it a gate.

Also reused unchanged: T_HAIR_FLOW (tangent flow so the anisotropic highlight runs *along* the

strand rather than across it), the MI_CHAR_0001_Hair and MI_CHAR_0001_Scalp material slots, and

the importer's masked-material handling — BLEND_MASKED, alpha wired to MP_OPACITY_MASK,

two_sided True, because *"hair cards without an opacity mask are opaque rectangles, which is the

single loudest tell that hair is a texture"* (GAME:Tools/char/import_char_0001_headasm.py

L203-208).

2.2 REPLACED

instead of cards, and converting them is *"the highest-value next step by a wide margin"* —

closing three measured ceilings at once: the LOD floor (LOD2 = LOD3 = 51,492 tris, cause proven by

a topology-free control at 51,282), the texture hole (~19.3% unobserved, concentrated on the back

of the head where strand mass occludes the six views), and the appeal gap against the floor sheet

(docs/pipeline_review/AAAAA_IMPROVEMENT_REGISTER_2026-08-06.md L86, register row 13, scored 2.5).

This is the stage's first execution step.

hard-coded root bands with literal constants. A factory stage needs the style to be data, so

the same emitter can stamp a different hairstyle for a different character or a different age

without a code edit. §3.3 makes the band table a file.

(char_head_textures.py L125). The ruled curve is a function of age (§4), so colour becomes a

looked-up per-age value.

2.3 THE HOLE — everything that is not this one head

*"Hair, everything else: zero. A grep for groom|fur|hair card|xgen|fibermesh across harness/,

build/3d/schema/ and the game repo's Tools/ returns only the CHAR_0001 head's cards and the

rubric's lens list — re-derived at HEAD this sitting. **73 creature rows (62 QUADRUPED + 11

ARBOREAL_PRIMATE) cannot reach the bar as bald shells no matter how good the rig is**"* (dossier

L501-505; register row 47 at AAAAA_IMPROVEMENT_REGISTER_2026-08-06.md L130). This spec is written

so the coat stage is the same stage with a different band table, not a second pipeline.

And the engine end is already built and waiting. Unreal's groom pipeline is Alembic-schema

driven with strand/card/mesh LODs and a Groom Binding Asset, *"which means a creature-coat stage

does not need a new engine capability, only an authoring stage that emits conforming .abc"*

(dossier L519-522).

---

3. THE CARD PIPELINE

Four steps. **The stage is defined so that step 1 can be swapped — for a real strand groomer, for a

generated strand field, for a hand-authored curve set — without touching steps 2 through 4.** That

is what makes it a stage rather than a script.

3.1 Step 1 — STRAND SOURCE

Input to the bake is a strand set: N polylines in scalp-local space, each with a root position,

a root tangent, a per-vertex width taper, and a clump id. Three producers are legal and the stage

does not care which ran:

what the landed head used and what the synthetic fixture in card_atlas_bake.py --self-test

exercises.

row 13 takes for the pivot head's 2,558 shells.

schema (groups for head hair, vellus, beard, eyelashes, eyebrows; width and color attributes;

guide curves flagged for interpolation and simulation — dossier L459-467). **Tool freedom

applies**: *"survey and adopt whatever model/open-source tool does age progression (or any task)

BEST"* (DECISIONS_PENDING_JOSH.md L4439-4442). If a better groomer exists, it feeds this step.

3.2 Step 2 — CARD BAKE

The strand set becomes an atlas plus a card library. This is the step the scaffolding tool in

this wave implements end-to-end on a synthetic fixture.

vertical strip of the atlas. The incumbent uses K = 6 with strips assigned by card index modulo 6

(char_head_author.py L1018-1022 sets strip = (i % 6) / 6.0). The bake generalises this: strip

count is a parameter, strip assignment is by measured clump shape rather than by index, and the

layout is emitted as data so placement can look up which strip a card belongs to.

Alpha is geometry-bearing (§2.1).

is what lets a flat card catch light like a rounded clump instead of a ribbon, and the incumbent

does not have it. Consumed as a normal-derivation input plus a parallax term at LOD0.

runtime rather than baking the jitter in. The incumbent bakes it (clump term,

char_head_textures.py L500-501); moving it to runtime is what lets one atlas serve many

characters.

ramp position, and physics stiffness all read one authoritative gradient instead of each

re-deriving V.

clipped_fraction — the share of opaque texels pinned at 1.0 in any channel — and

value_separation_p90_minus_p10. The history is the reason: silver-white measured 0.3146

clipped against ash-blond's 0.0000, because a ramp whose three basis weights summed to 1.511

was a 1.5× multiply masquerading as an interpolation, and *"the root-to-tip separation the strands

are drawn by vanished, and the render printed a flat white cap"* (char_head_textures.py

L446-458). **A light preset cannot blow out on a normalised ramp, and the gate proves it did not

rather than assuming it.** Threshold: clipped_fraction == 0.0 and

value_separation >= 0.20. Both are asserted by card_atlas_bake.py.

no headroom on a light preset; one that darkens has all the headroom there is. It is also the

truthful model — blond and silver hair are read by the SHADOWS between the strands, not by

highlights on them"* (char_head_textures.py L460-464). Every per-clump and per-strand modulation

in the bake multiplies downward. This matters more here than anywhere else in the factory because

the ruled curve's age-7 end is silver-blonde — the lightest hair the project will ever author.

3.3 Step 3 — CARD PLACEMENT

Placement is where the band table lives, and the band table is the file that makes a hairstyle.

height (u0) rule, travel (du_total), length, width multiplier, lift multiplier, and the atlas

V-window the band samples. The incumbent's five bands become five rows: whorl fill (0.00-0.11,

golden spiral, V-window 0.42-0.92, width ×1.52, lift ×0.34), fringe (0.11-0.34, parted at 0.42

rad with unequal lobes), side/temple sweep (0.34-0.60), crown (0.60-0.92, golden-increment spiral

so *"no radial line of bald scalp can survive between them"*), nape (0.92-1.00) —

char_head_author.py L920-999.

it is counted, never assumed (§2.1). Additional exclusions arrive per character and per equipped

state (§6.3).

show skin-coloured skull, which the check render printed"*

(CHAR_0001_HEAD_AUTHORED_RECORD.json /geometry/hair/scalp_cap_reason). The cap is a dark

light-blocker under the cards on its own material slot (MI_CHAR_0001_Scalp), sitting at a

measured 0.2361 cm standoff at the crown.

partition region with its own UV block (DECISIONS_PENDING_JOSH.md L4630-4633), a placement

expressed in scalp-region UV **transfers to every age morph and every character sharing the cage

topology for free.** This is the single largest reason the groom stage waits for the cage verdict

rather than proceeding around it.

3.4 Step 4 — THE LOD LADDER

LODRepresentationMechanism
0full card fieldevery card, depth map consumed as parallax + derived normal
1reduced card fieldthin the field by clump; widen survivors to hold coverage — never raise lift
2coarse cardsone card per clump type per band; depth map as normal only
3helmet / scalp bakethe card field baked to a fitted shell over the scalp with the silhouette's outer strands preserved as a fringe strip

coverage bought with lift produces a slab in silhouette (§2.1). A thinning pass that widens

survivors keeps the mass; one that lifts them makes a helmet.

Prioritize* as the silhouette lever (dossier L872-875); a card field's equivalent is the

overshooting-strand tail (the ±34% length variance with a 6% long tail,

char_head_author.py L1000-1004). The reduction must keep the outliers and thin the mass, which

is the opposite of what a naive decimator does.

cause proven to be the shell count by a topology-free control at 51,282 (register row 13). Cards

are the fix; the ladder above is where the fix is measured.

---

4. PER-AGE HAIR STATES — the ruled colour curve as data

4.1 The ruling, verbatim

Josh, and this is the operative shape of the curve — recorded against his own reference panels:

HAIR CURVE REVISED BY THE FLOORS THEMSELVES: silver-blonde (fairy realm, age 7)
-> visibly warm sandy-blond BY 11 -> dirty blonde through 14-18; the earlier
crown-holds-silver-through-13 proposal is SUPERSEDED by Joshs own panels.

(docs/spine/DECISIONS_PENDING_JOSH.md L4599-4601, THE AGE-11 AND AGE-14 FLOORS LAND.)

And the end-state, ruled in the same sitting:

THE HAIR END-STATE REFINED (updates the progression ruling): the ladder runs
SILVER-BLONDE (fairy realm child) -> DIRTY BLONDE at age 18 - not golden/clear
gold; the curves end-state is dirty blonde, with the transition still massed in
Adolescence 14-17 per the standing curve unless Josh re-shapes it.

(docs/spine/DECISIONS_PENDING_JOSH.md L4582-4585, JOSH GRADES ITERATION-2 IN FLIGHT.)

The origin ruling both of these update:

The hair as a child the silver white and as progression on the earthly realm turns
to golden blonde as ages to young adult

(docs/spine/DECISIONS_PENDING_JOSH.md L3875-3876, THE HAIR IS A PROGRESSION. Its end-state

"golden blonde" is superseded by L4583-4584's "not golden/clear gold … dirty blonde".)

The canon line under all of it, which does not move: the Elven King's *"hair is silver-white. His

eyes are the same color as the protagonist's but deeper"*

(_source/03_Tier_3_Characters/T3_Core_Characters [ACTIVE v1.0].md L563). The eye colour is the

canon-shared quantity; the hair colour is a curve.

4.2 One residual tension, recorded for the director rather than re-decided

L4584-4585 says the transition is *"still massed in Adolescence 14-17"*. L4599-4601, written later

in the same sitting and explicitly *"REVISED BY THE FLOORS THEMSELVES"*, places **visibly warm

sandy-blond BY 11** — which means the transition has substantially begun before 14. The two readings

cannot both shape the curve.

This spec implements the LATER entry (warm sandy-blond by 11), on the ground that it is the one

that says it is revising, and that it is grounded in Josh's own landed floor panel — the director's

sighted read of that panel records *"the 11 already wears warm sandy-blond hair with the freckle

dusting and full child charm"* (L4595-4597). **This is recorded as a finding for the director, not

as a ruling by this lane.** If it is wrong, the fix is one field in one data file.

4.3 The four keystone states, and what this lane refuses to invent

The keystone ages are ruled: *"anchor ages 7 (the pick), 11, 14, 18 FIRST — built as the LARGEST

jumps first … then interpolate between keystones for the gradual steps. Fill ages derive from graded

keystones, never the reverse"* (DECISIONS_PENDING_JOSH.md L4435-4438). The groom stage carries

exactly those four as declared states and interpolates 8-17 between them.

AgeColour, in the ruling's own wordsRGB root/mid/tipLength + style state
7silver-blonde (fairy realm)MEASURED AND LANDED(0.520,0.523,0.536) / (0.762,0.768,0.786) / (0.940,0.946,0.962)the landed card field: fringe with the 0.42-rad parting, crown spiral, nape, ear window open
11visibly warm sandy-blondAWAITING THE GRADED KEYSTONEawaiting
14dirty blonde (transition through)AWAITING THE GRADED KEYSTONEawaiting
18dirty blonde (the end-state)AWAITING THE GRADED KEYSTONEawaiting

**Three of the four rows read AWAITING and that is the correct state of this stage today, not a

gap in it.** The age-7 values are on disk because the age-7 plate was picked and the atlas that

renders it was measured (char_head_textures.py L88-107;

CHAR_0001_HEAD_AUTHORED_RECORD.json /textures/colour_canon/hair_rgb_root_mid_tip). The other

three keystones currently read FAIL on every axis

(CHAR_0001_AGE_KEYSTONES.json /keystones/11|14|18/verdict), so there is no graded plate to

measure a colour off. Inventing three RGB triples here would be exactly the defect the

proposals-are-HOW-never-WHAT rule exists to prevent.

The mechanism is therefore built and the values are left null. GAME:Tools/groom/hair_age_states.json

carries the four keystones with rgb_root_mid_tip: null on three of them, the ruled colour NAME as

a quoted string with its citation, and a status of AWAITING_GRADED_KEYSTONE. The interpolator in

card_atlas_bake.py refuses loudly when asked for an age whose bracketing keystones are not

both resolved, rather than silently returning grey — and the self-test proves that refusal fires.

ash_blond is explicitly NOT the end-state. It is the retired lane default kept only as the

ladder's comparator (char_head_textures.py L112-124), and the ruling names the end-state as

*"dirty blonde — not golden/clear gold"* (L4583-4584). Anyone reaching for ash_blond as the 18 has

misread the curve.

4.4 What a "state" contains beyond colour

A per-age hair state is not a colour. It carries:

who has fallen into another world and an 18-year-old who has lived eleven years in it do not wear

the same head of hair, and **the physique ladder's own principle applies: the body at every age

shows what the spine's lived history has earned by that chapter** (DECISIONS_PENDING_JOSH.md

L4751-4755, THE TRAINING CLOCK). Hair follows the same clock.

Ages 8-10, 12-13, and 15-17 are derived by interpolation between the bracketing keystones, in

line with the keystone-order ruling. The interpolation is on the data, so it is reproducible and it

costs no generation.

4.5 The child-age register — and this stage does not touch it

For completeness against the standing minor-age ruling: *"MINOR-AGE ASSETS (the child/teen ages

under 18): generated imagery keeps the tasteful-minimal register permanently — not an

over-restriction but a hard line — and loses NOTHING by it, because mesh completeness for every age

comes from the parametric CAGE (complete by construction), never from generated imagery"*

(DECISIONS_PENDING_JOSH.md L4768-4772). **Nothing in the groom stage generates imagery of a

person.** It bakes hair atlases from strand geometry and places cards on a scalp. The register

binds the plate lanes; it is stated here only so the boundary is on the record and no future reader

has to re-derive it.

Related and equally binding on any lane that does author prompts: register language is removed from

prompt text entirely and lives instead in framing defaults and sighted post-checks, because

restriction language *"steals attention from identity and fidelity"* (DECISIONS_PENDING_JOSH.md

L4776-4789). The groom stage writes no prompts.

---

5. PHYSICS AND WIND

5.1 The simulation model

time and flagged in the placement data) becomes a guide chain of bones; the rest interpolate their

transform from the nearest guides. This is the same guide/interpolated split Unreal's Alembic

groom schema already expresses with its guide curve flag (dossier L461-463), which means the

card route and a future strand route share one concept.

authoritative gradient: stiff at the root, loose at the tip, monotonic. One gradient, three

consumers (occlusion, colour ramp, physics), which is what keeps them from disagreeing.

rigid-body count at roughly 1,000 live physics objects across the whole scene (dossier

L488-490). A groom that spends 200 of them on one NPC's hair is a groom that cannot ship in a

crowd. Guide count per LOD is therefore a declared number in the placement data, and it drops

with LOD alongside the card count.

per-clump phase offset from the _ID map so the mass does not move as one board. Amplitude scales

with the length multiplier from the age state (§4.4), so a longer 18-year-old's hair moves more

than a 7-year-old's without a second tuning pass.

5.2 Collision proxies — against the cage, not against the mesh

fitted to the partition regions rather than to a per-character mesh. Because the partition is

shared topology, one proxy set serves every character and every age morph — the same

transfer property that makes placement free (§3.3).

simulation tell there is, and the review ceremony is a motion test precisely because *"a static

groom that reads well can still explode on a run cycle"* (dossier L490-492).

the same arithmetic discipline the creature rig used to place joints — solved and recorded, not

eyeballed (dossier L567-571).

5.3 THE SWAP-GAUNTLET INTERACTION — hair must survive the hood

This is where the groom stage meets the 16-slot equipment law, and it is a named gate rather than a

hope. **The swap gauntlet requires the full equip/unequip cycle in-engine across all 16 slots, their

combinations, and every age state, with garment inner surfaces showing ZERO penetration of visible

body, measured rather than eyeballed** (DECISIONS_PENDING_JOSH.md L4692-4699). Hair is the hardest

case in that gauntlet because it is the only body-adjacent surface that moves.

enumeration (registries/T0_Equip_Slot_Registry [DRAFT v0.1]/Sheet1.csv, SLOT_0001; the ruling

quoted in that row's ruled_by field). The hood is the helmet-slot cloth class — the first

human-realm pickup, *"whose function is concealing the tipped ears and other fairy-elf signs …

the PHYSICAL LAYER of FIRST_CONCEALMENT"* (DECISIONS_PENDING_JOSH.md L3735-3739).

which BANDS of the band table it suppresses and which it leaves. A hood suppresses crown and

nape and leaves the fringe; a full helmet suppresses everything but the fringe and adds a short

under-band. **This is the per-region suppression model the partition architecture already

ratified** (DECISIONS_PENDING_JOSH.md L4630-4633), applied one level down to hair bands. It

costs no extra mesh and it cannot desynchronise from the equipment state, because the equipment

state is what drives it.

DESIGN.** The card field must never cover the ear, because the ear is the elven marker

(§2.1). The hood must cover the ear, because concealing it is the hood's entire gameplay

function (L3735-3739). These do not conflict — they compose: hair leaves the marker visible so

the player and the world can read it, and the hood is what the player equips to hide it. The

groom's ear exclusion is therefore *preserved* under a hood rather than relaxed, and the hood's

own geometry does the concealing. A design that let hair creep over the ear would quietly delete

the mechanic the hood exists to serve.

every age state, imaged per the every-pass law. This rides the existing swap gauntlet rather than

minting a parallel gate.

(DECISIONS_PENDING_JOSH.md L4524-4529), which has no head-slot component, so hair returns to its

unsuppressed state — a testable assertion, not an assumption.

---

6. SCALP AND HAIRLINE — consuming the cage's head partition

boundary against the forehead region IS the hairline. Because the partition is shared topology,

a hairline authored once is the same hairline on every character and every age — and moving it

for a character is a region-boundary edit, which is a data change rather than a re-author.

light-blocker at (0.072, 0.062, 0.048) roughness 0.62, carries used_with_skeletal_mesh: True,

and survived an engine import (GAME:Tools/char/import_char_0001_headasm.py L89-90;

CHAR_0001_HEAD_AUTHORED_RECORD.json /engine_import/materials). The stage fills it; it does not

mint a new one.

material slot come from the cage verdict. Until that lands, the band table's u0 values are

expressed in the incumbent head's own parameterisation and will need re-expressing in the cage's.

**That re-expression is one of the first execution steps (§8), and pretending otherwise would

hide a real cost.**

The incumbent already builds lashes and brows as geometry with real alpha

(char_head_author.py L1187-1249; T_LASH_BCA), on MI_CHAR_0001_LashBrow. They are folded into

the band table as two additional bands rather than kept as a separate script.

---

7. THE REVIEW LAW

No groom claim counts unless it was made under the calibrated light, per roster item 4

(DECISIONS_PENDING_JOSH.md L4712-4714). The W-LOOK standard is being built this same wave by the

sibling lane (docs/HANDOFF_2026-08-05_ACCOUNT_SWITCH.md L1025-1031) and landed as

docs/LOOKDEV_STANDARD.md — THE CALIBRATED LOOKDEV STANDARD — while this spec was being written;

the groom stage consumes it and does not restate it. If that path ever moves, find it by its

DOC_MAP row.

Groom-specific ceremony on top:

and a wind gust — because a static groom that reads well can still explode on a run cycle

(dossier L490-492). A groom reviewed only on a bust is un-reviewed.

the frame that catches the slab defect (§2.1) and the frame the whorl-fill regression was found in.

the sheet beside the atlas, because "silver-white now renders" is a number and was measured as one.

reference for that age, and *"a sheet without the references inline is un-DONE"*

(DECISIONS_PENDING_JOSH.md L4649-4653).

---

8. THE EXECUTION ORDER, THE MOMENT THE TRIGGER CLEARS

1. Read the cage verdict; re-express the band table's root positions in the winning cage's scalp

region UV, and fit the collision proxies to its head/shoulder regions.

2. Convert the pivot head's 2,558 strand shells to cards through the bake — register row 13,

scored 2.5, the highest-value next step by a wide margin.

3. Land the four bake maps (_BCA, _D, _ID, _RT) with the clipping gate armed.

4. Resolve the three AWAITING colour keystones off the graded 11/14/18 plates the moment they

grade, and fill hair_age_states.json. Ages 8-17 then derive with no generation.

5. Build the LOD ladder and declare per-LOD card/guide counts into Lane B's budget gate.

6. Wire physics: guide chains, cage-fitted collision, wind with per-clump phase.

7. Run the swap gauntlet's hair leg — every head-slot item against every age state, penetration

measured, imaged.

8. Run the review ceremony under W-LOOK: motion test, silhouette frame, atlas sheet, side-by-side.

9. Cascade to the creature coat — the same stage with a different band table, closing the 73

bald rows (register row 47).

9. WHAT THIS SPEC DOES NOT CLAIM

the tool refuses to interpolate across them.

ages are ruled, and the band table is the landed head's own.

Generated by harness/site/structure_site.py — the URL path is the repo path. review root