mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-09-11 03:54:31 +00:00
fix(h3d-carve-15): resolve Toby r1 F1/F2/F3 + scope-check test
F1 (HIGH): remove 44 phantom constants + fireDrawHooks + fxSpawnPop from
createRenderer DI signature and screen.js wiring. None ever existed in
screen.js scope; the engine threw ReferenceError at plugin init before
any argument was passed to createRenderer.
F2 (HIGH): un-move _setLabelMap back to screen.js (declared before
createNoteRenderer wiring at line ~6631), pass as DI to both
createNoteRenderer and createRenderer. Removing it from screen.js scope
caused a second independent ReferenceError before F1 even fired.
F3 (MED): drop 16 confirmed-dead DI params (0 body occurrences in
renderer.js): S_COL, SLIDE_RIBBON_SAMPLES, drawNotedetectLabels,
drawScoreFx, _resetStringDependentCaches, getCurDist, getCurLookY,
getTgtLookY, getFretRowFitBoost, getNdHitMarks, getNdMissMarks,
getImPMXFillCount, getImPMXLinesCount, getImFHXFillCount,
getImFHXLinesCount, getMeasureStarts. getMeasureStartsRef retained
(1 body use at renderer.js:831).
Scope-check also caught 4 pre-existing phantoms:
- PROJ_WIN, PROJ_WIN_G in createNoteRenderer wiring: note-renderer.js
body uses hardcoded 0.6 / _PROJ_WIN_ARP; these DI params only appear
in comments. Removed from note-renderer.js signature and both wiring
calls.
- camAhead, camTau in createRenderer wiring: update() re-declares both
as local let vars that shadow any DI value; also not declared in
screen.js. Removed from renderer.js signature and wiring.
New test (highway_3d_renderer.test.js #16): static wiring-scope check
blanks all four factory wiring blocks from the corpus, then asserts each
shorthand token appears in the remainder. RED at 7623ad8 on BEAT_HEAD_SEC
(44 phantoms), GREEN at this tip.
DI count: 241 → 177 (createRenderer), 130 → 128 (createNoteRenderer).
Suite: 1396/1397 (test 46 pre-existing).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uZ169yfoFYArXz962g7KW
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
7623ad85e3
commit
7180eff05d
@@ -6628,13 +6628,24 @@ import { createRenderer } from './src/renderer.js'; // h3d-carve-15
|
||||
// lookaheadTargetWorldX extracted below in the createCamera() destructure.
|
||||
|
||||
|
||||
// h3d-carve-15 F2: _setLabelMap must be in scope before both createNoteRenderer
|
||||
// and createRenderer wiring calls; defined here, passed as DI to both factories.
|
||||
// See renderer.js DI comment for the full explanation.
|
||||
function _setLabelMap(sprite, srcMat) {
|
||||
const m = sprite.material;
|
||||
if (m.map === srcMat.map) return;
|
||||
const nullnessChanged = (m.map == null) !== (srcMat.map == null);
|
||||
m.map = srcMat.map;
|
||||
if (nullnessChanged) m.needsUpdate = true;
|
||||
}
|
||||
|
||||
/* ── h3d-carve-14: V-section (note renderer) → src/note-renderer.js ── */
|
||||
const { drawNote, drawArpBrackets, drawNotedetectLabels, chordHarmonyLabels } = createNoteRenderer({
|
||||
// ── Constants ──────────────────────────────────────────────────
|
||||
K, NFRETS, NW, NH, AHEAD,
|
||||
GHOST_HOLD_AFTER_ONSET, NEXT_ON_STRING_T_EPS, NOTEDETECT_GEM_VERDICT_WINDOW,
|
||||
SLIDE_RIBBON_SAMPLES, S_GAP,
|
||||
BEND_HALFSTEP_WORLD_Y, PROJ_WIN, PROJ_WIN_G, PROJ_GROW_MIN,
|
||||
BEND_HALFSTEP_WORLD_Y, PROJ_GROW_MIN,
|
||||
GHOST_FRET_LBL_FADE_S,
|
||||
BEND_ENV_RISE_FRAC, BEND_ENV_RELEASE_FRAC,
|
||||
VIBRATO_HALF_WAVE_S, TREMOLO_BUMP_S,
|
||||
@@ -6838,7 +6849,7 @@ import { createRenderer } from './src/renderer.js'; // h3d-carve-15
|
||||
// in renderer.js with ponytail: comments.
|
||||
const { update } = createRenderer({
|
||||
// ── Consts ─────────────────────────────────────────────────────
|
||||
K, NFRETS, NW, NH, AHEAD, BEHIND, S_GAP, S_COL,
|
||||
K, NFRETS, NW, NH, AHEAD, BEHIND, S_GAP,
|
||||
CAM_FOCUS_BLEND_RATE,
|
||||
CAM_LOCK_ZOOM_MIN, CAM_LOCK_ZOOM_MAX, CAM_LOCK_CENTER_FRET,
|
||||
LOOKAHEAD_LOCK_ENGAGE_MAXF, LOOKAHEAD_LOCK_RELEASE_MAXF,
|
||||
@@ -6846,35 +6857,13 @@ import { createRenderer } from './src/renderer.js'; // h3d-carve-15
|
||||
FRET_WIDTH_MID, CAM_TGT_BEHIND, CAM_DIST_BASE,
|
||||
VENUE_GEM_EMISSIVE_MUL, NOTEDETECT_GEM_VERDICT_WINDOW,
|
||||
INLAY_LABEL_FRETS,
|
||||
GHOST_HOLD_AFTER_ONSET, camAhead, camTau,
|
||||
BEAT_HEAD_SEC, SEC_HEAD_SEC,
|
||||
LANE_BEAT_W, LANE_BEAT_DIV_W, LANE_LANE_W, LANE_OPEN_W, LANE_OPEN_H,
|
||||
CHORD_BOX_LEAD_S, CHORD_BOX_TRAIL_S, CHORD_BOX_FADE_S,
|
||||
CHORD_BOX_FRET_LABEL_THRESH_W,
|
||||
GHOST_HOLD_AFTER_ONSET,
|
||||
CHORD_FRAME_RIM_MIN, CHORD_FRAME_RIM_FRAC_H,
|
||||
SLIDE_RIBBON_SAMPLES,
|
||||
HALO_BAR_HALF_H, HALO_BAR_HALF_W,
|
||||
PM_X_BOX_TRAIL_S, PM_X_BOX_LEAD_S,
|
||||
FH_X_BOX_TRAIL_S, FH_X_BOX_LEAD_S,
|
||||
MUTE_X_LINES_TRAIL_S, MUTE_X_LINES_LEAD_S,
|
||||
FH_X_LINES_TRAIL_S, FH_X_LINES_LEAD_S,
|
||||
TECH_PLANE_LEAD_S, TECH_PLANE_TRAIL_S,
|
||||
CONNECTOR_LINE_LEAD_S, CONNECTOR_LINE_TRAIL_S,
|
||||
DROP_LINE_TRAIL_S, DROP_LINE_LEAD_S,
|
||||
SUS_RAIL_LEAD_S, SUS_RAIL_TRAIL_S,
|
||||
FRET_COL_MARKER_LEAD_S, FRET_COL_MARKER_TRAIL_S,
|
||||
TEACH_MARK_LBL_TRAIL_S, TEACH_MARK_LBL_LEAD_S,
|
||||
NOTE_FRET_LABEL_LEAD_S, NOTE_FRET_LABEL_TRAIL_S,
|
||||
GHOST_FRET_LBL_TRAIL_S, GHOST_FRET_LBL_LEAD_S,
|
||||
ARP_BRACKET_LEAD_S, ARP_BRACKET_TRAIL_S,
|
||||
HALO_BAR_LEAD_S, HALO_BAR_TRAIL_S,
|
||||
SEC_LABEL_LEAD_S, SEC_LABEL_TRAIL_S,
|
||||
BARLINE_LEAD_S, BARLINE_TRAIL_S,
|
||||
// ── Fn-refs ─────────────────────────────────────────────────────
|
||||
sY, xFret, xFretMid, fretLabelScaleForFret, pbBeg, pbEnd, pbReportTick,
|
||||
hwyFirstRelevantFrettedTime, _syncOpenStringPitchLabels, txtMat, fireDrawHooks,
|
||||
hwyFirstRelevantFrettedTime, _syncOpenStringPitchLabels, txtMat, _setLabelMap,
|
||||
// createNoteRenderer outputs:
|
||||
drawNote, drawArpBrackets, drawNotedetectLabels, chordHarmonyLabels,
|
||||
drawNote, drawArpBrackets, chordHarmonyLabels,
|
||||
// createCamera outputs:
|
||||
camUpdate,
|
||||
// createArp outputs:
|
||||
@@ -6888,8 +6877,7 @@ import { createRenderer } from './src/renderer.js'; // h3d-carve-15
|
||||
arpeggioLaneOuterRailLaneSlice, arpeggioLaneOuterRailAtChartTime,
|
||||
arpeggioLaneDividerFrameAccentMul, arpeggioLaneDividerXYScaleMatchFrameRim,
|
||||
// Other fn-refs:
|
||||
validString, filterValidNotes, fxSpawnPop, drawScoreFx,
|
||||
_resetStringDependentCaches,
|
||||
validString, filterValidNotes,
|
||||
// ── Pool getters (all 33) ────────────────────────────────────────
|
||||
getPNote: () => pNote,
|
||||
getPNoteEdge: () => pNoteEdge,
|
||||
@@ -6944,10 +6932,6 @@ import { createRenderer } from './src/renderer.js'; // h3d-carve-15
|
||||
getTgtX: () => tgtX,
|
||||
getTgtDist: () => tgtDist,
|
||||
getCurX: () => curX,
|
||||
getCurDist: () => curDist,
|
||||
getCurLookY: () => curLookY,
|
||||
getTgtLookY: () => tgtLookY,
|
||||
getFretRowFitBoost: () => fretRowFitBoost,
|
||||
getPrevLowFretBonus: () => prevLowFretBonus,
|
||||
getPrevLockActive: () => prevLockActive,
|
||||
// ── Lookahead / clock state getters ─────────────────────────────
|
||||
@@ -6970,8 +6954,6 @@ import { createRenderer } from './src/renderer.js'; // h3d-carve-15
|
||||
getNdVerdictSawAlpha: () => _ndVerdictSawAlpha,
|
||||
getNdVerdictMaxAlpha: () => _ndVerdictMaxAlpha,
|
||||
getNdFrameNowMs: () => _ndFrameNowMs,
|
||||
getNdHitMarks: () => _ndHitMarks,
|
||||
getNdMissMarks: () => _ndMissMarks,
|
||||
// ── Per-frame state getters ──────────────────────────────────────
|
||||
getInlayLabels: () => _inlayLabels,
|
||||
getLeanSusPollCounter: () => _leanSusPollCounter,
|
||||
@@ -6980,11 +6962,6 @@ import { createRenderer } from './src/renderer.js'; // h3d-carve-15
|
||||
getTextSizeMulApplied: () => _textSizeMulApplied,
|
||||
getImPMTechCount: () => _imPMTechCount,
|
||||
getImFHTechCount: () => _imFHTechCount,
|
||||
getImPMXFillCount: () => _imPMXFillCount,
|
||||
getImPMXLinesCount: () => _imPMXLinesCount,
|
||||
getImFHXFillCount: () => _imFHXFillCount,
|
||||
getImFHXLinesCount: () => _imFHXLinesCount,
|
||||
getMeasureStarts: () => _measureStarts,
|
||||
getMeasureStartsRef: () => _measureStartsRef,
|
||||
// ── Stable object refs ───────────────────────────────────────────
|
||||
_frameLabeledKeys, _ndLabels, _scrGhostUpcomingCount,
|
||||
|
||||
@@ -27,7 +27,8 @@ export function createNoteRenderer({
|
||||
K, NFRETS, NW, NH, AHEAD,
|
||||
GHOST_HOLD_AFTER_ONSET, NEXT_ON_STRING_T_EPS, NOTEDETECT_GEM_VERDICT_WINDOW,
|
||||
SLIDE_RIBBON_SAMPLES, S_GAP,
|
||||
BEND_HALFSTEP_WORLD_Y, PROJ_WIN, PROJ_WIN_G, PROJ_GROW_MIN,
|
||||
BEND_HALFSTEP_WORLD_Y, PROJ_GROW_MIN,
|
||||
// PROJ_WIN, PROJ_WIN_G: body uses hardcoded 0.6/_PROJ_WIN_ARP locals — not DI
|
||||
GHOST_FRET_LBL_FADE_S,
|
||||
BEND_ENV_RISE_FRAC, BEND_ENV_RELEASE_FRAC,
|
||||
VIBRATO_HALF_WAVE_S, TREMOLO_BUMP_S,
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
export function createRenderer({
|
||||
// ── Plain consts (shorthand) ──────────────────────────────────────────
|
||||
K, NFRETS, NW, NH, AHEAD, BEHIND, S_GAP, S_COL,
|
||||
K, NFRETS, NW, NH, AHEAD, BEHIND, S_GAP,
|
||||
CAM_FOCUS_BLEND_RATE,
|
||||
CAM_LOCK_ZOOM_MIN, CAM_LOCK_ZOOM_MAX, CAM_LOCK_CENTER_FRET,
|
||||
LOOKAHEAD_LOCK_ENGAGE_MAXF, LOOKAHEAD_LOCK_RELEASE_MAXF,
|
||||
@@ -22,36 +22,14 @@ export function createRenderer({
|
||||
FRET_WIDTH_MID, CAM_TGT_BEHIND, CAM_DIST_BASE,
|
||||
VENUE_GEM_EMISSIVE_MUL, NOTEDETECT_GEM_VERDICT_WINDOW,
|
||||
INLAY_LABEL_FRETS,
|
||||
GHOST_HOLD_AFTER_ONSET, camAhead, camTau,
|
||||
BEAT_HEAD_SEC, SEC_HEAD_SEC,
|
||||
LANE_BEAT_W, LANE_BEAT_DIV_W, LANE_LANE_W, LANE_OPEN_W, LANE_OPEN_H,
|
||||
CHORD_BOX_LEAD_S, CHORD_BOX_TRAIL_S, CHORD_BOX_FADE_S,
|
||||
CHORD_BOX_FRET_LABEL_THRESH_W,
|
||||
GHOST_HOLD_AFTER_ONSET,
|
||||
CHORD_FRAME_RIM_MIN, CHORD_FRAME_RIM_FRAC_H,
|
||||
SLIDE_RIBBON_SAMPLES,
|
||||
HALO_BAR_HALF_H, HALO_BAR_HALF_W,
|
||||
PM_X_BOX_TRAIL_S, PM_X_BOX_LEAD_S,
|
||||
FH_X_BOX_TRAIL_S, FH_X_BOX_LEAD_S,
|
||||
MUTE_X_LINES_TRAIL_S, MUTE_X_LINES_LEAD_S,
|
||||
FH_X_LINES_TRAIL_S, FH_X_LINES_LEAD_S,
|
||||
TECH_PLANE_LEAD_S, TECH_PLANE_TRAIL_S,
|
||||
CONNECTOR_LINE_LEAD_S, CONNECTOR_LINE_TRAIL_S,
|
||||
DROP_LINE_TRAIL_S, DROP_LINE_LEAD_S,
|
||||
SUS_RAIL_LEAD_S, SUS_RAIL_TRAIL_S,
|
||||
FRET_COL_MARKER_LEAD_S, FRET_COL_MARKER_TRAIL_S,
|
||||
TEACH_MARK_LBL_TRAIL_S, TEACH_MARK_LBL_LEAD_S,
|
||||
NOTE_FRET_LABEL_LEAD_S, NOTE_FRET_LABEL_TRAIL_S,
|
||||
GHOST_FRET_LBL_TRAIL_S, GHOST_FRET_LBL_LEAD_S,
|
||||
ARP_BRACKET_LEAD_S, ARP_BRACKET_TRAIL_S,
|
||||
HALO_BAR_LEAD_S, HALO_BAR_TRAIL_S,
|
||||
SEC_LABEL_LEAD_S, SEC_LABEL_TRAIL_S,
|
||||
BARLINE_LEAD_S, BARLINE_TRAIL_S,
|
||||
// camAhead, camTau: re-declared as let vars inside update() — not DI
|
||||
// ── Stable fn-refs (shorthand) ────────────────────────────────────────
|
||||
sY, xFret, xFretMid, fretLabelScaleForFret, pbBeg, pbEnd, pbReportTick,
|
||||
hwyFirstRelevantFrettedTime, _syncOpenStringPitchLabels, txtMat,
|
||||
fireDrawHooks,
|
||||
hwyFirstRelevantFrettedTime, _syncOpenStringPitchLabels, txtMat, _setLabelMap,
|
||||
// createNoteRenderer outputs (fn-refs from screen.js wiring):
|
||||
drawNote, drawArpBrackets, drawNotedetectLabels, chordHarmonyLabels,
|
||||
drawNote, drawArpBrackets, chordHarmonyLabels,
|
||||
// createCamera outputs:
|
||||
camUpdate,
|
||||
// arp.js outputs (from createArp destructure in screen.js):
|
||||
@@ -66,8 +44,6 @@ export function createRenderer({
|
||||
arpeggioLaneDividerFrameAccentMul, arpeggioLaneDividerXYScaleMatchFrameRim,
|
||||
// other screen.js fn-refs:
|
||||
validString, filterValidNotes,
|
||||
fxSpawnPop, drawScoreFx,
|
||||
_resetStringDependentCaches,
|
||||
// ── Getters (live state reads) ─────────────────────────────────────────
|
||||
// New pools:
|
||||
// All 33 pools (note-renderer 15 + new 18):
|
||||
@@ -84,8 +60,7 @@ export function createRenderer({
|
||||
getTextSize, getCameraMode, getCameraSmoothing, getZoomSmoothing,
|
||||
getCameraLockLow, getCameraLockZoom, getNStr, getLeftyCached, getInverted,
|
||||
// Camera state:
|
||||
getTgtX, getTgtDist, getCurX, getCurDist,
|
||||
getCurLookY, getTgtLookY, getFretRowFitBoost,
|
||||
getTgtX, getTgtDist, getCurX,
|
||||
getPrevLowFretBonus, getPrevLockActive,
|
||||
// Lookahead / clock state:
|
||||
getLookaheadCamX, getLookaheadFretSpan,
|
||||
@@ -95,13 +70,11 @@ export function createRenderer({
|
||||
getCamSnapped, getCamPreScanned, getCamBootstrapHolding, getCamBootstrapMode, getSongKey,
|
||||
// ND / per-frame state:
|
||||
getNdVerdictSawAlpha, getNdVerdictMaxAlpha, getNdFrameNowMs,
|
||||
getNdHitMarks, getNdMissMarks,
|
||||
// Other frame state:
|
||||
getInlayLabels,
|
||||
getLeanSusPollCounter, getLeanSus, getTextSizeMul, getTextSizeMulApplied,
|
||||
getImPMTechCount, getImFHTechCount,
|
||||
getImPMXFillCount, getImPMXLinesCount, getImFHXFillCount, getImFHXLinesCount,
|
||||
getMeasureStarts, getMeasureStartsRef,
|
||||
getMeasureStartsRef,
|
||||
// Stable object refs (mutable arrays/maps, passed by reference):
|
||||
_frameLabeledKeys,
|
||||
_ndLabels,
|
||||
@@ -344,24 +317,9 @@ function smoothNow(bundle) {
|
||||
// draw() after each init.
|
||||
// txtMat() rasterises into the unbounded cache these draws hit
|
||||
// anyway; ren.initTexture() forces the GPU upload now.
|
||||
// Swap a pooled label sprite's cached texture WITHOUT recompiling.
|
||||
// Setting material.needsUpdate bumps material.version, which forces
|
||||
// Three.js through getParameters/getProgramCacheKey on the next
|
||||
// render. Swapping one non-null texture for another does NOT change
|
||||
// the compiled program (the USE_MAP define is unchanged); only a
|
||||
// null <-> non-null transition does, and pooled label sprites are
|
||||
// constructed with a non-null map, so in practice this never
|
||||
// recompiles. (Note: the DOMINANT getParameters churn turned out to
|
||||
// be Three's transparent-DoubleSide two-pass path — see the
|
||||
// forceSinglePass comment in _spriteMat2MeshMat — this helper
|
||||
// removes the label-swap contribution on top of that.)
|
||||
function _setLabelMap(sprite, srcMat) {
|
||||
const m = sprite.material;
|
||||
if (m.map === srcMat.map) return;
|
||||
const nullnessChanged = (m.map == null) !== (srcMat.map == null);
|
||||
m.map = srcMat.map;
|
||||
if (nullnessChanged) m.needsUpdate = true;
|
||||
}
|
||||
// _setLabelMap is defined in screen.js and passed as DI (F2: used by both
|
||||
// createNoteRenderer and createRenderer — must live in screen.js scope before
|
||||
// either factory is wired).
|
||||
|
||||
let _chartPrewarmed = false;
|
||||
function _prewarmTex(mat) {
|
||||
|
||||
@@ -37,7 +37,7 @@ test('screen.js imports createNoteRenderer from note-renderer.js', () => {
|
||||
'screen.js must import createNoteRenderer');
|
||||
});
|
||||
|
||||
test('screen.js wiring block contains all 130 DI params', () => {
|
||||
test('screen.js wiring block contains all 128 DI params', () => {
|
||||
// Locate the wiring call; count getter arrows, setter arrows, and
|
||||
// shorthand entries. Each property in the object literal is one entry.
|
||||
// Strategy: extract the createNoteRenderer({...}) call text and count.
|
||||
@@ -62,11 +62,13 @@ test('screen.js wiring block contains all 130 DI params', () => {
|
||||
}, 0);
|
||||
|
||||
const total = getterCount + setterCount + shorthandCount;
|
||||
// 130 = 27 constants + 24 fn-refs + 7 stable-refs (shorthands:58) + 69 getters + 3 setters
|
||||
// (7 dead fn-refs removed in Toby r1 fix: xFret, pbBeg, pbEnd,
|
||||
// arpeggioChordIdForNoteWithInferCache, arpHsBoundsForNote, chordWireHighDensity, muteXMat)
|
||||
assert.strictEqual(total, 130,
|
||||
`DI param count must be exactly 130 (got getters:${getterCount} setters:${setterCount} shorthands:${shorthandCount} = ${total})`);
|
||||
// 128 = 56 shorthands + 69 getters + 3 setters
|
||||
// 130 → 128: removed PROJ_WIN + PROJ_WIN_G (scope-check phantoms — never
|
||||
// declared in screen.js; note-renderer.js body uses hardcoded 0.6 /
|
||||
// _PROJ_WIN_ARP, not these DI params; only appeared in comments).
|
||||
// Caught by r2 scope-check test in highway_3d_renderer.test.js.
|
||||
assert.strictEqual(total, 128,
|
||||
`DI param count must be exactly 128 (got getters:${getterCount} setters:${setterCount} shorthands:${shorthandCount} = ${total})`);
|
||||
});
|
||||
|
||||
// ── 2. Factory returns all 4 exports ────────────────────────────────────────
|
||||
|
||||
@@ -2,13 +2,16 @@
|
||||
//
|
||||
// Guards:
|
||||
// 1. Wiring: createRenderer factory exists in renderer.js and screen.js
|
||||
// imports + calls it with the expected DI param count (241).
|
||||
// imports + calls it with the expected DI param count (179).
|
||||
// 2. Kill tests: extracted private helpers are live in renderer.js; gut and
|
||||
// restore proves RED.
|
||||
// 3. Export contract: { update } returned by createRenderer.
|
||||
// 4. Caller-list corrections: _applyNoteCamTargets and lookaheadSmoothCamStep
|
||||
// have exactly the audited caller counts.
|
||||
// 5. screen.js tombstone: original U-section bodies are absent from screen.js.
|
||||
// 6. Wiring scope check: every shorthand identifier in every factory wiring call
|
||||
// in screen.js resolves to a declared name — no phantoms (RED at 7623ad8 on
|
||||
// BEAT_HEAD_SEC).
|
||||
|
||||
'use strict';
|
||||
|
||||
@@ -39,7 +42,10 @@ test('screen.js imports createRenderer from renderer.js', () => {
|
||||
'screen.js must import createRenderer');
|
||||
});
|
||||
|
||||
test('screen.js wiring block contains expected DI param count (241)', () => {
|
||||
test('screen.js wiring block contains expected DI param count (177)', () => {
|
||||
// 177 = 77 getters + 35 setters + 65 shorthands (pinned after r2 phantom/dead-param fixes)
|
||||
// OLD pinned value was 241 (inflated by 44 phantom consts, 2 undefined fn-refs, 16 dead params,
|
||||
// and 2 shadowed locals camAhead/camTau that were re-declared as let inside update()).
|
||||
const wiringMatch = screenSrc.match(/createRenderer\(\{([\s\S]*?)\}\)/);
|
||||
assert.ok(wiringMatch, 'screen.js must contain createRenderer({...}) call');
|
||||
const body = wiringMatch[1];
|
||||
@@ -53,7 +59,7 @@ test('screen.js wiring block contains expected DI param count (241)', () => {
|
||||
}, 0);
|
||||
|
||||
const total = getterCount + setterCount + shorthandCount;
|
||||
assert.strictEqual(total, 241,
|
||||
assert.strictEqual(total, 177,
|
||||
`DI param count mismatch: got ${total} (getters=${getterCount}, setters=${setterCount}, shorthands=${shorthandCount})`);
|
||||
});
|
||||
|
||||
@@ -144,3 +150,66 @@ test('createRenderer wiring is after createCamera in screen.js', () => {
|
||||
assert.ok(renPos > camPos,
|
||||
'createRenderer({}) wiring must appear after createCamera({}) in screen.js');
|
||||
});
|
||||
|
||||
// ── 7. Wiring scope check — every shorthand in all factory wirings is declared ──
|
||||
// This test is the source-scan mitigation for wiring specifically:
|
||||
// it was RED at 7623ad8 (BEAT_HEAD_SEC phantom failed; 44 phantoms total) and
|
||||
// GREEN at the r2 fix tip.
|
||||
//
|
||||
// Strategy: for each wiring call block, extract shorthand identifier lines
|
||||
// (no => arrow, no key: pattern), strip comment lines, collect identifier tokens.
|
||||
// Then verify each appears in screen.js OUTSIDE the wiring block itself.
|
||||
// A phantom never appears outside — so it fails here with a clear name.
|
||||
|
||||
test('all shorthand identifiers in factory wiring calls are declared in screen.js scope', () => {
|
||||
// Extract shorthand tokens from the wiring body of a factory call.
|
||||
// Lines containing '=>' are getter/setter arrow functions (skip).
|
||||
// Lines whose only non-whitespace content is identifiers + commas are shorthand lines.
|
||||
function extractShorthands(wiringBody) {
|
||||
const names = new Set();
|
||||
for (const line of wiringBody.split('\n')) {
|
||||
const t = line.trim();
|
||||
if (!t || t.startsWith('//')) continue;
|
||||
if (t.includes('=>')) continue;
|
||||
// If line contains 'word:' pattern it's a key:value line — skip key (param name, not scope ref)
|
||||
if (/\b\w+\s*:/.test(t)) continue;
|
||||
const toks = t.match(/\b[A-Za-z_][A-Za-z0-9_]*\b/g) || [];
|
||||
for (const tok of toks) names.add(tok);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
// Build corpus = screen.js with each wiring block blanked out.
|
||||
// Names that only exist inside the wiring block → not in corpus → fail.
|
||||
// Each wiring block is identified by its factory call signature.
|
||||
const factoryPatterns = [
|
||||
/createArp\(\{([\s\S]*?)\}\)/,
|
||||
/createNoteRenderer\(\{([\s\S]*?)\}\)/,
|
||||
/createCamera\(\{([\s\S]*?)\}\)/,
|
||||
/const \{ update \} = createRenderer\(\{([\s\S]*?)\}\)/,
|
||||
];
|
||||
|
||||
// Build scope corpus: screenSrc with all wiring blocks blanked
|
||||
let corpus = screenSrc;
|
||||
for (const pat of factoryPatterns) {
|
||||
corpus = corpus.replace(pat, (m) => ' '.repeat(m.length));
|
||||
}
|
||||
|
||||
const allMissing = [];
|
||||
for (const pat of factoryPatterns) {
|
||||
const m = screenSrc.match(pat);
|
||||
if (!m) continue;
|
||||
const shorthands = extractShorthands(m[m.length - 1]); // last capture group = body
|
||||
for (const name of shorthands) {
|
||||
// Check the name appears in the corpus (outside all wiring blocks)
|
||||
if (!new RegExp(`\\b${name}\\b`).test(corpus)) {
|
||||
allMissing.push(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert.deepEqual(allMissing.sort(), [],
|
||||
`Shorthand identifiers not declared in screen.js scope (phantoms): ${allMissing.sort().join(', ')}\n` +
|
||||
`This test was RED at 7623ad8 on BEAT_HEAD_SEC (44 phantoms). ` +
|
||||
`Fix: delete undefined names from both the DI signature and wiring call.`);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user