From 6c15ed9dda6f9024be063c6000963e429e43f85a Mon Sep 17 00:00:00 2001 From: byrongamatos Date: Sun, 6 Sep 2026 07:21:01 +0200 Subject: [PATCH] =?UTF-8?q?fix(h3d-carve-16):=20Toby=20r1=20=E2=80=94=20F1?= =?UTF-8?q?=20ternary,=20F2=20dead=20DI,=20F3=20naming=20guard,=20F4=20smo?= =?UTF-8?q?ke=20honesty?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit F1 (HIGH): Fix truncated-ternary in _bgLoadSettings — setZoomSmoothing and setTiltSmoothing were closing before the ternary, storing the boolean _bgHasStored(...) result instead of the camera-smoothing value. Move closing ) to after : _cameraSmoothing. Add kill tests for both setters asserting the argument contains '?'. F2 (MED): Remove 13 dead DI params (5 lines) from createSceneInit signature and matching entries from screen.js wiring: - FRET_WIRE_HIT_OP / HIT_INTENSITY / HIT_DECAY (renderer.js only) - updateStringHighlights (declared null, never called) - getIsDestroyed (screen.js lifecycle flag, not scene-init's concern) - setChartEnv/PrevT, setBcBeatIdx/NoteIdx/ChordIdx (BC chart-sync: per-frame) - setTintR/G/B (BC tint: per-frame, managed outside scene-init) DI count repinned: 183 → 178. F3 (LOW): Add naming-correspondence guard — for every getX in the DI, assert a matching setX exists unless getX is in READ_ONLY (6 pinned stable-ref getters that scene-init never writes). F4 (honesty): Rename smoke test — was 'setters called before null-T throw' (wrong: null canvas returns before T is accessed, no setter is called). Now: 'factory construction + null-canvas early guard'. Remove dead di stub entries (FRET_WIRE_HIT_*, getIsDestroyed, updateStringHighlights) that no longer exist in the DI signature. Suite: 427/427 (h3d glob). Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_014uZ169yfoFYArXz962g7KW --- plugins/highway_3d/screen.js | 11 ---- plugins/highway_3d/src/scene-init.js | 13 ++--- tests/js/highway_3d_scene_init.test.js | 80 ++++++++++++++++++++++++-- 3 files changed, 78 insertions(+), 26 deletions(-) diff --git a/plugins/highway_3d/screen.js b/plugins/highway_3d/screen.js index f4a72c7..3108c78 100644 --- a/plugins/highway_3d/screen.js +++ b/plugins/highway_3d/screen.js @@ -4254,7 +4254,6 @@ import { createSceneInit } from './src/scene-init.js'; // h3d-carve-16 SPARK_N: _SPARK_N, _ND_TTL_MS, _ND_TIME_EPS, FRET_WIRE_HIT_HEX, FRET_WIRE_HIT_EMISSIVE, FRET_WIRE_IDLE_HEX, FRET_WIRE_IDLE_OP, - FRET_WIRE_HIT_OP, FRET_WIRE_HIT_INTENSITY, FRET_WIRE_HIT_DECAY, ACCENT_RIM_BASE_EMISSIVE, ACCENT_HALO_OP_NEAR, ACCENT_HALO_OP_MID, ACCENT_HALO_OP_FAR, ACCENT_HALO_XY_INNER, ACCENT_HALO_XY_MID, ACCENT_HALO_XY_OUTER, @@ -4277,7 +4276,6 @@ import { createSceneInit } from './src/scene-init.js'; // h3d-carve-16 _darkenInt, _lightenInt, _h3dHexToInt, boardSpanX, _bcCreateController, - updateStringHighlights: null, canvasSize, applySize, fxInit, _disposeOpenStringPitchSprites, @@ -4303,7 +4301,6 @@ import { createSceneInit } from './src/scene-init.js'; // h3d-carve-16 getVibrancyProjOp: () => _vibrancyProjOp, getBgReactiveOptOut: () => _bgReactiveOptOut, getVenueSceneOverride: () => _venueSceneOverride, - getIsDestroyed: () => _destroyed, getVibrancy: () => vibrancy, // ── Getter+setter pairs ────────────────────────────────────────── getWrap: () => wrap, setWrap: (v) => { wrap = v; }, @@ -4347,11 +4344,6 @@ import { createSceneInit } from './src/scene-init.js'; // h3d-carve-16 getStringLines: () => stringLines, setStringLines: (v) => { stringLines = v; }, getProjMeshArr: () => projMeshArr, setProjMeshArr: (v) => { projMeshArr = v; }, getBcCtrl: () => bcCtrl, setBcCtrl: (v) => { bcCtrl = v; }, - setChartEnv: (v) => { _chartEnv = v; }, - setChartPrevT: (v) => { _chartPrevT = v; }, - setBcBeatIdx: (v) => { _bcBeatIdx = v; }, - setBcNoteIdx: (v) => { _bcNoteIdx = v; }, - setBcChordIdx: (v) => { _bcChordIdx = v; }, getSparkPos: () => _sparkPos, setSparkPos: (v) => { _sparkPos = v; }, getSparkCol: () => _sparkCol, setSparkCol: (v) => { _sparkCol = v; }, setSparkVel: (v) => { _sparkVel = v; }, @@ -4505,9 +4497,6 @@ import { createSceneInit } from './src/scene-init.js'; // h3d-carve-16 setSlideArrowApproachVisible: (v) => { slideArrowApproachVisible = v; }, setSlideArrowNeckVisible: (v) => { slideArrowNeckVisible = v; }, setSlideArrowChainPreviewVisible: (v) => { slideArrowChainPreviewVisible = v; }, - setTintR: (v) => { _tintR = v; }, - setTintG: (v) => { _tintG = v; }, - setTintB: (v) => { _tintB = v; }, setBoardStringStartX: (v) => { boardStringStartX = v; }, setBoardTuningLabelX: (v) => { boardTuningLabelX = v; }, getNdOnHit: () => _ndOnHit, setNdOnHit: (v) => { _ndOnHit = v; }, diff --git a/plugins/highway_3d/src/scene-init.js b/plugins/highway_3d/src/scene-init.js index ac56705..b9400d4 100644 --- a/plugins/highway_3d/src/scene-init.js +++ b/plugins/highway_3d/src/scene-init.js @@ -26,7 +26,6 @@ export function createSceneInit({ SPARK_N, _ND_TTL_MS, _ND_TIME_EPS, FRET_WIRE_HIT_HEX, FRET_WIRE_HIT_EMISSIVE, FRET_WIRE_IDLE_HEX, FRET_WIRE_IDLE_OP, - FRET_WIRE_HIT_OP, FRET_WIRE_HIT_INTENSITY, FRET_WIRE_HIT_DECAY, ACCENT_RIM_BASE_EMISSIVE, ACCENT_HALO_OP_NEAR, ACCENT_HALO_OP_MID, ACCENT_HALO_OP_FAR, ACCENT_HALO_XY_INNER, ACCENT_HALO_XY_MID, ACCENT_HALO_XY_OUTER, @@ -49,7 +48,6 @@ export function createSceneInit({ _darkenInt, _lightenInt, _h3dHexToInt, boardSpanX, _bcCreateController, - updateStringHighlights, canvasSize, applySize, fxInit, _disposeOpenStringPitchSprites, @@ -73,7 +71,6 @@ export function createSceneInit({ getVibrancyIdleOp, getVibrancyProjOp, getBgReactiveOptOut, getVenueSceneOverride, - getIsDestroyed, // ── Getter+setter pairs (written here; read by renderer.js / teardown etc.) ─ getWrap, setWrap, getRen, setRen, @@ -115,7 +112,6 @@ export function createSceneInit({ getStringLines, setStringLines, getProjMeshArr, setProjMeshArr, getBcCtrl, setBcCtrl, - setChartEnv, setChartPrevT, setBcBeatIdx, setBcNoteIdx, setBcChordIdx, getSparkPos, setSparkPos, getSparkCol, setSparkCol, setSparkVel, setSparkLife, setSparkPts, @@ -188,7 +184,6 @@ export function createSceneInit({ setTuningLabelsVisible, setProjectionVisible, setSlideArrowApproachVisible, setSlideArrowNeckVisible, setSlideArrowChainPreviewVisible, - setTintR, setTintG, setTintB, setBoardStringStartX, setBoardTuningLabelX, getNdOnHit, setNdOnHit, getNdOnMiss, setNdOnMiss, @@ -1827,12 +1822,12 @@ export function createSceneInit({ // when the user has never explicitly written them. Once the user // moves either slider, the corresponding _bgHasStored() flips // true and the read becomes independent. - setZoomSmoothing(_bgHasStored(panelKey, 'zoomSmoothing')) + setZoomSmoothing(_bgHasStored(panelKey, 'zoomSmoothing') ? _bgReadSetting(panelKey, 'zoomSmoothing') - : _cameraSmoothing; - setTiltSmoothing(_bgHasStored(panelKey, 'tiltSmoothing')) + : _cameraSmoothing); + setTiltSmoothing(_bgHasStored(panelKey, 'tiltSmoothing') ? _bgReadSetting(panelKey, 'tiltSmoothing') - : _cameraSmoothing; + : _cameraSmoothing); setCameraLockLow(_bgReadSetting(panelKey, 'cameraLockLow')); setCameraLockZoom(_bgReadSetting(panelKey, 'cameraLockZoom')); setCameraMode(_bgReadSetting(panelKey, 'cameraMode')); diff --git a/tests/js/highway_3d_scene_init.test.js b/tests/js/highway_3d_scene_init.test.js index cd8ff58..3b4fc70 100644 --- a/tests/js/highway_3d_scene_init.test.js +++ b/tests/js/highway_3d_scene_init.test.js @@ -96,8 +96,9 @@ test('createSceneInit receives ≥150 DI parameters (anti-vacuity floor)', () => // Anti-vacuity floor — if regex changes and extracts 0, this fails loudly assert.ok(names.size >= 150, `anti-vacuity: expected ≥150 DI params, got ${names.size}`); // Exact pinned count — update this if DI surface intentionally changes - assert.strictEqual(names.size, 183, - `exact DI param count must be 183 (got ${names.size}) — update if DI surface changes`); + // Cut-16 tip: 183. After F2 (remove 5 dead-param lines): 178. + assert.strictEqual(names.size, 178, + `exact DI param count must be 178 (got ${names.size}) — update if DI surface changes`); }); // ── §5 Import correctness ───────────────────────────────────────────────────── @@ -248,6 +249,74 @@ test('kill: _bcSyncMode body calls setBcCtrl(', () => { '_bcSyncMode must call setBcCtrl() — gut it and bcCtrl in screen.js scope is never updated; BC stays dead'); }); +// F1 kill: ternary must be INSIDE the setter argument (not truncated to boolean). +// Mutation: add extra ) after _bgHasStored(...) closing paren → argument becomes a bare boolean +// → argument text has no '?' → RED. +// A helper to extract the full argument (handles nested parens). +function extractSetterArg(src, fnName) { + const idx = src.indexOf(fnName + '('); + if (idx === -1) return null; + let depth = 0, argStart = -1, i = idx + fnName.length; + while (i < src.length) { + if (src[i] === '(') { if (depth === 0) argStart = i + 1; depth++; } + else if (src[i] === ')') { depth--; if (depth === 0) return src.slice(argStart, i); } + i++; + } + return null; +} + +test('kill: setZoomSmoothing argument contains ternary ? (not truncated to boolean)', () => { + const src = fs.readFileSync(sceneInitJs, 'utf8'); + const arg = extractSetterArg(src, 'setZoomSmoothing'); + assert.ok(arg !== null, 'setZoomSmoothing call must exist in scene-init.js'); + assert.ok(arg.includes('?'), + 'setZoomSmoothing argument must include ternary ? — ' + + 'if missing, the boolean condition was stored instead of the camera-smoothing value (F1 regression)'); +}); + +test('kill: setTiltSmoothing argument contains ternary ? (not truncated to boolean)', () => { + const src = fs.readFileSync(sceneInitJs, 'utf8'); + const arg = extractSetterArg(src, 'setTiltSmoothing'); + assert.ok(arg !== null, 'setTiltSmoothing call must exist in scene-init.js'); + assert.ok(arg.includes('?'), + 'setTiltSmoothing argument must include ternary ? — ' + + 'if missing, the boolean condition was stored instead of the camera-smoothing value (F1 regression)'); +}); + +// ── §9 Naming-correspondence guard ──────────────────────────────────────────── +// For every getX in the DI signature, assert a matching setX exists — or the +// getter is in READ_ONLY (stable state never written by scene-init). +// Mutation: rename setWrap → setWrp in scene-init.js DI → getWrap has no pair → RED. + +test('createSceneInit DI: every getX has a corresponding setX (naming correspondence)', () => { + const src = fs.readFileSync(sceneInitJs, 'utf8'); + const sigStart = src.indexOf('export function createSceneInit({'); + const bodyOpen = src.indexOf('\n}) {', sigStart); + const paramBlock = src.slice(sigStart, bodyOpen); + + const setters = new Set( + [...paramBlock.matchAll(/\bset([A-Z][A-Za-z0-9]*)\b/g)].map(m => m[1]) + ); + const getters = [ + ...paramBlock.matchAll(/\bget([A-Z][A-Za-z0-9]*)\b/g) + ].map(m => m[1]); + + // Stable read-only refs: screen.js never writes these after initial capture. + // scene-init receives getX but has no setX because it never needs to update them. + // Pinned: update only when a new stable-ref getter is added to the DI. + const READ_ONLY = new Set([ + 'BgReactiveOptOut', 'H3dFretUniform', 'InstanceId', + 'LeftyCached', 'NStr', 'VenueSceneOverride', + ]); + + for (const g of getters) { + if (READ_ONLY.has(g)) continue; + assert.ok(setters.has(g), + `DI naming gap: get${g} has no matching set${g} — ` + + `add setter to DI or add to READ_ONLY list in this test`); + } +}); + // ── §10 Execution smoke (§11 gate-2 of contract) ───────────────────────────── // new-Function harness: wrap scene-init.js in a function call, inject recording // DI stubs, invoke createSceneInit and then initScene(). The expected failure @@ -272,7 +341,7 @@ test('smoke: createSceneInit factory returns expected 4-key surface', () => { } }); -test('smoke: new-Function harness — setters called before null-T throw', () => { +test('smoke: new-Function harness — factory construction + null-canvas early guard', () => { const rawSrc = fs.readFileSync(sceneInitJs, 'utf8'); // Strip ES module syntax for new Function @@ -307,7 +376,6 @@ test('smoke: new-Function harness — setters called before null-T throw', () => SPARK_N: 256, _ND_TTL_MS: 1000, _ND_TIME_EPS: 0.01, FRET_WIRE_HIT_HEX: '#fff', FRET_WIRE_HIT_EMISSIVE: 1, FRET_WIRE_IDLE_HEX: '#888', FRET_WIRE_IDLE_OP: 0.5, - FRET_WIRE_HIT_OP: 1, FRET_WIRE_HIT_INTENSITY: 2, FRET_WIRE_HIT_DECAY: 0.9, ACCENT_RIM_BASE_EMISSIVE: 0.5, ACCENT_HALO_OP_NEAR: 0.8, ACCENT_HALO_OP_MID: 0.5, ACCENT_HALO_OP_FAR: 0.2, ACCENT_HALO_XY_INNER: 0.1, ACCENT_HALO_XY_MID: 0.2, ACCENT_HALO_XY_OUTER: 0.3, @@ -329,7 +397,7 @@ test('smoke: new-Function harness — setters called before null-T throw', () => _venueSwapPlateIfNeeded: () => {}, _darkenInt: (v) => v, _lightenInt: (v) => v, _h3dHexToInt: () => 0, boardSpanX: () => 10, _bcCreateController: () => ({}), - updateStringHighlights: () => {}, canvasSize: () => ({ w: 800, h: 600 }), + canvasSize: () => ({ w: 800, h: 600 }), applySize: () => {}, fxInit: () => {}, _disposeOpenStringPitchSprites: () => {}, // Stable refs @@ -348,7 +416,7 @@ test('smoke: new-Function harness — setters called before null-T throw', () => getTextSize: makeGetter(1), getGlowMul: makeGetter(1), getVibrancyIdleOp: makeGetter(0.5), getVibrancyProjOp: makeGetter(0.3), getBgReactiveOptOut: makeGetter(false), - getVenueSceneOverride: makeGetter(null), getIsDestroyed: makeGetter(false), + getVenueSceneOverride: makeGetter(null), getVibrancy: makeGetter(0.5), };