fix(h3d-carve-4): export _bcLoadSettings + _bcFfIdx; add caller-coverage test (Creed HIGH)

screen.js H/P-section render path at lines 15396-15402 calls _bcLoadSettings()
and _bcFfIdx() (3×) — both moved to bc-panel.js in cut 4 but omitted from the
export list.  Browser: first render() after bcCtrl creation → ReferenceError;
seek/loop fast-forward index also dead.  Suite was green because no test
executed the butterchurn render path.

Fix:
- export _bcLoadSettings and _bcFfIdx from bc-panel.js
- add both to the tagged import in screen.js

Class-killer (test 12 — generic, not instance-specific):
  Extracts all exports from bc-panel.js, all imports in screen.js's
  bc-panel.js import clause, then asserts no exported symbol appears as a
  bare reference in the screen.js IIFE body without being imported.
  Generic: adding a new export + new caller without updating the import → RED.

Own grep (audit):
  grep (non-comment lines, all private _bc* names from bc-panel.js):
    _bcLoadSettings  1 hit  (line 15396)
    _bcFfIdx         3 hits (lines 15400-15402)
    all others: 0 hits
  Only the two symbols Creed found.

Mutation-verify:
  remove _bcLoadSettings from screen.js import →
    node --test tests/js/highway_3d_bc_panel.test.js
    tests 12   pass 11   fail 1   (test 12 RED)  ✓
  restore →
    node --test tests/js/highway_3d*.test.js plugins/highway_3d/tests/*.test.js
    tests 222   pass 222   fail 0               ✓ GREEN

Plan §8 amended: exports 2→4 with dated note.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uZ169yfoFYArXz962g7KW
This commit is contained in:
byrongamatos
2026-09-05 09:03:10 +02:00
co-authored by Claude Sonnet 4.6
parent 81b366746e
commit f69c544eea
3 changed files with 48 additions and 4 deletions
+2 -2
View File
@@ -9,7 +9,7 @@
import { geoFretX, dZ, slideTrailEnd, camBaseDistU, camLowFretPullbackU, computeBPM, _makeGaussTex, RENDER_ORDER_LAYER_STACK, RENDER_ORDER_LAYER_INDEX, RENDER_ORDER_AT_Z_ZERO, RENDER_ORDER_FAR_CLAMP, renderOrderForLayerAtZ, _noteKey, lowerBoundT, hwyFirstRelevantFrettedTime, geoFretMid } from './src/geometry.js'; // h3d-carve-1b
import { loadThree, T } from './src/three-loader.js'; // h3d-carve-2
import { _h3dHexToInt, _clampByteI, _darkenInt, _lightenInt, resolveStringCount as _resolveStringCountBase, _NOTE_NAMES_SHARP, _BASE_OPEN_MIDI_BASS4, _BASE_OPEN_MIDI_BASS5, _BASE_OPEN_MIDI_GUITAR6, _BASE_OPEN_MIDI_GUITAR7, _BASE_OPEN_MIDI_GUITAR8, _baseOpenStringMidis, _midiToPitchLabel, _openStringPitchLabelsForTuning as _openStringPitchLabelsForTuningBase, _ssActive, _ssIsCanvasFocused } from './src/utils.js'; // h3d-carve-3
import { _bcIsDesktop, _bcCreateController } from './src/bc-panel.js'; // h3d-carve-4
import { _bcIsDesktop, _bcCreateController, _bcLoadSettings, _bcFfIdx } from './src/bc-panel.js'; // h3d-carve-4
(function () {
'use strict';
@@ -25,7 +25,7 @@ import { _bcIsDesktop, _bcCreateController } from './src/bc-panel.js'; // h3d-ca
// THREE_URL / THREE_CDN — h3d-carve-4: dead code (three-loader.js owns its own URLs). Tombstoned.
// ── B-section: Butterchurn control panel — h3d-carve-4 ──────────────
// Moved to src/bc-panel.js. Imports: _bcIsDesktop, _bcCreateController.
// Moved to src/bc-panel.js. Imports: _bcIsDesktop, _bcCreateController, _bcLoadSettings, _bcFfIdx.
// window.h3dBcApplySettings assigned at bc-panel.js module scope (R5).
// ────────────────────────────────────────────────────────────────────
// TOMBSTONE: BC_VENDOR, BC_FRAME, BC_WORKLET, _bcMeters, BC_BTN — h3d-carve-4: moved to src/bc-panel.js.
+2 -2
View File
@@ -47,7 +47,7 @@ export function _bcIsDesktop() {
// Position at the first entry whose time is >= ct (strict <), so an event
// landing exactly on the seek/loop target time is still fired by the update
// walkers (which consume `<= ct`) instead of being skipped past here.
function _bcFfIdx(arr, ct, key) { if (!arr) return 0; let i = 0; while (i < arr.length && (arr[i][key] || 0) < ct) i++; return i; }
export function _bcFfIdx(arr, ct, key) { if (!arr) return 0; let i = 0; while (i < arr.length && (arr[i][key] || 0) < ct) i++; return i; }
// Force-free a canvas's WebGL context so the GPU resources are released
// immediately instead of lingering until GC — repeated Butterchurn
// mount/unmount cycles otherwise pile up live contexts toward the browser cap.
@@ -164,7 +164,7 @@ function _bcGuitarFeed(actx, onReady) {
const BC_LS = 'viz3d_settings';
const BC_DEFAULTS = { enabled: true, opacity: 1.0, laneDim: true, laneDimStrength: 0.45, chartAccents: true, colorTint: true, chartStrength: 1.0, tintStrength: 0.65, guitarGain: 6, songGain: 1.8, cyclePool: 'all', hold: false };
let _bcSettings = null;
function _bcLoadSettings() {
export function _bcLoadSettings() {
if (_bcSettings) return _bcSettings;
let saved = {};
try { saved = JSON.parse(localStorage.getItem(BC_LS) || '{}'); } catch (e) {}