Verify 02: opening group (clean-room)

ETS27 prototype, round 2 · 2026-10-13 · scope: prototype/index.html, prototype/shared.css and the fork's hand-off into prototype/mind.html

Stance: clean-room. This pass used the finding list, the fixer's claims and skipped items, the brief and the design direction. It did not open the fixer's report (studio/fix-02-opening.md) or the critique files. Every verdict below comes from fresh pixels and measurements taken in this pass or from the code, never from the fixer's own screenshots (r2-*).

Verdict

Score: 78 / 100 for the opening group as shipped now.

Owner decisions 1, 2 and 3 are in place and correct: exact fork copy, accessible names, keyboard contract, dated lockup and a single raspberry accent with no retired ember left in any page. The realm-loading and fallback engineering is solid. Self-hosted three.js matches the pinned hashes, the DOM never waits for the realm, and stalls, failed imports, context loss and moderately slow GPUs all land on the CSS realm with the phase clock carried over. Draws are capped at 30 fps after the intro settles.

Two things keep this from a high score:

  1. Decision 5 (the head) is partial. The skull defects are gone: no dark sockets, streaks, drips or teeth. The minimum luminance on the head rose from 117 to 164, and no pixel is under 150. But the eye hollows are oversized, and the 0.60 shading floor flattens their interior into a uniform grey plateau. They read as flat grey patches more than soft mannequin dishes.
  2. The slow-device probe fails open on the slowest devices. Those are the phones this probe exists for.

Smaller issues:

Method

Owner decisions

# Decision Status Evidence
1 Fork copy, tags, link names, tab order, / and printable keys Landed DOM (v2-opening-1440x900.png): eyebrow // two ways in; labels Open the map / Ask the mind (Unbounded 400, 28 px, no transform); explainers Everything laid out: agenda, lineup, venue, tickets. / Say what you came for. Only that appears.; hint // you can switch any time.; tags [ browse ] / [ ask ] (aria-hidden, opacity 0 at rest, 1 on hover/focus, always 1 under hover: none, see v2-opening-390x844-touch.png); aria-labels exactly per 3.2 (index.html 236, 242). Tab order: skip link, map, mind, toggle. / and printable keys verified (see claims). The explainer uses the colon form from the decision and the brief; the design direction 3.2 still shows an em dash.
2 Lockup dates // MAY 3-6, 2027 // AUSTIN, TX Landed Static markup index.html 226-227 and CONFIG; rendered // MAY 3-6, 2027 // AUSTIN, TX in every capture, including no-JS (v2-opening-nojs-1440x900.png, -390x844).
3 Single accent --accent #C1115A; no #e8a06a in text, links or marks Landed --accent resolves to #c1115a; focus ring rgb(193,17,90) 2px solid, offset 4 px; door B top hairline is raspberry pixels at y 700-701 on hover and focus. Grep of index/mind/standard for e8a06a, 232,160,106, ember, --ets-signal: no hits in any page. --ets-signal is deleted and no var() in any page is undefined. The token --ets-sun: #e8a06a remains in shared.css line 27 but nothing uses it (nit N8).
4 Persona unnamed, sentence case, no exclamation marks, no film quotes Landed (opening) The only persona line on the fork is the nudge > pick a door, or just start typing.. No ! in CONFIG copy. Grep for film lines and other names: none.
5 Smooth matte mannequin cranium, shallow soft hollows, white fog dissolve Partial See F1 below. Dissolve and darkness are fixed; the hollow shape and shading are not yet a mannequin read.
6 No grey head disc through content on mind.html Landed Offline demo at 1440 and 390: #head opacity 0 from the first answer, 24 px glyph in the top bar (v2-opening-decision6-mind-first-answer-1440x900.png, -390x844.png). No disc behind the speaker grid.
7 Escape link on every component, visible sample markers Landed Five answers per width: speaker_grid [ open the map: lineup ] to standard.html#lineup, session_list to #panel-d1, venue to #venue, tickets to #register, partners to #partners (all anchors exist in standard.html; panel ids are generated and hash-routed). Markers: 8 speakers · sample lineup, day 1 · monday may 3 · sample, partners · sample, venue · to be announced. Chips carry no escape link, which is reasonable.

Fixer claims

