38 KiB
P7 Scene graph: evidence log
Status
Review R1 fixes complete (2026-10-07 12:45; review wp/P7-review-R1.md, session 10:05-12:45). M3 reached
(09:10) and the card complete again with the fixes; every R1 finding is fixed and re-tested on the device (rows
under "Review R1 fixes" below). The fixed device/lgs_sg.js (md5 15235040) is installed on the Frame.
- B1 (blocker) fixed and proven. Root cause measured (it was not the parent's
origin):panel-anchor'sanchor-u/vare the parent's texture uv, which SteamVR maps onto the displayed range (clamped), not fractions of the displayed range.describe()anchors atx / texW,y / texH. A second defect found by the new test is fixed too: copies on a bar popup came out flat (only a middle strip in front of the curved popup); items on popup parents now name the parent's effectivecurvature-origin-idand dropinherit. SG-POPUP (new,native/spike/sg_popup.py, every popup parent, tinted copies, measured inside each frame) PASS 12:40: bar, floating footer, frame menu, "+" bar popup all on the spot (leak 0 .. 0.004), the old anchor's control doubles the tab bar (1.33). SG-POPUP-N (the reviewer's A/B with the daemon, native, laser mode) PASS 12:36: one tab bar in A, B and C, P7's frame-menu items at anchor 0.8867. SG-5 re-run 12:20: recorded as before, one tab bar. - M1 fixed: an absent /
nullspec.windowis the window at rest (SG-WIN2 PASS). Minors: m1 (SG-3 wording), m2 (fail closed without the retire export, SG-FAILCLOSED), m3 (no webpack residue, SG-CHUNK), m4 (any first call revives, SG-REVIVE), m5 (destroy()try/finally), m6 (measured: 0.53 ms per 500 ms tick, 0 pushes at rest, SG-TICK; kept at 500 ms), m7 (detached SIGCONT guard; SG-6 with the daemon PASS 12:37: off 12.42 s, back 0.096 s), m8 (sg.md §7 and the SG-5 row) all done. - Full page suite with the installed file: 17/17 PASS (10:48,
p7_results/suite_r1.jsonl). - Contract
contracts/sg.mdupdated (§0 anchors and popup parents, §1noRetire, §2, §3.1window, §5, §6 fail closed, §7, §8). REQ P10->P7 (no__pycache__on the Frame) done. New REQs: P7->V1 (NATIVE fact 3), P7->C1a (the frame menu's glassd cover is a square-cornered rectangle around the capsule; not P7's placement). - Lessons for whoever reruns: ~20 agents queue for
native.lockandlab.lock;sg_native.pytakesNWAIT(native lock) andLABTRIES(lab-lock retries),MODE=laser(the frame menu is a laser-only surface since P6's R1); never leave a frame reaper of an earlier run alive (one deleted run 2's SG-5 frames before the look).
Before R1 (2026-10-07 09:36): every card build is in and every acceptance test SG-1..SG-6 is PASS or recorded
(SG-5 is a measurement). M3 reached 09:10, M1 reached earlier (contract docs/phase2/contracts/sg.md).
Every card build is in device/lgs_sg.js (in the tree and installed on the Frame, md5 84581c98) and tested live:
depth channel (SG-1; SG-RATE with the real daemon: 0 pushes at rest, max 52/s while moving), transform overrides on
every built-in target with React composition and TTL restore (SG-3, SG-3d, SG-TARGETS, SG-REACT, SG-FRAG with C1a's
20-winbar.json), dim wrappers (SG-4), profiles (SG-PROF), ordering (SG-ORDER), retire hygiene (SG-2), sinking and
slot moves (SG-SINK), window dim / recede (SG-WIN), P10's yaw hook (SG-YAW), the watchdog with the real daemon frozen
(SG-6: off at 12.5 s, back 0.09 s after SIGCONT since P8's 09:26 fix), and the room-dim cell placement for glassd G7
/ P8's dimSlabs (SG-ROOMDIM, added this session). Full suite with the installed file: 13/13 PASS (09:30).
SG-5 measured: a t1 tint does dim everything reparented to Steam's panel in native mode (sg.md §5).
Open requests from P7 (others' files; nothing of P7's waits on them): REQ P7->C3b (CC-A: window.dim alone), REQ
P7->V1 (NATIVE fact 3 states the wrong anchor space; R1 B1). Answered by their owners: P7->Coordinator, P7->P10,
P7->P9, P7->P8 (all three). Later rounds: M4 / M5 are V1 / V2's gates
(G-DEPTH, G-HV) over the context packages' fragments.
How to rerun everything (on the Frame, ~/.local/share/glass-shell): flock -w 1800 /tmp/lgs/native.lock flock -w 240 /tmp/lgs/lab-vr.lock python3 -B native/spike/sg_test.py device/lgs_sg.js all --motion (17 tests; plus sg6, and
popup,tick --lablock without the lab-vr.lock flock), python3 -B native/spike/sg_native.py popup,sg5,sg6|rate OUTDIR (one P10 native-session for the list; NWAIT=3600 to queue longer for native.lock) or ... daemon (under
flock -w 1800 /tmp/lgs/native.lock). On the PC: python native/spike/sg_popup.py (SG-POPUP end to end: runs the
Frame side, fetches, measures and deletes the frames). Headset frames go to /tmp/lgs/p7/hv or /tmp/lgs/p7/pop:
look, then delete on both machines.
Requests
-
REQ P7->P8: please (1) send the spec fields of
contracts/sg.md§3 (profile,reduceMotion,depthMotion("none"while the flagsgDepthAnimis false),window,unitM,surfaces[].dim,surfaces[].slabsOut,popped[].interactive/from/motion/sinkfrom the report's layer fields); (2) mergetheme/sg/*.jsonin name order (supersedesdrops earlier rule ids), keep the rules whoseflagis true in the merged flags (defaults.json</tmp/lgs/flags.json) and call__LGS_SG.overrides({seq, rules})when the set changes and on every (re)inject; (3) in CSS-only mode too, installlgs_sg.jsinvr:systemuiand keep the 1 sping()heartbeat while any sg rule is active or awindowstate is requested (no spec surfaces then), anddestroy()it when neither is; (4) calldestroy()at teardown in CSS-only mode as in native mode. Why: the window-bar row (S10), the tab-bar depth and CC-A's dim are SteamVR transforms that must work without glassd.- P8 (2026-10-07 04:28): done. (1) spec
profile,reduceMotion,depthMotion("none"whilesgDepthAnimis false),window,unitM, surfacedim,mosaic,coverDz,slabsOut, popinteractive(wearer profile only),from,motion,sink; (2)theme/sg/*.jsonmerged withsupersedesand flag filtering,overrides({seq, rules})on change and after every inject; (3) CSS-only install while an override or awindowstate (report, or thesgwindowaction) is active,destroy()when none: verified live 04:27 with--flags tabBarDepth(installed,overridesansweredunsupportedby the tree's Phase 1 copy, removed when the flag dropped); (4) teardown always callsdestroy()(and deletes__LGS_MOTION). Daemon contract §9.
- P8 (2026-10-07 04:28): done. (1) spec
-
REQ P7->P8: in
device/lgs_shell.py(line ~580, the geometry snippet, andSP12_SNIPPET~2905) please find Steam's page by its summon key instead of/page:3/:for (const f of FrameStore.frames) for (const p of f.pages) if (p.m_sSummonOverlayKey === 'valve.steam.gamepadui.main') -> f, pand read r fromp.size.latestMeasuredPanelLocalHeight(notf.activePage). Why: page ids are handed out at run time; on the Frame Steam's page was page 3 and is now page 4 (FrameStore.frames[0].pages: 1 = SteamVR Settings, 2 = controller binding, 4 = Steam), so/page:3/falls back toframes[0].activePage, which is the wrong page whenever SteamVR Settings or the binding UI shows (wrong r, wrong unitM in the spec).lgs_sg.jsdoes it this way since 2026-10-07 08:20 (sg.md §4.2).- P8 (2026-10-07 09:32): done.
GEOM_JSandSP12_SNIPPETfind Steam's page by its summon key inframe.pages(fallbackframes[0].activePageonly when no page has it);r,Hmfrom that page'ssize. Live:frames[0].pages= 1 settings, 2 controller binding, 4 Steam (lh1.5, the others 0); DM-3 15 / 15 against the new daemon (09:32). Contractdaemon.md§4.1.
- P8 (2026-10-07 09:32): done.
-
REQ P7->P8: after a freeze of the daemon itself (SIGSTOP / SIGCONT, NAT freeze regression), please send the systemui heartbeat (
__LGS_SG.ping(), or the spec) first, before the glassd health check, and do not count the daemon's own stall as glassd output silence. Why: SG-6 in a native session (2026-10-07 08:31,sg_native.py sg6): the nodes went at 12.5 s as they should, but after SIGCONT the daemon logged "glassd: no output for 17 s (hung?); restarting it" and re-injected the reporter, and its first systemui call came 2.36 s after SIGCONT (PLAN P7 SG-6 wants the nodes back within 1 s). The page side rebuilds 0.01 s after a ping (SG-6 in-page). A loop-time jump (monotonic gap > 2 × the beat) is a way to tell a frozen daemon from a hung glassd. Rerun 09:16 with the 08:32+ daemon (sha1 1853ffea…): same 2.38 s. Log: SIGCONT at 09:16:23 -> "glassd: no output for 17 s (hung?); restarting it", "watchdog had fired (rebuilt True)", thenspec -> {surfaces: 0} [glassd not ready](which removes the rebuilt nodes again), glassd restarted, real spec at 09:16:26. glassd was not hung: the daemon was the one stopped. (p7_results/sg6n2.jsonl)- P8 (2026-10-07 09:26): done. A
stall_loopnotices our own event-loop gap (> 1.5 s): glassd's silence during it is not held against glassd (no "hung?" restart; its output window restarts), the systemui loop sends__LGS_SG.ping()first when its own iteration gap shows the stall, evaluations that timed out across the stall keep their sockets, and lgs-native retries at once. New selftestfreeze(real glassd--no-feed, no camera; SIGSTOP 15 s): nodes back 0.37 s after SIGCONT, lgs-native 0.7 s, glassd same pid, no restart; journaldaemon: our event loop stalled 14.5 s …,systemui: heartbeat sent first after a 14.5 s stall of ours(09:25:42;wp/P8.mdR1 rows). Contractdaemon.md§1. - P7 (2026-10-07 09:36): confirmed live: SG-6 with the daemon PASS, nodes back 0.09 s after SIGCONT (
p7_results/sg6n3.jsonl).
- P8 (2026-10-07 09:26): done. A
-
REQ P7->Coordinator: PLAN §1.8, second bullet: SG-5 is measured and the inference is wrong. In native mode a
t1tint dims everything reparented to Steam's main panel (glassd's cover, the base mosaic, pops and slabs); only the frame menu, the bar and other popups keep their brightness. Suggested text: "In native mode at1tint dims the whole visible window, popped crops included (SG-5, contracts/sg.md §5); for a window that dims behind a bright popped element use the surfacedim(cover and base wrappers) instead." CC-A then useswindow.dim 0.6alone in both modes. Nothing that ships today relies on either (CC-A gated, S7 off).- Coordinator (2026-10-07, round R2): adopted: §1.8 now states SG-5's measurement, keeps the CSS scrim for in-window modals (
t1would dim the modal's own crop), makes CC-Awindow.dim 0.6alone and names the surfacedimfor a dim behind a bright pop; §0 #7, SG-5's row and R9 updated (PLAN §1.19 R2-4).
- Coordinator (2026-10-07, round R2): adopted: §1.8 now states SG-5's measurement, keeps the CSS scrim for in-window modals (
-
REQ P7->P10:
hv(and anything built onhvgrab): please discard the first frame, or grab twice ~0.5 s apart and keep the second. Why: SG-2 rerun 2026-10-07 09:15: the frame grabbed 0.4 s after a scene-graph push showed Steam's bar clock 3 min older than the frame grabbed 0.8 s later (which had the change);system.HeadsetViewseems to be refreshed only while someone samples it, so a lone grab after a pause returns an old picture.hvmetrics (glass luma, edge profile, doubling) on such a frame would measure the past.- P10 (2026-10-07 session 4): done: every
hvgrabs twice, 0.5 s apart (--grabs N,--gap S), deletes the earlier frame on the Frame at once and measures the last; the metrics JSON saysgrabs. Checked live with a dialog held open (C1c's new--pre), frames looked at and deleted on both machines at once:--grabs 1(10:59) showed another route and no dialog; the default two grabs (11:00) showed the dialog and the current clock. contracts/lab.md §4hvstep 2.
- P10 (2026-10-07 session 4): done: every
-
REQ P7->P9:
contracts/glassd.md§6 says the room-dim placement is "not built":lgs_sg.jsnow placesdimSlabscells (sg.md §3.2: behind the window at z <= -0.05, centred on the rect, 3x its size; SG-ROOMDIM PASS). Please update that line; the cell must span its rect at your texture scale (it does today), else the quad's size changes with it.- P9 (2026-10-07 11:15, maintenance session): done. glassd.md §6 now says the compositor side of the room dim is
built (glassd's pieces, P8's
roomDim/dimSlabspass-through, your placement, SG-ROOMDIM) and states the guarantee you rely on as part of the contract: adimslab's cell spans exactly its rect ×backdropScale(the slab rule of §1.4), with the 8 px feather inside the cell. It also says what is still missing: the report side (P6 has nodimlayer material and reports no top-levelroomDim; nobody asks while C7'sroomDimis off).
- P9 (2026-10-07 11:15, maintenance session): done. glassd.md §6 now says the compositor side of the room dim is
built (glassd's pieces, P8's
-
REQ P7->C3b: for CC-A in native mode use the report's
window {dim: 0.6}alone (data-lgs-window-dim); do not add a surfacedimtoo (it would compound to 0.36). Measured in SG-5 (contracts/sg.md §5). Alsoconcepts/control-center.md§3 row "Power alert … in-place crop +t1tint": thet1tint would dim the alert's own crop as well (PLAN §1.8 already moves alerts to the CSS scrim; C1c's REQ says the same). -
REQ P7->V1:
docs/NATIVE.md, "Scene-graph facts found while buildinglgs_sg.js", fact 3, says "Anchors are relative to the displayed range". That is wrong (review R1 B1, measured 2026-10-07 10:10-10:42):panel-anchor'sanchor-u/anchor-vare the parent's texture uv (cx / texW,cy / texH, as the spike diagram at the top of NATIVE.md already says); SteamVR maps them onto the displayed range and clamps what lies outside to its edge. It is also why the frame menu (tab bar) showed twice in native mode. Please replace the "Anchors are relative to the displayed range" bullet with: "Anchors are texture uv; SteamVR maps them onto the displayed range (clamped). Items on popup parents name the parent's curvature origin (curvature-origin-id, the bar's for a bar popup) and noinherit-from-parent-panel, or a bar-popup copy comes out flat. Verified on the bar, the frame menu and the "+" bar popup (contracts/sg.md §0, SG-POPUP)." -
REQ P7->C1a:
theme/layers/20-shell.json, surfaceframe.menu: in native mode the frame menu's glassd cover shows as a grey rectangle with square corners around the tab-bar capsule (headset frame 2026-10-07 12:36, laser mode,/library/tab/AllGames; P7's copies now sit exactly on Steam's capsule, so this is the cover's own shape). The bar's cover gives"r": "capsule"; the frame menu's has nor. Please give it the capsule radius (or the.lgs-tabcapshape) so the glass edge follows the capsule (no outline-like plate, P-quality bar "edges only from the material").- C1a answer (2026-10-07, R2 fix pass): done:
theme/layers/20-shell.jsongives theframe.menucover"r": "capsule"for both the.lgs-tabcapcapsules and the fallback menu box (the fragment'sownsfields apply whatever its flag, review R2 M2), so the default-flag native mode draws a capsule, never a square slab.
- C1a answer (2026-10-07, R2 fix pass): done:
-
REQ P8->P7: off axis, content of the base pieces next to a pop disappears behind the cover's glass on one side. Found while closing REQ C2a->P8 #17 (native sessions 2026-10-07 13:58 and 14:02, Steam build 11094443,
--flags wp.c2a,wp.p3,wp.c1a --mode pad,/library/homewindowless with the card popped at +15 mm on cell 0; the window lifted and brought 350 mm closer for the look with a lab-only__LGS_SG.overrides({rules: [{id: "p8-lift", target: "window", addMm: [0, 560, 350]}]}), cleared after; frames looked at, then deleted on both machines). Frontal (hv) andhv --offaxis -20: right (glass discs with their art and bezel).hv --offaxis 20: in the base pieces that the card's hole splits off (dump:[0.68125, 0.33287] 1224 x 187and[0.68125, 0.533796] 1224 x 103, anchors off the window's centre) the art is gone behind the disc plates on part of the piece: the disc next to the card (Halo, x 702-882 tex) is a bare grey glass disc, Tomb Raider (1038-1218) loses its left part along a vertical line, Balatro and Robo Recall show glass to the left of the art; the full-width pieces (centred anchors, e.g. row 3[0.5, 0.827778] 1920 x 198) are right in all three views. The same frames show the search capsule's plate (cover) faint behind the full-width band 1 piece frontally. Panel-flag trials through P8's/tmp/lgs/sg-flags.json(removed after):{"base": {"sort-depth-bias": -0.3}, "slab": {…-0.45}, "pop": {…-0.6}}partly helps (the search capsule shows, Balatro and Arizona complete) but the Halo disc stays bare;{"cover": {"no-depth-write": true}}changes nothing. The asymmetry (+20 wrong, -20 right) points at the per-panel draw order between the cover and the off-centre base pieces rather than at their geometry. Please find an ordering (explicitsort-orderper kind, cover < base < slab < pop?) or a piece layout (e.g. base pieces never narrower than the full width except at a pop's row) that keeps every base piece in front of the cover from any side, and add an off-axis case (+20 and -20) to SG-ORDER. Why: a wearer sees the window off axis all the time (any part left or right of the gaze); on Home it removes the art of the discs beside the open card, on window routes the posters beside a popped card (not measured there; the library's off-axis frames at ±20 showed dotted vertical seams at the tab row's pop edges instead, also worth a look). Also seen (C2a's, FYI): the card's rectangular crop takes the neighbour disc's top-right part to +15 mm, so Stardew Valley's disc shows a horizontal cut at the card's bottom edge (y 627 tex).
Decisions taken without the user (PLAN §1.17 rule)
| # | Question | Decision | Flag |
|---|---|---|---|
| D-P7-1 | Tab-bar depth. PLAN §1.7 says +25 mm total; WN §3.3.6 says "Steam's +10 mm plus +15 mm". Live, Steam's frame-menu offset is z 0.01 units = 3.7 mm at r = 1 (not 10 mm) | The rule adds what reaches +25 mm in all (addMm z 21.3) on the frame's left side panel; off until V1 or C1a turns it on |
tabBarDepth (off) |
| D-P7-2 | Depth animation on by default inside native mode | On (native mode is itself gated by the native gate); kill switch depthMotion: "none" |
sgDepthAnim (default true) |
Evidence
| Test | Command | Result | Shots / JSON | Date | Steam build |
|---|---|---|---|---|---|
| SG-1 | sg_test.py device/lgs_sg.js sg1 (on the Frame, under native.lock + lab-vr.lock; all sg_test.py rows likewise), then ... sg1 --motion (P5's motion.js prepended as the daemon does) |
PASS both: 0.002 -> 0.0271 units (+10 mm at r = 1) on depth; max error against the independent closed form 0.0002 mm; 28 / 27 pushes at 16-17 ms (60/s), final push with the exact target at 447 / 444 ms, 0 pushes after; status().motion = motion.js in the second |
native/spike/p7_results/suite_0822.jsonl |
2026-10-07 05:33, 08:22 | 11094443 |
| SG-2 | sg_test.py ... sg2,sg3 --motion --grab /tmp/lgs/p7/hv; rerun ... sg2 --grab holding lab.lock too (no route change by others) |
PASS: 300 add/remove cycles (each state pushed), 5101 sgids created, after the cycles live = dom = 7, after clear() 0 / 0, noRetire 0, nothing queued (both runs). Rendering continues: the tinted test pop and base (green / red) are in place in the headset frames 1.2 s and 3 s after the re-install. The frame grabbed 0.4 s after it was stale (Steam's bar clock in it is 3 min older than in the next frame): hvgrab's first frame after a pause is an old one, not a compositor delay (REQ P7->P10) |
p7_results/r3.jsonl, p7_results/sg2b.jsonl; frames looked at and deleted on both machines |
2026-10-07 08:52, 09:15 | 11094443 |
| SG-3 | same run | PASS: frame-controls child moved 120 mm left (0 -0.04 0 -> -0.3252033 -0.04 0), DumpLaserOverlays size unchanged (0.768 x 0.168) and bOnlyVisibleWithLaser false while the props rule was on (the vsg-node override reached the compositor); restored after overrides({rules: []}); TTL: restored 4.5 s after the last heartbeat (5 s test watchdog). Headset frames: the capsule moved left, same size. Wording (R1 m1): DumpLaserOverlays has no position field for the frame controls (its entry stays byte-identical during the move, reviewer probe SG-3x), so it proves the size only; the move is proven by the DOM translation and the headset look (the reviewer's frames: about 35 px of a 290 px window, about 12 %, which matches 120 mm) |
p7_results/r3.jsonl, suite_0822.jsonl; frames deleted |
2026-10-07 08:52 | 11094443 |
| SG-3d | sg_native.py daemon (CSS only, native.lock; flag tabBarDepth for this step via P10's step flags) |
PASS: the daemon installed lgs_sg.js 1.8 s after the flag and applied tabbar-depth (frame-left z 0 -> 0.0577236); daemon SIGSTOP: restored by the page's watchdog 12.68 s after the last heartbeat; SIGCONT: re-applied 0.05 s later; flag off: __LGS_SG removed and z back to 0 within 1.8 s; /tmp/lgs/flags.json absent afterwards |
p7_results/daemon.jsonl |
2026-10-07 08:26 | 11094443 |
| SG-4 | sg_test.py ... sg4 |
PASS: dim 0.6: cover 1/1 and base 4/4 wrapped at [0.6, 0.6, 0.6], pop and slab not; back to none: no wrapper left (fixed this session: they used to stay as identity tints); animated dim on sheet-in: 46 pushes, final 0.6 |
suite_0822.jsonl |
2026-10-07 08:22 | 11094443 |
| SG-5 | sg_native.py sg5 /tmp/lgs/p7/hv (inside P10's native-session; holds lab.lock + lab-vr.lock; routes /library/tab/AllGames and /library/home, route given back) |
Recorded: a t1 tint is visible in native mode. It dims everything reparented to Steam's panel (cover, base, pops, slabs): window glass 73.8 -> 45.7, text row 108.6 -> 65.7, popped posters 95.0 -> 57.4 (luma, gamma-encoded frames, window.dim 0.35); the brightness of the frame menu, the bar and the room unchanged. Correction (R1 m8 / B1): "frame menu unchanged" holds for its brightness only: those frames also showed the frame menu (tab bar) twice (P7's copy half a capsule left of Steam's), which this luma comparison did not look at; the defect and its fix are SG-POPUP / SG-POPUP-N below, and SG-5 was re-run after the fix (row "SG-5 (R1)"). main.dim 0.35 on top dims cover and base only (popped hero card 38.8 -> 38.8, base posters 69.9 -> 40.7). PLAN §1.8's expectation was wrong: written to contracts/sg.md §5, REQ P7->Coordinator, REQ P7->C3b |
p7_results/sg5n.jsonl; 8 frames looked at and deleted on both machines |
2026-10-07 08:38 | 11094443 |
| SG-6 (page) | sg_test.py ... sg6 (12 s watchdog, heartbeat stopped 15 s) |
PASS: nodes and the frame-controls override gone 12.12 s after the last heartbeat; the first ping rebuilt and pushed within 0.01 s (rebuilt: true), override re-applied |
suite_0822.jsonl |
2026-10-07 08:22 | 11094443 |
| SG-6 (daemon) | sg_native.py sg6 (native-session; lab.lock + lab-vr.lock held; SIGSTOP lgs-shell 15 s), three runs |
Runs 1-2 (08:31, 09:16): nodes off 12.53 / 12.14 s after the last heartbeat, back 2.36 / 2.38 s after SIGCONT (FAIL: the daemon took its own stall for a hung glassd; REQ P7->P8). Run 3 with P8's fix (daemon sha1 2f3bdbf2, 09:35): PASS: nodes off 12.51 s after the last heartbeat, cover pushed again 0.09 s after SIGCONT (rebuilds 1) |
p7_results/sg6n.jsonl, sg6n2.jsonl, sg6n3.jsonl |
2026-10-07 08:31, 09:16, 09:35 | 11094443 |
| SG-PROF | sg_test.py ... prof |
PASS: serialized panel props: default profile every panel interactive: false, no steam-input-appid; wearer: only the pop that asks gets interactive: true, steam-input-appid: 769, can-take-keyboard-focus: true (its slab, the cover and base pieces stay false); back to default clears it; every panel frame-resize-scale-factor: 1 |
suite_0822.jsonl |
2026-10-07 08:22 | 11094443 |
| SG-ORDER | sg_test.py ... order |
PASS: cover 0.001 < base 0.002 < slab 0.0263 < pop 0.0271; a pop below the base floors at 0.002 with its slab at max(zPop - 0.0008, coverDz + 0.0003) = 0.0013; with coverDz -0.027 (K-G6) the slab floor follows (0.0012) |
suite_0822.jsonl |
2026-10-07 08:22 | 11094443 |
| SG-TARGETS | sg_test.py ... targets |
PASS: every built-in target found (window, window-scale, frame-left, frame-controls, grab-handle, resize-corner 1 each, tooltips 4); a no-op rule changes nothing; tabbar-depth composes: frame-left z 0 -> 0.0577236 (21.3 mm at r = 1; with Steam's own 0.01 two levels down, 25.0 mm in all), restored |
suite_0822.jsonl |
2026-10-07 08:22 | 11094443 |
| SG-WIN | sg_test.py ... win |
PASS: windowState({dim: 0.5, recede: 0.05}): t1's parent serialized as tint 0.5, t1 z 0 -> -0.05 (composed), 45 pushes on sheet-in, final exact; back to 1 / 0: both restored, no own buildNode left |
suite_0822.jsonl |
2026-10-07 08:22 | 11094443 |
| SG-YAW | sg_test.py ... yaw |
PASS: test.yaw(20) -> t1 rotation (0.9848, 0, 0.1736, 0); yaw(0) restores at once; TTL 1.5 s restores in 1.54 s |
suite_0822.jsonl |
2026-10-07 08:22 | 11094443 |
| SG-SINK | sg_test.py ... sink |
PASS: from: "cut" appears at 0.0271 (no animation); from: 0.0271 + motion: "snappy" retargets on snappy; a leaving pop sinks on fade to 0.002 in 28 pushes using the slabsOut cell (uv starts 0.5) and is then removed; sink: false goes at once; a slot id moved to another element: old one sinks as b~1 (0.0407 -> 0.002) while the new one rises (0.002 -> 0.0407); live = dom |
p7_results/r2.jsonl |
2026-10-07 08:47 | 11094443 |
| SG-REACT | sg_test.py ... react |
PASS (after a fix to status()): React writes a new frame-controls translation while an override is on: re-composed before any push (-0.1084011 -0.05 0), status().overrides.applied[].base follows; removing the rule leaves React's latest value |
p7_results/react.jsonl |
2026-10-07 09:00 | 11094443 |
| SG-FRAG | sg_test.py ... frag |
PASS: every rule of theme/sg/00-base.json and C1a's 20-winbar.json (flags ignored, supersedes honoured) applies on the live page: tabbar-depth z +0.0577, fc-left x -0.6274 (231.5 mm at S alone, resize: false), grab-up y -0.1 -> +0.157, tips-below 4 tooltips y 0.15 -> -0.15; no errors; every SteamVR transform back to its value after overrides({rules: []}) |
p7_results/frag.jsonl |
2026-10-07 09:05 | 11094443 |
| SG-RATE | sg_native.py rate (native-session, real daemon, lab.lock + lab-vr.lock, /library/tab/AllGames, route given back) |
PASS (card item 1 with the daemon): pushes per second at rest 0,0,0,0,0; while the gamepad moved the focus over posters (6 moves, 17 specs, pops lifting and settling) 0,26,52,47,39 (max 52 ≤ 60), 160 animation frames and 4 final pushes; after 0,0,0,0,0 | p7_results/rate.jsonl |
2026-10-07 09:10 | 11094443 |
| SG-ROOMDIM | sg_test.py ... roomdim and ... roomdim --grab |
PASS: a dimSlabs entry becomes one roomdim panel at z -0.05 (behind the window), centred on its rect (anchor 0.5, 0.5), 3x its size (600 x 400 -> 1800 x 1200 px, 1920 x 1080 -> 8 x 4.5 units), interactive: false, gone when the entry leaves, live = dom. Headset look (the cell replaced by a crop of Steam's own texture so it is visible): the 3x copy fills the view around the window, behind it, curved like the window; the bar and tab bar in front. The real dark cell needs C7's flag roomDim (off) |
p7_results/roomdim.jsonl; frames looked at and deleted |
2026-10-07 09:27 | 11094443 |
| Full suite | sg_test.py device/lgs_sg.js all --motion with the installed file (md5 84581c98) |
13/13 PASS (SG-1, 2, 3, 4, PROF, ORDER, TARGETS, WIN, YAW, SINK, REACT, FRAG, ROOMDIM) | p7_results/suite_final.jsonl |
2026-10-07 09:30 | 11094443 |
Review R1 fixes (2026-10-07, session from 10:05; review wp/P7-review-R1.md)
| Finding | Fix | Test | Command | Result | Shots / JSON | Date | Steam build |
|---|---|---|---|---|---|---|---|
| B1 (blocker) root cause | (diagnosis) | B1-PROBE | scratch probe (not kept): a test instance of lgs_sg.js builds a tinted copy of the frame menu's own displayed texture (cover only) at +z on valve.steam.gamepadui.frame.menu.85100005 (texture 450 x 1200, displayed uv x 0.773..1, y 0.18..0.82, origin [1, 0]); its panel-anchor rewritten per variant; full-size hvgrab per variant; lab.lock + lab-vr.lock + native.lock |
anchor-u 0.5 (the pre-R1 value, the displayed-range centre): copy half a capsule left of Steam's (the reviewer's doubling); 0.0: same place (clamped to the left edge); 1.0: half a capsule right; 0.8867 (= the displayed centre in texture uv): exactly on Steam's capsule, one capsule visible; 0.83 / 0.95: a quarter left / right; anchor-v 0.18 / 0.82: half a panel up / down. Panel origin [1, 0] on the copy moved it further left. So anchor-u/v are the parent's texture uv, mapped onto the displayed range and clamped (not the displayed-range fraction NATIVE fact 3 states); the parent's origin plays no part (the reviewer's hypothesis, which they marked unproven, is not the cause). Fix: describe() anchors at x / texW, y / texH |
frames looked at and deleted on both machines (two sweeps had other agents' theme toggles in them and were redone under the lab lock) | 2026-10-07 10:10-10:20 | 11094443 |
| B1, second defect | items on popup parents name the parent's effective curvature-origin-id (own, or that of the panel a popup is reparented to) and drop curvature: inherit-from-parent-panel |
B1-CURV | the same probe on the "+" bar popup (barpopup.85100001, 450 x 1536, displayed v 0.363..1, reparented to the bar), variants of the copy's panel props |
inherit alone, inherit + origin, nothing: the copy is flat and shows only as a middle strip in front of the curved popup (it crosses it; z-fighting hatching at the crossings). Origin system.systemui::DashboardCurvatureOrigin without inherit: the whole copy in front, every glyph on Steam's (none of Steam's white glyphs visible). The bar and floating footer carry that origin on their own panels; a bar popup inherits the bar's |
frames looked at and deleted | 2026-10-07 10:35-10:38 | 11094443 |
| M1 (major) | update(): an absent or null window is the window at rest (setWindow({}), animated back on sheet-out, one push under reduceMotion); setWindow pushes only when a target changes |
SG-WIN2 | sg_test.py device/lgs_sg.js all --motion (installed file md5 15235040; native.lock + lab-vr.lock) |
PASS: update({window: {dim: 0.5}}) tints t1's parent; the same state again: 0 pushes; update({surfaces: []}) with no window: t1 back to its React values, no own buildNode left, dimTarget 1; {dim: 0.6, recede: 0.05} then window: null: both restored; with reduceMotion the jump back restores in one push. SG-WIN (explicit windowState) still PASS |
p7_results/suite_r1.jsonl |
2026-10-07 10:48 | 11094443 |
| m2 | no retire export: no node of ours is built, scheduler.error "... (fail closed)", the update() summary's error |
SG-FAILCLOSED | same run (opts.noRetire simulates the missing export) |
PASS: a spec with a pop gives items 0, 0 sgids created, root empty, scheduler.retire false with the error; an override still moves the frame controls and clear() restores them |
suite_r1.jsonl |
2026-10-07 10:48 | 11094443 |
| m3 | locate() takes its webpackChunkvrwebui entry out again, with any Symbol('lgs-sg') entries older installs left |
SG-CHUNK | same run (3 more installs) | PASS: length 18 before and after, 0 lgs-sg entries (the reviewer counted 180 -> 187; systemui has since reloaded) |
suite_r1.jsonl |
2026-10-07 10:48 | 11094443 |
| m4 | contact() revives after a watchdog expiry, whatever the first call is (update() builds its own spec) |
SG-REVIVE | same run (5 s test watchdog, no heartbeat, then one call) | PASS: after each expiry (items 0, expired) the first call overrides(), windowState(), test.yaw(0) or ping() brings all 6 items back and the cover is pushed within 0.3 s |
suite_r1.jsonl |
2026-10-07 10:48 | 11094443 |
| m5 | destroy() is try/finally: the interval, timers and the global always go; if clear() failed half way the root is dropped and pushed once |
(code) + every test's cleanup | same run | Every test ends with destroy(); cleanup absent (no __LGS_SG_TEST left). A throwing clear() cannot be provoked from outside; the finally block is the fix |
suite_r1.jsonl |
2026-10-07 10:48 | 11094443 |
| m6 | measured, kept at 500 ms: status().tick reports the housekeeping cost; the relayout check is skipped for a spec without surfaces (CSS-only mode) |
SG-TICK | sg_test.py /tmp/lgs/p7/lgs_sg.js revive,tick --motion --lablock (the draft copy, md5 15235040, the same file as installed) |
PASS: main + bar + frame menu (10 items), 12 ticks at rest: 0.53 ms average per tick (0.1 % of one core), max 1.0 ms, 0 pushes. Kept: Steam re-crops a popup at any time and the copies must follow within 0.5 s, and the crop range is in each panel's buildNode output, which nothing can observe |
console JSON (draft run) | 2026-10-07 10:45 | 11094443 |
| m7 | sg_native.py: stop_daemon() starts a detached guard (setsid sh -c 'sleep 20; kill -CONT pid') before the SIGSTOP, for sg6 and daemon |
SG-6 (daemon) | below (native session) | see the SG-6 (R1) row | |||
| m1, m8 | SG-3 row reworded (size from DumpLaserOverlays, move from the DOM and the headset look); SG-5 row corrected (the frame menu was doubled in those frames); sg.md §7 P8 row closed |
(docs) | done | 2026-10-07 10:45 | |||
| Full suite (R1) | the installed file, md5 15235040 | all | flock native.lock flock lab-vr.lock python3 native/spike/sg_test.py device/lgs_sg.js all --motion |
17/17 PASS: SG-1 (max error 0.0002 mm, 28 pushes, 0 after settle, motion.js), SG-2 (5101 sgids, live = dom = 7, 0 / 0 after clear()), SG-3 (TTL 4.54 s), SG-4, PROF, ORDER, TARGETS, WIN, YAW, SINK, REACT, FRAG, ROOMDIM, WIN2, FAILCLOSED, REVIVE, CHUNK; cleanup absent |
p7_results/suite_r1.jsonl |
2026-10-07 10:48 | 11094443 |
| B1 fix | anchors x / texW, y / texH; items on popup parents name the parent's effective curvature-origin-id, no inherit |
SG-POPUP (new: every popup parent present, CSS-only, tinted copies built by lgs_sg.js itself) |
python native/spike/sg_popup.py (PC; runs sg_test.py device/lgs_sg.js popup --grab /tmp/lgs/p7/pop --lablock on the Frame under native.lock + lab.lock + lab-vr.lock, full-size frames, opens "+" as inventory/bar.md 0.3 does and closes it) |
Final run 12:40: PASS (installed file md5 15235040, the final pass rule): floating footer (anchor 0.4994/0.5, front 1287 px, leak behind 0.002), bar (uv x 0.1608..0.8392, 0.001), frame menu (anchor 0.8867/0.5, 0.0; control with the old anchor 1.333), "+" bar popup (v 0.291..1, anchor 0.5/0.6455, curvature origin from the bar, 0.004; control 0.207); live = dom = 0 after (20 sgids created and retired). Run 11:06, all values, also passes under that rule: floating footer (uv x 0.21..0.79, anchor 0.5/0.5, copy front 2209 px, leak behind 0.001), bar (0.1708..0.8292, front 2575, 0.0), frame menu (x 0.7733..1, y 0.18..0.82, anchor 0.8867/0.5, front 343, 0.0; control with the old anchor 1.353), "+" bar popup (v 0.3633..1, anchor 0.5/0.6816, curvature origin inherited from the bar, front 21019, 0.001; control 0.097); live = dom = 0 after. Earlier runs: 10:54 the same picture (control 1.393 / 0.255), 10:58 the bar copy did not render once (Steam's popups were being re-created at that moment, ids 851000xx -> 925200xx; the next run had it). Look strips of 10:42 and 10:54 looked at: every copy exactly on Steam's panel, one tab bar; the old anchor doubles the tab bar and lifts the bar-popup copy by a quarter; then deleted. The measure was rebuilt twice this session (a frame-to-frame A/B failed because the head pose moved between frames; a "white twin" search was fooled by the neighbouring panel's glyphs) | p7_results/popup.jsonl; frames fetched, measured, deleted on both machines |
2026-10-07 10:54-12:40 | 11094443 |
| B1 / m8 re-check | (SG-5 re-run after the fixes; sg5 now sends window in its own spec, since an absent one is "at rest" after M1) |
SG-5 (R1) | python3 -B native/spike/sg_native.py popup,sg5,sg6 /tmp/lgs/p7/hv with MODE=laser NWAIT=3600 (P10 native-session, lab.lock + lab-vr.lock), the fourth attempt (the first timed out in the native.lock queue; in the second, P7's own frame reaper of the first deleted the SG-5 frames before the look; the third could not get the lab locks to turn native mode on) |
Recorded as before: window.dim 0.35 held through both grabs on both routes (status().window 0.35 at each shot), main.dim wrapped cover and base only (/library/tab/AllGames cover 1/1, base 14/14, pops 0/5, slabs 0/5; /library/home 1/1, 11/11, 0/4, 0/4), restored to 1. Look (8 frames, crops of the tab bar at 2x): one tab-bar capsule in every frame, no copy beside it. Caveat: P6 has made the frame menu a laser-only surface since the review, and Steam's laser mode could not be set (mode=laser via classes (no rt.input)), so the daemon most likely built no frame-menu copy in these frames; the anchor fix itself is covered by SG-POPUP (the same code, on the same parent) |
p7_results/sg5n_r1.out; frames looked at and deleted on both machines |
2026-10-07 12:20 | 11094443 |
| B1 (native, with the daemon) | the fixed file in the daemon's own instance (status().version f14d16cf2e+a9fdddd1dd; dump carries curv) |
SG-POPUP-N (the reviewer's A/B) | MODE=laser NWAIT=3600 LABTRIES=5 python3 -B native/spike/sg_native.py popup,sg6 /tmp/lgs/p7/hv (P10 native-session; lab.lock + lab-vr.lock; laser mode through rt.test.input.set, so P6 reports the laser-only frame menu; /library/tab/AllGames, route given back) |
PASS: the daemon's spec had main, bar, floating footer and frame.menu.92520005; P7's frame-menu cover and base at anchor (0.886667, 0.5) = the displayed centre in texture uv, 102 x 768 px. Frames: A (as built) one tab-bar capsule, crisp, icons single; B (frame-menu surface taken out of the spec, 0 items) Steam's capsule alone at the same place; C (restored, 2 items) as A. Before the fix A and C showed two capsules half a capsule apart (review B1). Seen in passing (not P7's placement): the frame menu's glassd cover is a grey rectangle with square corners around the capsule (REQ P7->C1a) |
p7_results/native_r1b.out; 3 frames looked at and deleted on both machines |
2026-10-07 12:36 | 11094443 |
| m7 + SG-6 (R1) | stop_daemon(): detached SIGCONT guard (20 s) before the SIGSTOP |
SG-6 (daemon) | same native session | PASS: nodes off 12.42 s after the last heartbeat (17 items before), cover pushed again 0.096 s after SIGCONT (rebuilds 1, expiries 1); the guard's own SIGCONT at 20 s is a no-op |
p7_results/native_r1b.out |
2026-10-07 12:37 | 11094443 |