Просмотр исходного кода

fix(cockpit): repair engine boot broken by bad scene-grade import

三维场景消失的根因:cesiumEngine 从 sceneGrade 导入了它并未导出的
parseHexColor —— ESM 链接错误让引擎模块整个加载失败,Cesium 永远起不来。

- parseHexColor 归位其唯一 owner fog.js;GRADE_DEFAULTS 仍来自 sceneGrade
- 工作区里并行会话把雾/调色两处 shader 的 varying 改成了 in(未提交实验,
  未经真机验证),恢复为雾真机验证过的 varying 模板,排除第二个编译变量
- t49 新增 C2 ESM 链接守卫:导入的具名绑定必须真实导出(静态字符串断言
  查不出这类错误,本次事故的防回归断言)
Kazerin 1 неделя назад
Родитель
Сommit
09905be058

+ 36 - 2
.scratch/cockpit-shell-panel-layout/verify/t49-scene-grade.mjs

@@ -97,9 +97,44 @@ const { builtinConfig, normalizeConfig } = await import('../../../src/modules/co
     assert.ok(shader.includes('0.2126, 0.7152, 0.0722'), '同一套 Rec.709 亮度权重')
     assert.ok(shader.includes('out_FragColor'), '用 Cesium 当前的 out_FragColor 出口')
     assert.ok(shader.includes('gradeTintStrength * (1.0 - luma)'), '阴影权重公式与 domain 一致')
+    // varying 而不是 in:与雾 shader(真机验证过的模板)保持一致;写 in 是并行会话的
+    // 未提交实验,GLSL 翻译行为未经验证, shader 编译失败 = 整帧失败 = 三维场景消失。
+    assert.ok(shader.includes('varying vec2 v_textureCoordinates;'), 'shader 用雾同款 varying 模板')
     console.log('PASS C1 引擎处理级:函数 uniform、enabled 随计划、shader 与 domain 同序同式')
 }
 
+// ---- C2. ESM 链接守卫(本次事故的防回归断言)----
+// cesiumEngine 从 sceneGrade 导入 parseHexColor(未导出)→ ESM 链接错误 →
+// `await import('./cesiumEngine.js')` 整个 reject → 引擎永远起不来 → 三维场景消失。
+// 静态字符串断言查不出这类错误,必须核对"导入的具名绑定在目标模块里真实导出"。
+{
+    const importsOf = (source, targetPath) => {
+        const re = new RegExp(`import \\s*\\{([^}]*)\\}\\s*from\\s*'${targetPath}'`, 'g')
+        const names = []
+        for (const m of source.matchAll(re)) for (const name of m[1].split(',')) {
+            const clean = name.trim().split(/\s+as\s+/).pop()
+            if (clean) names.push(clean)
+        }
+        return names
+    }
+    const exportsOf = (source) => new Set(
+        [...source.matchAll(/^export\s+(?:const|function|let|class)\s+([A-Za-z0-9_$]+)/gm)].map((m) => m[1]),
+    )
+    const engine = read('src/modules/cockpit/services/cesiumEngine.js')
+    for (const [target, path] of [
+        [read('src/modules/cockpit/domain/sceneGrade.js'), '\\.\\./domain/sceneGrade\\.js'],
+        [read('src/modules/cockpit/domain/fog.js'), '\\.\\./domain/fog\\.js'],
+    ]) {
+        const exported = exportsOf(target)
+        for (const name of importsOf(engine, path)) {
+            assert.ok(exported.has(name), `cesiumEngine 从 ${path} 导入的 ${name} 必须真实导出(否则 ESM 链接错误,引擎起不来)`)
+        }
+    }
+    assert.ok(/import \{ GRADE_DEFAULTS \} from '\.\.\/domain\/sceneGrade\.js'/.test(engine), 'GRADE_DEFAULTS 来自 sceneGrade')
+    assert.ok(/import \{ parseHexColor \} from '\.\.\/domain\/fog\.js'/.test(engine), 'parseHexColor 的 owner 是 fog.js(sceneGrade 自己也只是导入它)')
+    console.log('PASS C2 ESM 链接守卫:导入的具名绑定都真实导出,parseHexColor 归位 fog.js')
+}
+
 // ---- D. 服务层装配 ----
 {
     const service = read('src/modules/cockpit/services/mapService.js')
@@ -125,9 +160,8 @@ const { builtinConfig, normalizeConfig } = await import('../../../src/modules/co
     const gradeDomain = read('src/modules/cockpit/domain/sceneGrade.js')
     assert.ok(!/function readNumber/.test(gradeDomain), 'sceneGrade 不再自带 readNumber 副本(复用 fog.js 导出)')
     assert.ok(/import \{ parseHexColor, readNumber \} from '\.\/fog\.js'/.test(gradeDomain), '口径单一来源:parseHexColor + readNumber 都从 fog.js 复用')
-    // 引擎兜底色从 domain 默认派生,不再手抄浮点魔数。
+    // 引擎兜底色从 domain 默认派生,不再手抄浮点魔数(导入归属见 C2 的 ESM 链接守卫)。
     const engine = read('src/modules/cockpit/services/cesiumEngine.js')
-    assert.ok(/import \{ GRADE_DEFAULTS, parseHexColor \} from '\.\.\/domain\/sceneGrade\.js'/.test(engine), '引擎兜底色引 domain 默认')
     assert.ok(/params\.tintRgb \|\| parseHexColor\(GRADE_DEFAULTS\.tint\)/.test(engine), '兜底 = GRADE_DEFAULTS.tint(无第三层魔数)')
     console.log('PASS D1 服务层装配:建级/写参/销毁/归零/配置生效/顺序在雾后/三态读数/口径复用')
 }

+ 2 - 1
src/modules/cockpit/services/cesiumEngine.js

@@ -55,7 +55,8 @@ import { createTilesetLoadingController } from './tilesetLoading.js'
 // 本层只把相位写成 billboard 的 scale/alpha/rotation。
 import { DEVICE_EFFECT, RING_LAYERS, blinkStrengthAt, glowScaleAt, glowStrengthAt, hasGlow, pulseStrengthAt, ringEntityCount, ringFrameAt, spinAngleAt } from '../domain/deviceEffects.js'
 // 场景调色的兜底色直接取 domain 的默认(不再手抄一份 #2fa8ff 的浮点,两处会漂)。
-import { GRADE_DEFAULTS, parseHexColor } from '../domain/sceneGrade.js'
+import { GRADE_DEFAULTS } from '../domain/sceneGrade.js'
+import { parseHexColor } from '../domain/fog.js'
 
 const DEG = Math.PI / 180