Claim Status Evidence
Head rebuilt (decision 5), white fogged dissolve, haze below the hollows, floor 0.60, camera lift 0.40, probe clean Partial Code matches the claim (index.html 535-551, 510-511, 617, 715, 299). The luminance probe is clean: settled crop min 164 vs round-1 117; pixels under 150: 0 vs 5,840; longest dark run under the cut: 0. Still and phone frames: same min 164, zero under 150. But the histogram spikes at luminance 165-166 (8,096 px in the settled crop, 4,192 in the still, 1,812 on the phone), which is the 0.60 floor after distance fog. The hollow interiors are clamped flat. Each hollow spans from the bridge almost to the silhouette, and the turned side shows a notch at hollow height (v2-opening-head-1440.png, v2-opening-head-still-1440.png).
Fork per decision 1: copy, tags, aria, outlines, door B hairline, focus ring, active scale, Space, / and printable keys to mind.html#compose with ets27.draft, modifiers/IME/editable/Tab ignored, shortcuts toggle in localStorage, 10 s nudge Fixed Rest outline 1px solid rgba(11,11,12,.5), measured 3.45-3.53:1 against the adjacent background. Hover and focus: ink border plus 1 px inset, explainer to ink, tag visible (v2-opening-hover-mind-1440.png, -hover-map-, -focus-1440x900.png, -focus-map-). / opens /mind.html#compose, composer focused and empty, 0 turns. w gives value w, caret 1, 0 turns, draft removed. Shift+W gives W. Ctrl/Meta/Alt+K, Meta+Shift+K, Escape, F2, Enter and Space on the body, ArrowDown, Shift, synthetic isComposing and defaultPrevented events, and typing in an input: no navigation, scrollY 0. Tab moves focus normally. Space on door A opens /standard.html; Enter on door B opens mind.html with the composer focused. Toggle reads [ shortcuts on ] with an updated aria-label, stores off, survives a reload and makes keys inert (v2-opening-shortcuts-off-1440.png). Nudge appears at t 10.7 s and only once per session (v2-opening-nudge-1440.png). Caveats: N3 (nudge overflow) and N5 (burst typing).
Lockup per decision 2, tag--caps Fixed See decision 2. .tag defaults to text-transform: none; only the lockup spans use tag--caps.
Palette: white bg, fog tones, hairline #e2e2df, --line-ui, muted #64635f AA everywhere, accent-ink and accent-tint, --ets-signal deleted, ember renamed --ets-sun with aliases to raspberry, peach ring gone, h1 300 / h2 400 / h3 500, lowercase tags, title, theme-color Fixed, AA sub-claim partial Tokens read live: --bg #ffffff, --line #e2e2df, --line-ui rgba(11,11,12,.5), --muted #64635f, --accent-ink #8f0c43, --accent-tint #fbe9f0, --ets-signal empty, --ets-ember resolves to #c1115a. Headings 300/400/500. Title ETS27 \| free_your_mind [OPEN]; theme-color #ffffff. Muted text against the darkest adjacent cloud measures 4.47:1 (door A explainer, 1440x900) and 4.48:1 (eyebrow, 1280x720). That is a hair under 4.5, and the clouds drift (N6).
Realm loading: self-hosted three.js 0.180.0 (sha384 verified), modulepreload, no addons, 1.5 s DOM timer, 2.5 s import race, quick-reveal, late import ignored Fixed sha384 of vendor/three.module.js = wyxAlyAV…NRoZKv; vendor/three.core.js = r1q8Si7x…n+8m8. Both equal the pinned values; REVISION 180; the import map has only three. Requests: same-origin plus Google Fonts only. Six-second stall on three.module.js: quick-reveal is-live at 1.5 s, CSS realm by 2.5 s with doors visible at 3.2 s, still CSS at 8 s after the module arrived (v2-opening-stall-1440.png). Aborted three.core.js: CSS realm by 1.2 s, settled by 5.6 s.
Slow devices and housekeeping: failIfMajorPerformanceCaveat, 1.5 s probe stepping to 0.55 then CSS, dispose on context loss, rAF-debounced resize, 30 fps once settled, phase clock carried Partial Works: --disable-gpu lands on the CSS realm. 70 ms frames give a probe median of 74.7 ms, scale 0.55 at about 1.4 s, then the CSS realm at about 2.5 s (v2-opening-slow-device-1440.png). Context loss at t 2.03 gives the CSS realm at 2.43 with the clock carried (settled at 5.6), with no page errors (v2-opening-context-lost-1440.png). Resizing 1440 → 900 → 390 → 1440 reframes each time. Draw rate is 359/s during the intro and 87/s once settled (3 draws per frame). Fails: see N1. A device that fits fewer than 4 frames in the window passes the probe.
Intro: skip from 0.4 s, any key/pointer/wheel/touch or focus in the fork ends the intro and jumps the realm clock, doors never focusable while invisible Fixed [ skip ] is visible at t 0.79 and hidden once settled (v2-opening-skip-visible-1440.png). A click at t 0.60 adds intro-done; the realm clock jumps to 5.83 and doors are at opacity 1 (v2-opening-after-skip-1440.png). Tab at t 0.51 lands on the skip link with the doors already at opacity 1; the next Tab focuses door A at opacity 1 with no filter, focus visible (v2-opening-focus-early-1440.png). The skip button click also settles.
No-JS CSS realm; neutral CSS realm and head; phone fork stacked 12 px apart, min 64 px; lookYTall -0.50; lockup follows head-bottom; definite stage height; short wide viewports fit without scroll Partial No-JS shows the CSS realm, the dated lockup and plain door links, with the toggle hidden (v2-opening-nojs-*). The CSS realm and head are neutral grey (v2-opening-nowebgl-1440x900.png). At 390x844, the doors are 358 x 101.6 px with a 12 px gap, map above mind, head-bottom 369 px with the mark at 370 px, and no scroll. No scroll at settle at 1024x680, 1280x720, 1366x768, 1440x900, 1920x1080, 768x1024, 414x896, 430x932 and 360x780. Breaks: the nudge overflows 1024x680, 1280x720 and 1366x768 after 10 s (N3), and 375x667 and 360x640 overflow at settle (N4).

