Skip to content

the-hide-mask-boundary contract is red on main for peds-nurse-kevin, and neither recent asset landing caused it #744

Description

@gidich

the-hide-mask-boundary-is-not-a-sawtooth is red on main, on one actor, and neither of the two most
recent asset landings caused it.

Measured 2026-08-28 on main at 50a1e993

(2) COUNTERWEIGHT: the mask ring is not smoothed by decimation
    mpfb-peds-nurse-kevin: mask ring 40 verts < floor 42
(3) COUNTERWEIGHT: the mask still covers what it covered
    mpfb-peds-nurse-kevin: mask Y extent 538mm < 98% of 571mm

2 of 3 clauses fail. Only mpfb-peds-nurse-kevin is named by either.

Attribution, measured rather than assumed

Kevin's openclinxr_hidden_upper primitive, read with NodeIO at three trees:

tree verts Y extent
f82e1cc2 — before #739 1719 538 mm
de57fc4d#739's teeth retreat 1719 538 mm
main, after #740's fleet re-materialisation 1719 538 mm

Identical at all three. Neither #739 nor #740 moved it. #739 translated teeth meshes on z and
could not touch a body primitive's vertex count; #740 re-materialised the fleet and did not change
this one.

So the 571 mm reference and the 42-vertex floor were written against a kevin that no longer exists,
and something before f82e1cc2 changed it. The contract has been red since then without anyone
noticing.

Two readings, and I have not distinguished them

  • A real regression: kevin's mask genuinely stopped covering what it covered, and the floors are
    right. No garment in this pipeline can have a long sleeve, because the body has no forearm #199 swapped kevin's scrub for the longer toigo_fisherman_sweater, and the file's own
    ## FIXED (#389) block records re-measuring the rim after that — so a garment swap moving the mask
    is a live mechanism on this actor specifically.
  • A stale floor: MIN_MASK_RING_VERTS and the 571 mm reference were pinned to an older bake and
    never re-derived. The same FIXED block says kevin's rim measured 42 verts then and 40 now, which is
    a two-vertex drift rather than a collapse.

The first measurement I would take: walk kevin's GLB back through the commits that touched it and
find where 571 became 538. That is a bisect over a tracked binary and it is cheap.

Why this matters beyond one actor

The file's own header says fixing the mask ring "changes nothing a learner can see" — the mask is
discarded, not drawn. So this red is not an appearance defect. It is a gate that has been failing
silently on main, and a red gate nobody reads is the state this repo has already recorded costing it
a full cycle elsewhere.

Not measured

Which commit moved it. Whether the other ten actors are near their own floors. Whether 571 mm was
ever right for kevin after #199's garment swap.

factory_step: instrument

unblocks: clothing_consume

No new RED — the defect is already red on main

tools/openclinxr/evidence/the-hide-mask-boundary-is-not-a-sawtooth.test.ts fails clauses (2) and
(3) today. What was missing was the counterweight, added in a04c6519:

Probe: lowering kevin's floors to 40 and 0.5380 — the exact cheat — turns (2) and (3) green and reds
(4). Reverted.

The file also carries one unrelated it.fails that is not this card's business. The done_when
below is run: only for that reason; do not flip it.

The first measurement, and it is not a guess

Bisect kevin's GLB across the commits that touched it between 2026-08-14 and f82e1cc2, measuring
hidden_upper verts and Y extent at each, and find where 42 became 40 and 571 mm became 538 mm.
git show <commit>:<path> > <scratch> extracts a tracked binary at a commit; the NodeIO pattern is
in the card above.

THE CAUSE IS NOT KNOWN TO ME BEYOND THOSE NUMBERS. My three-commit attribution only rules out
#739 and #740. Do not take a hypothesis of mine as fact.

If the floors turn out to be stale

Say so and stop. That is a successful finding and does not fail the slice. Do not lower them
silently — clause (4) refuses that, and a justified re-measurement needs the commit that changed the
asset named alongside it.

Report these

If any proof cannot pass as written, OR passes trivially against the ambient range, OR asserts the
opposite direction from the defect, say so in your first report, at the moment you find it.

If satisfying a clause would make the product visibly worse, say so and satisfy it anyway. Note that
this file's own header records that fixing the mask ring "changes nothing a learner can see" — this
is a silently-failing gate, not an appearance defect, so do not expect a visible change.

Report any out-of-scope wrongness you saw and are not fixing, naming the object and what is wrong.

Write your report with the section headers IN-SCOPE:, OUT-OF-SCOPE:, CLAIM: and NOT TESTED:
in that colon form.

done_when

  • run:pnpm exec vitest run tools/openclinxr/evidence/the-hide-mask-boundary-is-not-a-sawtooth.test.ts
  • live:tools/openclinxr/evidence/the-hide-mask-boundary-is-not-a-sawtooth.test.ts
  • exists:tools/openclinxr/evidence/mask-extent-bisect.json

The live: rule is here because briefFromIssue refuses a run: on a file containing it.fails
vitest counts an expected-fail as a pass, so run: alone cannot tell done from not-started. That
file carries ONE unrelated it.fails from an earlier card. Flipping it is therefore in scope for
this slice ONLY to the extent of making it honest: if that clause's defect is fixed, flip it and
append a FIXED block; if it is not, SAY SO IN YOUR FIRST REPORT and stop, because the alternative is
flipping a plant whose defect still stands.

mask-extent-bisect.json records the bisect: one row per commit that touched kevin's GLB between
2026-08-14 and f82e1cc2, carrying the commit sha, the hidden_upper vertex count and the Y extent
in metres, so the commit where 42 became 40 and 0.5706 became 0.538 is named rather than inferred.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions