Files

29 KiB
Raw Permalink Blame History

P3 Interaction runtime: evidence log

Package card: PLAN §2.3 "P3 Interaction runtime". Contract: docs/phase2/contracts/interaction.md. Review: docs/phase2/wp/P3-review-R1.md.

Status

  • Maintenance session 4 (2026-10-07 13:40-14:30 EDT, platform maintainer): REQ Coordinator->P3 (PLAN R2-8) done. P3-D4 is decided: §1.13's 0.8 s / 0.2 s are delays, tipQuick stays off (S29) and stays a test switch, and IN-7 is scored by the amended criterion (PLAN §2.3 P3). contracts/interaction.md §0, §4.1 and §8 already cite R2-8 (no "pending"); REQ P3->V1 no longer asks for tipQuick. IN-7 by R2-8: the run the coordinator cited (s3k, 08:17, quiet device) meets every clause on both inputs (table below). Re-runs this session on the busy shared device (runner /tmp/lgs/p3/p3run.py, now also scoring R2-8, pass_r2_8_default): laser passes every clause in 3 of 4 runs (materialize start 836-839 ms; one at 846 ms); the pad path fails only "materialize starts 800 ± 40 ms" (3 valid runs): each time the samples stop for about 100 ms at the moment the tooltip shows (last sample at 790-797 ms, the next at 888-915 ms), so its first visible sample is 896-915 ms although the label timing puts the start at about 840 ms. Laser shows the same stall shorter (30-40 ms). With wp.c1a, wp.c2b, c2bToggle off for the step it is unchanged, so it is not another area's module. An isolated probe without the runner's per-frame getComputedStyle sampling (Evidence "S4 probe") shows no frame gap when a tooltip appears, except once per window: the first show creates the window's tip node and style (30.7 ms synchronous, a 29-38 ms frame gap), later shows cost 1.3-1.8 ms with normal frames. Measured directly (the moment data-state turns in, which starts the materialize, against the button's vgp_onfocus, one clock): 802, 803, 802 ms for the pad path, inside 800 ± 40. So the pad clause's miss in the runner is its own sampling cost while the thick-glass layer starts, not a late tooltip; the one-off first-show hitch is recorded, not changed (paid once per window and runtime install). IN-7 by R2-8: PASS (s3k on both inputs; this session laser on its own samples, pad by the direct start time and its own samples for every other clause; bar wrapper and m_mapTooltips empty in every run).
  • Review R1 fixes done (session 3, 2026-10-07 07:32 to 08:25, Frame clock EDT, Steam build 11094443). All six findings are handled; see "Review R1" below. Every card test was re-run live on the final code: runs s3k to s3n, 08:17 to 08:22, after the last sync at 08:16 and loaded with --reload.
  • M1 reached (2026-10-07). Contract written; modules input, attention, states, tooltip (device/rt/04-input.js to 07-tooltip.js) load through P1's runtime behind flag wp.p3.
  • M3 reached, with one recorded deviation (re-verified 2026-10-07 08:22 on the final code). Every Build of the card is in.
    • Pass in both input modes: IN-1 to IN-6, IN-8, IN-9, and the bar part of IN-7.
    • Also pass: the extras IN-3b, IN-10 to IN-13, the leak test and the lazy-token test.
    • IN-7 as written failed with the default timing (deviation P3-D4; decided in round R2, PLAN R2-8: the criterion is amended, see the maintenance note above). Measured on computed opacity, the label is at 0.07 at 900 ms, and the capsule is still at 1.0 250 ms after leaving. The cause: PLAN §1.13, D2 §11 and MO make 0.8 s and 0.2 s delays, which come before a 250 ms materialize and a 350 ms dematerialize.
    • With flag tipQuick (off by default), IN-7 passes as written on both inputs.
  • What is live (behind wp.p3):
    • input-mode signals on every popup, with rt.input (mode, vrMode, state(), onChange, stub);
    • the global 80 ms laser dwell, and rt.attend / rt.attention;
    • the light spot --hx/--hy, and the classes lgs-pressed, lgs-focus-in, lgs-ring-check and lgs-focus-disabled;
    • in-window tooltips (P4 thick glass, P5 materialize), the bar ShowTooltip 0.8 s wrapper, and flag tipQuick;
    • rt.sound through Steam's bus, and rt.haptic as a dry run (S17).
  • Remaining:
    • (a) Done: the coordinator amended the card (R2-8); tipQuick stays off.
    • (b) V1 decides whether wp.p3 is on by default (REQ below).
    • (c) M5 (V2 acceptance). After that, delete the prototype device/proto/input_mode.js (PLAN §6).
    • Wearer-only items stay outside the card's tests: SteamVR's own grip mode toggle (onChange reason vr-mode / vr-overlay-focus, wired from source as in IM §2.1), and how a haptic feels. Haptics stay disarmed (S17).
  • How to re-run the tests:
    • Runner: <scratch>/p3/p3run.py, where scratch is this workflow's scratchpad. A copy lives at /tmp/lgs/p3/p3run.py on the Frame until a reboot.
    • What a run does: it runs inside one lab.Lock step and turns wp.p3 on through rt.test.flags.push. It drops haptic, affordance and sound playback calls (IM §9). It drives the laser with CDP Input.dispatchMouseEvent on the popup's own target. At the end it restores the pointer to (1400, 900), the pad source, the route and the interceptions.
    • Command: sh run.sh NAME [--reload] [--media reduce] TESTS…, run from the scratch folder. It waits up to 240 s for the lab lock.
    • Tests: in1 in2 in3 in3x in3b in4 in5 in6 in7 in8 in10 in11 in12 in13 idx selset shot. in9 and leak run outside the flag block.
    • Output: each out_NAME.json carries t0 / t1 (Frame clock) and the Steam build.
    • Offline checks: node --expose-gc <scratch>/p3fix/offline.js. It covers fail-closed installs of all four modules, the chunk record, weak marks and lazy tokens.

Requests

  • REQ P3->Coordinator: please rule on IN-7 (P3-D4).
    • Coordinator (2026-10-07, round R2): your proposal adopted with tolerances from your own measurements: §1.13's delays stand; IN-7 now passes on "nothing before 760 ms; materialize starts 800 ± 40 ms; label ≥ 0.9 by 1100 ms; leave starts 200 ± 40 ms; label 0 by 460 ms, node hidden by 640 ms; a return within 200 ms keeps ≥ 0.9; m_mapTooltips empty" (PLAN §2.3 P3); C9 follows it; tipQuick stays off (S29) (PLAN §1.19 R2-8). Follow-up REQ Coordinator->P3 in wp/coordinator.md.
    • The conflict. The card says "None at 500 ms; the label at 900 ms; gone ≤ 250 ms after leaving". PLAN §1.13 ("0.8 s in and 0.2 s out") and D2 §11 ("After 0.8 s, materialize 250 ms | 0.2 s, dematerialize 350 ms", MO §4.17, Apple's WWDC24 sample) make both numbers delays. Under those, the label reaches 0.9 at about 1045 ms, and the capsule is gone about 565 ms after leaving (measured, Evidence IN-7).
    • Proposal. Amend the IN-7 pass criterion to: "none at 500 ms; the materialize starts 800 ± 40 ms after attention; label ≥ 0.9 by 1080 ms; the leave starts 200 ± 40 ms after attention ends; the node is hidden by 600 ms; m_mapTooltips empty after cleanup". C4a's C9 (concepts/controls.md §18.2) repeats the card's numbers and needs the same amendment.
    • If you keep the card instead. Flag tipQuick already meets it (all checks pass, both inputs), and V1 can turn it on in defaults.json. The cost is laser jitter. A laser that leaves and returns within about 180 ms makes the capsule dip to about 0.6 instead of staying solid. If it returns later, the tooltip is gone and waits the full 0.55 s again.
  • REQ P3->C4a: FYI, no change in your files is requested. C9's timing ("its aria-label at 900 ms; gone ≤ 250 ms after leaving") inherits P3-D4. With the default timing it fails exactly as P3's IN-7 does, and with --flags wp.p3,tipQuick it passes. Please score C9 per the coordinator's ruling on REQ P3->Coordinator.
  • REQ P3->V1: please set "wp.p3": true in device/defaults.json once you agree.
    • P3 is at M3 (evidence below). The R1 review's leak (F1) is fixed and verified live.
    • Every T2/T3 consumer (attention in deps: C1a More circle and frozen target, C2a ramp, tooltips) stays blocked while wp.p3 is off. With it off, CSS keeps the documented fallbacks (contracts/interaction.md §1.1).
    • (2026-10-07, session 4) No tipQuick: PLAN R2-8 keeps it off (S29); only "wp.p3": true is asked.
  • REQ P3->P4: a --lgs-shadow-5mm token (CTL §11: in-window tooltips sit at owner + 5 mm as a CSS shadow; by your rule y .4 px/mm, blur 1.2 px/mm: 0 2px 6px rgb(0 0 0 / .30)). 07-tooltip.js already reads var(--lgs-shadow-5mm, 0 2px 6px rgb(0 0 0 / .30)). P4 (2026-10-07): done: --lgs-shadow-5mm: 0 2px 6px rgb(0 0 0 / .30) in theme/00-tokens.nowrap.css (live) and the kit; contracts/tokens.md §1.7.

Decisions taken without the user (PLAN §1.17 rule)

# Question Decision (safe default) Where
P3-D1 (superseded by P3-D4, review R1 F2) IN-7 "gone ≤ 250 ms" vs PLAN §1.13 + MO Was: IN-7 scored on the start of the leave. Withdrawn: IN-7 is now scored on computed opacity, and the conflict is recorded as a deviation (P3-D4) —
P3-D2 Lab tests by other packages use L.hover, which sends untrusted events and cannot set :hover Attention accepts untrusted hover by tracking the last mouseover target (trusted events keep the stricter :hover check). No change for real laser input 05-attention.js, contract §2
P3-D3 Tooltip look source P4's thick material and edge hook plus P5's lgs-mat-* keyframes (instead of private keyframes), zero-specificity so C3a/C1a can restyle 07-tooltip.js
P3-D4 IN-7 ("label at 900 ms; gone ≤ 250 ms after leaving") contradicts PLAN §1.13 / D2 §11 / MO §4.17 (0.8 s and 0.2 s are delays before a 250 ms materialize and a 350 ms dematerialize) Default: PLAN §1 timing, because §1 decides conflicts and it matches Apple's sample. IN-7 as written is recorded as FAIL (deviation), and a coordinator ruling is requested. Flag tipQuick (off) implements the card's literal timing with tokens only: materialize starts at 550 ms (fully in at 800 ms), no leave grace, and the dematerialize runs on --lgs-d-reduce (180 ms). A return to the same owner during the leave brings the tooltip straight back (data-resume) 07-tooltip.js, contract §0, §4.1
P3-D5 When does a laser leave start? At the attended element's own mouseout (to an element outside it). It used to start at the next element's mouseover, which Steam's handlers held back by about 70 ms (measured: mouseout at 1273 ms, mouseover at 1342 ms). leaveMs: 0 now leaves in the same task instead of on a 0 ms timer, which Steam's D-pad work delayed by about 100 ms 05-attention.js, contract §2.2

New strings

None. Tooltip text always comes from the owner (data-lgs-tip-text, aria-label, title). The test strings used by the runner ("Glass test tooltip", "Pad test tooltip", "Options", "Leak test", "Now tip") exist only inside the locked test step.

Review R1 (session 3)

# Finding Fix Evidence (live rows below)
F1 major Detached-DOM leak: states.st.touched and attention.st.marked Both sets were removed. In 04, the sticky-marks registry is now weak (WeakMap element → classes, plus a WeakRef set used only for sweeps, pruned of collected elements and closed documents). The last pointer target, the spot host and the tooltip's last owner are WeakRefs. Removal sweeps every live window (classes, [style*="--hx"], .lgs-tip) and calls marks.sweep. The live leak test found a second leak, also fixed: if a feed attention was re-entered by the laser, it kept source: 'feed', so the laser's leave never ended it. That held the element and even showed its tooltip after the pointer had left. The input that enters last now owns the attention leak PASS (runs s3g 08:05 and s3k 08:17): control collected, and with P3 on the node is collected in all three variants. The reviewer's own harness (08:06) went from alive to collected. Offline: an 8 MB marked element is collected under --expose-gc
F2 major IN-7 scored on DOM state, reported PASS The runner now samples the computed opacity of the capsule and the label every frame. The leave sampler is armed in the page before the pointer moves, so there is no CDP round trip in the measurement. IN-7 is scored as written: default FAIL (deviation P3-D4), tipQuick PASS. M3 is qualified in the Status IN-7 row (s3k 08:18; also s3h 08:07)
F3 minor input not fail-closed; same order in 05/06/07 Each module sets st.remove right after live = st, before its first subscription. In 04, every Steam subscription registers its undo the moment it is made, both in undo and with P1's tracked rt.cleanup (run once). All public members go through rt.expose, with plain assignment only as a fallback Offline (p3fix/offline.js): input throwing at each of 6 points (with and without P1's scope) leaves 0 subscriptions and 0 API members. attention, states and tooltip throwing late leave 0 listeners. The reviewer's failclosed.js reads 0 in all four cases, and node now exits (no leaked interval)
F4 minor [Symbol(lgs-p3-input)] left in webpackChunksteamui Steam's require is taken once per page load and cached. The record is spliced out at once, and records left by earlier builds are cleaned IN-9 (s3k): webpackChunksteamui.length 221 → 221 → 221, records of ours 0 (s3f: 177 → 177 → 177; s3h: 190 → 190 → 190)
F5 minor Logged times did not match the artifacts; the shot predated the final code Rows below are replaced with session-3 runs. Each time comes from the runner's own t0/t1 stamp (Frame clock). The live shot was re-taken with the final code (08:20) and the comparison rebuilt. Key numbers are copied into this log. The session-2 rows were removed. Their true file times (per the review) were r2a 05:15, r2b 05:16, r2c 05:20, r2d 05:21, r2e 05:24, r3a 05:29 and r3b 05:30, not the 05:27 to 06:07 logged this table; shots/p2_p3_tooltip_live.png, shots/p2_cmp_p3_tooltip.png (08:21)
F6 minor %{Token} selectors resolved once at install rt.input.lazySel(list) is P3-internal and shared by 05/06/07. It resolves on use, drops unresolved parts, and retries at most once a second until every token resolves. Coverage: the ring, disabled, spot, press and spot-host selectors, rt.attend / rt.tooltip.register string targets, and dwellSelector. New diagnostics: rt.states.selectors(). New test hook: rt.input.test.index(fake), which affects P3 only idx and selset PASS (s3k; idx also s3f, s3h)
extra IN-3 failed once in s3a (07:48): Steam swapped the card's child under a still pointer, and Chromium sent the new mouseover 422 ms late When the 80 ms dwell timer finds the old element no longer hovered, the card now under the laser (the document's :hover chain) inherits the dwell in3x 3/3 three times (s3b, s3h, s3k)

Evidence

Common conditions. Steam build 11094443 and the final code, synced at 08:16 and loaded with --reload in s3k. Every row is one locked step (lab.Lock) with wp.p3 on through rt.test.flags.push, popped at the end. Steam's haptic and affordance calls and PlayAudioURL were intercepted and dropped, so nothing played and nothing pulsed; P3's own haptic calls were 0 in every run. Each step sent the pointer to (1400, 900), restored the pad source (padSource: 1) and restored the starting route. Outputs: <scratch>/p3/out_<run>.json, with times from the runner's t0–t1 (Frame clock, EDT). The main run is s3k: sh run.sh s3k --reload in9 leak idx selset in1 in2 in3x in3b in4 in5 in6 in7 in8 in10 in11 in12 in13, 08:17:29–08:19:19.

Test Run, time Command Result Artifacts
offline 08:16 node --check device/rt/0[4-7]-*.js; python glass.py check-theme; node --expose-gc p3fix/offline.js; reviewer's p3rev/failclosed.js PASS. The bundler reports 45 files; fail-closed, chunk, weak-mark and lazy-token checks as in "Review R1" p3fix/offline_out.json
IN-1 input classes on every popup s3k in1: pad source first, CDP mouseMoved ×5 on main, then L.pad('down') PASS. All 9 live popups (VR, VRKeyboard, VRNotificationToasts, bar, barpopup, tooltip, volumelevel, floatingfooter, frame.menu) went pad → laser on the move and → pad on the press. onChange fired pad→laser and laser→pad (reason source) out_s3k.json
IN-2 input stub s3m 08:20:34 sh run.sh s3m in2: from the live gamepad source; rt.input.stub('laser', {vrMode: 'laser'}), restore(), then P1's rt.test.input.set('laser') / set(null) PASS. Our classes went pad → laser → pad on all 9 popups at each step. NavigationSource.Value, IsInGamepadNav, the getter and both objects' own properties stayed identical. SteamVR's own mode was laser at the time (set outside this step), so the restored state is pad / laser. s3k failed only on the runner's old hard-coded gamepad; the runner now compares with the start state out_s3m.json
IN-3 dwell s3k (also s3b 07:54 and s3h 08:07) in3x: in3 three times on /library/home (CDP hold on card 2, then a sweep over 5 cards at about 45 ms per card) PASS 3/3: .lgs-dwell at 80.5, 85.5 and 80.5 ms after the entering mouseover; 0 dwells in every sweep. Earlier runs gave 85.1 / 80.3 / 80.4 (s3b) and 83.6 / 80.3 / 80.3 (s3h) out_s3k.json
IN-3b lab hover (untrusted) s3k in3b PASS: lgs-dwell and lgs-attend-80 set, then lgs-attend-300; current is the button; events enter,dwell,step300,leave; all cleared after the unhover out_s3k.json
IN-4 gamepad press s3k in4 on /zoo/buttons (rt.states.test.feed, then one real L.pad('down') with a passive spy) PASS: lgs-pressed on A down, cleared 0 ms after the up, safety clear at 413 ms; B, D-pad and repeats ignored; preventDefault / stopPropagation never called; the real D-pad event (button 10) arrived un-prevented and set nothing out_s3k.json
IN-5 light spot s3k in5 on /zoo/buttons PASS: --hx/--hy 25/50 %, 50/25 % and 75/75 %, written 1, 3 and 3 ms after each move; 0 writes while idle; 0 elements with --hx after the switch to pad out_s3k.json
IN-6 first focus frame s3k in6 (P5's lgs-focus-in keyframe on .lgs-focus-in.gpfocus::after, 3 × D-pad) PASS 3/3: lgs-focus-in set in the vgp_onfocus task, before Steam's .gpfocus, and both present at the next frame; ::after 0.60 at t0 and 1.00 at 700 ms; class gone by 700 ms out_s3k.json
IN-7 tooltips (opacity-scored) s3k in7. Laser: CDP hover on an icon-only 60 px test owner on /zoo/buttons; the leave goes to an empty page area inside the window, timed from the owner's own mouseout. Pad: a zoo button registered with force, timed from the real vgp_onfocus / vgp_onblur. Both run once in the default mode and once with tipQuick. Bar: CDP hover on the bar's "Launch Program" button Default: FAIL as written (P3-D4). "None at 500 ms" passes; "label at 900 ms" fails (0.066 laser, 0.077 pad); "gone ≤ 250 ms" fails (capsule 1.0, label 0.88 / 0.77). tipQuick: PASS as written on laser and pad. Bar: PASS: wrapper on, the entry has unDelayMS 800 and is not finished at 500 ms, finished at 900 ms; m_mapTooltips 0 after the pointer left. Timeline numbers in the next table out_s3k.json (also s3b–s3e 07:54–08:01, s3h 08:07)
S4 IN-7 by PLAN R2-8 2026-10-07 13:45, 14:06, 14:12, 14:21 (×2) EDT cd /tmp/lgs/p3 && python3 -B p3run.py in7 in12 (runner now also scores R2-8: metrics.r2_8, pass_r2_8_default); the last run also with --flags wp.c1a=false,wp.c2b=false,c2bToggle=false Busy shared device (other agents' gates and native sessions between the runs). Laser (start / label 0.9 / leave / label 0 / hidden, ms): 846 / 1053 / 210 / 397 / 564 (start 6 ms over), 839 / 1091 / 208 / 396 / 563, 836 / 1054 / 209 / 396 / 552, 838 / 1054 / 212 / 399 / 555: every other clause and "no dip on return" pass in all runs. Pad (14:06, 14:21, 14:22): first visible sample 896, 915, 906 ms after a 98-103 ms frame gap that starts at 790-800 ms (the tooltip's show); label 0.9 at 1046-1053, leave 208-247, label 0 395-409, hidden 560-575: all pass but the start clause (one run's leave 247 ms, 7 ms over). Not counted: the 13:45 pad part (no tooltip and no gamepad attention events at all, like that run's in12: gamepad focus was not in the main window then) and the 14:12 run, which overlapped P8's own dm2 selftest (native mode started mid-run). Bar wrapper checks pass in every run; in12 errored twice on the zoo's button list (route left elsewhere by other agents), not counted /tmp/lgs/p3/out_s4*.json (RAM)
S4 pad materialize start, direct 2026-10-07 14:41 EDT glass.py js "<probe3>" --flags wp.p3 --mode pad on /zoo/buttons: a tooltip registered on a button (force); three times: focus away 0.7 s, then L.gpTakeEl(button) with a vgp_onfocus listener (SharedJSContext clock), 1.3 s, then rt.tooltip.state().shown[].shownAt (same clock: the moment the node turns in and its lgs-mat-glass-in starts) 802, 803, 802 ms after the focus event: R2-8's "materialize starts 800 ± 40 ms" met on the pad path console output
S4 probe: frames at the show 2026-10-07 14:33, 14:36 EDT glass.py js "<probe>" --flags wp.p3 on /zoo/buttons: rt.tooltip.show(btn) four times with rAF timing, plus a control mutation; then --mode pad with real gamepad attention (L.gpTakeEl) and a 1.3 s rAF gap log, with and without a registered tooltip, twice each show() synchronous cost 30.7 ms the first time in the window (node and style created), then 1.3-1.8 ms; frames after it 6-11 ms. Under attention: with a tooltip, gaps 38 ms at 799 ms and 29 ms at 857 ms on the first show, none on the second; without one, no gap (one unrelated 148 ms gap at 1183 ms). The runner's 100 ms pad gap is therefore not the tooltip's own cost; the first-show 30 ms is console output
IN-7 look s3l 08:20 shot: rt.tooltip.show() on a 60 px test circle labelled "Options", over a game poster on /library/tab/AllGames; lab.capture('main') Thick-glass capsule 114 × 48 CSS px, 20 px Semibold, 12 px under its owner, no outline, E3 arc on the top edge; the poster shows through as blurred colour. It matches the mockup's "Options" capsule over a poster in size, weight, placement and material. The live capsule is lighter over this bright poster: worst label contrast 6.1 : 1 against the mockup's 8.3 : 1, both above 4.5 : 1 (P-39). Material density is P4's thick-glass token shots/p2_p3_tooltip_live.png, shots/p2_cmp_p3_tooltip.png
IN-8 sounds (+ haptic dry run) s3k in8 on /library/home PASS: activate → 21 (DefaultOk), and Steam's bus requested /sounds/deck_ui_default_activation.wav (intercepted); hover refused (null), 0 requests; 0 sound requests during a 5-card laser sweep; haptic plan {effect 3, available true, armed false, fired false}, 0 calls of ours out_s3k.json
IN-9 removal s3k in9: counts, wp.p3 push, counts, pop, counts, sweep of every node of every popup PASS: navigationSource 10 → 11 → 10; vrNavigationType 1 → 2 → 1; MobX observers 16 → 17 → 16; popup created / destroyed 6 / 3 unchanged (P1's single pair); webpackChunksteamui 221 → 221 → 221 with 0 records of ours. Sweep: no P3 class, attribute, --hx/--hy, .lgs-tip or #lgs-tip-style; no P3 member on __LGS_RT; ShowTooltip is the prototype's again out_s3k.json (s3f, s3h: same)
leak (F1) s3k (also s3g 08:05) leak. A node with an 8 MB payload is touched by the laser spot, dwell, an rt.attend registration, its tooltip, a synthetic A press (non-bubbling, our node only) and a pad focus / attention feed under the input stub. Then: (a) the pointer leaves the window and the page drops the node; (b) the node is dropped under a still pointer, then one move; (c) dropped with no further input. WeakRef, then CDP HeapProfiler.collectGarbage ×2 PASS: control (P3 off) collected; P3 on: (a), (b) and (c) collected, (c) even before any further input; marks.count() 0 afterwards. The first run (s3f 08:03) had (a) alive, which found the attention source bug fixed in "Review R1" F1 out_s3k.json, out_s3g.json, out_s3f.json; reviewer harness p3rev/out_s3_rev.json (08:06: withP3: collected)
lazy tokens (F6) s3k idx: rt.states.selectors(); a fresh lazySel('%{FocusRing}, .p3t-x') under rt.input.test.index(fake index without FocusRing), then the real index again. selset: area setters with an unresolved token PASS: every states selector resolved; with the stand-in index, .p3t-x and resolved: false; still cached within 1 s; after 1.1 s ._1wPplsegQqCoe06wXPhzKT, .p3t-x and resolved: true. selset: an unresolved spotSelector / pressSelector falls back to the default list; a mixed one keeps its resolved parts out_s3k.json
IN-10 ring tag (CTL §4.5) s3k in10 on /settings/notifications (44 check circles): L.gpTakeEl on a .DialogCheckbox, then on another Focusable PASS: focus in the checkbox, and its %{FocusRing} (40 px) carries lgs-ring-check; after the move no node keeps the class out_s3k.json
IN-11 disabled + focus (CTL §4.7) s3k in11 on /zoo/buttons PASS: exactly the focused "Can't click me" button carries lgs-focus-disabled (P4's --lgs-dis = 1); removed after the move out_s3k.json
IN-12 attention, gamepad paths s3k in12 on /zoo/buttons, focus by L.gpTakeEl only PASS: padImmediate fires enter, dwell, step400, step800 at once; a timed registration fires at 302 / 601 ms with source: 'pad'; away and back within 120 ms keeps it (hysteresis), while the leaveMs 0 one leaves and re-enters; leaving for 450 ms fires one leave and clears every class; current is the focused button; feed → enter:feed, dwell, leave; a padNow + above tooltip is in within 80 ms, above its owner, gone 650 ms after the blur out_s3k.json
IN-13 tooltip motion s3k; s3n 08:22:20 (--media reduce) in13; sh run.sh s3n --media reduce in13 PASS: P5's lgs-mat-glass-in / lgs-mat-content-in at 250 ms and -out at 350 ms; nothing running 1.3 s after the leave; node hidden (P-52). Reduce Motion: all four at 180 ms, the glass animates opacity only, and the label keyframes are empty out_s3k.json, out_s3n.json
perf (idle cost) 08:20:44–08:22:04 python glass.py perf main --route /library/tab/AllGames --flags wp.p3, then the same without the flag Theme on: 53.4 fps with P3, 57.2 fps without; median 11.1 ms in both; 23 long frames in both. Theme off moved between 74.9 and 73.0 fps in the same runs. The difference is inside run-to-run noise. P3 does nothing per frame while the user is not pointing (listeners only; the spot writes at most once per frame while the laser moves, IN-5). The theme-on fps is lower than session 2's 71–77, for all three runs alike, so the theme has grown since. A first attempt at 08:11 ran during P10's native session and was discarded console output

IN-7 timelines (s3k, ms from attention start or end, computed opacity sampled every frame; "label" = capsule opacity × label opacity):

Mode, input Glass visible Label 0.5 Label 0.9 At 900 ms (label) Leave starts Label gone Capsule gone Node hidden At 250 ms after leave (capsule / label)
default, laser 821 982 1048 0.066 233 420 588 588 1.0 / 0.88
default, pad 816 983 1049 0.077 223 416 568 581 1.0 / 0.77
tipQuick, laser 564 730 796 1.0 ≤ 106 (first sample) 106 190 190 hidden
tipQuick, pad 577 738 803 1.0 ≤ 83 (first sample) 210 223 223 hidden
  • Repeatability. s3h (08:07) gave the same picture: default laser 819 / 978 / 1045 / 0.068 / 213 / 400 / 566; default pad 818 / 986 / 1041 / 0.082 / 223 / 410 / 565; tipQuick capsule gone at 186 ms (laser) and 209 ms (pad).
  • Laser jitter (the pointer leaves for about 100 ms and returns):
    • Default: the tooltip never leaves. State is in throughout and the capsule stays at 1.0 (re-entry mouseover at 200 ms in s3k, 189 ms in s3h).
    • tipQuick: when the laser returns inside the 180 ms leave (176 ms in s3h), the capsule dips to 0.59 and is back at 1.0 75 ms after the return (data-resume). When it returns later (202 ms in s3k), the tooltip is already gone and needs the full 0.55 s again. That is the cost of having no grace, and why the default keeps PLAN §1's 0.2 s.
  • Earlier IN-7 runs found two timing faults, both fixed (P3-D5):
    • s3c (07:57): the laser leave started at 274 ms. The mouseout came at 1273 ms, but the new element's mouseover came only at 1342 ms.
    • s3c: tipQuick on the pad was gone at 294 ms, because the 0 ms leave timer ran after Steam's D-pad work.