Skipped items: the socket glow, lockup hierarchy, poster still, SVG wordmark, return-visitor intro and the --ets-ember deletion were checked against the code and are absent as the fixer stated. Two notes:

Blocker and major findings

Finding Status Evidence
F1 Head reads as a skull; sockets oversized and low Partial Not a skull any more: no dark sockets, drips or teeth; luminance min 164; dissolve is white fog. The sockets are no longer low (bottom at local y 0.11, above the fade), but they are still oversized and flat. Socket ellipsoid radii x 0.14 with ssub k 0.16 (index.html 545), and the 0.60 floor (617) clamps the interior to one value. See the claim row for the histogram.
F2 Fork copy, tags, link names and keys (decision 1) Fixed See decision 1 and the fork claim.
F3 Lockup lacks the dates (decision 2) Fixed See decision 2.
F4 Retired ember colours five hover, reveal and thinking states Fixed No e8a06a, 232,160,106 or ember use in any page. The door hover ring is ink; the mind.html halo is rgba(255,243,232,.35) (realm glow only). --ets-signal deleted.
F10 Fork copy, link names, keys, ets27.draft hand-off, Space, Tab Fixed The // 01 index is removed rather than hidden. Space and Tab are handled as specified. The draft travels in sessionStorage and is removed on read.
F11 Lockup dates line Fixed Real text in static markup; read by the accessibility tree as text.
F12 Keyboard focus can land on invisible doors Fixed See the intro claim: focus never lands on a door at opacity 0.
F13 Muted grey fails AA Partial #64635f gives 5.8:1 on the corners. Over the darkest drifting cloud it measures 4.47-4.52:1 on the door explainers and the hint, and 4.48:1 on the eyebrow at 1280x720.
F19 Fork stays blank while the three.js CDN stalls Fixed See the realm-loading claim.
F20 Decisions 1 and 2, and no auto-send on hand-off Fixed The draft is never sent (0 turns). mind.html?demo=1&q=tickets fills the composer, strips q from the URL, sends nothing and makes 0 POST requests.

Minor and nit findings, status in brief

New findings from this pass

N1 (major). The frame-time probe fails open on the slowest devices.

The probe only falls back when it has at least 4 samples (index.html 937). Its window starts on the first loop call (919), and that call includes shader compilation. So a device whose first frame takes more than 1.5 s, or whose frames take more than about 375 ms, ends the window with 0-3 samples and passes.

Evidence:

Emulation Probe result What happened
Steady 400 ms frames 3 samples, median 408 ms Passes; stays WebGL at scale 1; realm clock at 1.05 s after 9.4 s of wall time
1.8 s first frame, then 120 ms frames 0 samples Passes; stays WebGL at about 8 fps
Forced SwiftShader — Stays WebGL; realm clock at 0.57 s after 16.8 s; a click on a door took 6.5 s to navigate (v2-opening-swiftshader-1440.png shows a white realm)

Only real devices whose browsers report a major performance caveat are caught, as --disable-gpu was.

Fix:

N3 (minor). The 10 s nudge overflows common laptop viewports.

.nudge is absolutely positioned below the hint (index.html 162). Its bottom edge lands at:

Viewport Nudge bottom
1024x680 684
1280x720 727
1366x768 771

In each case the line is clipped and the page becomes scrollable after 10 s (v2-opening-vp-1280x720-nudge.png, v2-opening-vp-1024x680-nudge.png). It fits at 1440x900, but only with 1 px to spare.

Fix: show the nudge in place of or inside the hint row, or reserve its line inside the stage's spare bottom row, then re-measure scrollHeight after it appears.

N4 (minor). Small phones overflow.

Viewport Overflow
375x667 (iPhone SE class) +14 px
360x640 +29 px

The crown of the head sits under the corner tags, and the hint and toggle fall below the fold (v2-opening-vp-375x667.png, v2-opening-vp-360x640.png).

Fix: below about 700 px tall, shrink the head (raise lookYTall, increase halfH), tighten the row gaps and let the spare bottom row collapse to zero.

N5 (minor). Fast typing keeps only the first character.

Typing who at 40 ms per key on the fork lands w in the composer. The other keys are lost during navigation and before mind.html focuses #q after the fixture and health awaits. The storyboard (§2) promises "their words".

Fix: buffer keys on the fork for about 300-400 ms (until a pause) before navigating, then append the buffer. Separately, have mind.html focus #q synchronously at the top of its script and append any keydown that arrives before focus.

N6 (minor). Muted text is borderline AA over drifting clouds.

The minimum measured is 4.47:1 (see F13).

Fix: darken --muted slightly (about #5c5b57), or put a faint white veil behind the fork and hint band.

N7 (nit). The no-GPU path logs two three.js console.error lines before the CSS realm takes over.

Fix: probe with a bare canvas.getContext('webgl2', {failIfMajorPerformanceCaveat: true}) before constructing the renderer.

N8 (nit). Dead tokens.

--ets-sun: #e8a06a, --ets-ember and --ets-glow are used by no page. The realm uses its own shader constants and the CSS realm's own rgba halo. Delete them so the retired colour cannot creep back.

N9 (nit). [ shortcuts off ] shows on touch-only devices, where there are no shortcuts (v2-opening-390x844-touch.png).

Fix: hide it under (hover: none) and (pointer: coarse) until a keydown is seen.

N10 (nit, cross-group). Copy mismatch on mind.html. The unavailable-state door card (mind.html 684) uses the em-dash explainer; the fork uses the colon form from the decision. Align them.

N11 (nit). Small direction deviations:

Head: what would finish decision 5

The probe proves the darkness problem is solved; the remaining issue is shape and gradation.

  1. Lower the floor (0.60 → about 0.50-0.52) and add an up-facing hemisphere or bounce term, so the lower half of each dish lifts toward 200 and the interior keeps a gradient instead of a plateau.
  2. Narrow the hollows. Socket radius x 0.14 → about 0.11, centre x 0.27 → about 0.25, ssub k 0.16 → about 0.10. They should stop well inside the silhouette.
  3. Check the turned profile at yaw ±9°: the temple cutter plus socket currently leaves a notch on the turned side.
  4. Re-run the same probe. Expect no histogram spike within 2 levels of the floor, and keep zero pixels under 150 and zero dark runs under the cut.

Regressions against round 1

Compared with opening-1440x900.png, opening-390x844.png, opening-mid-intro-1440.png, opening-no-webgl-1440.png, opening-reduced-motion-1440.png and c2v-opening-head-1440.png:

Console and network

Not verified

Captures (prototype/shots/, all new, prefix v2-opening-)