diff --git a/apps/web-console/app.js b/apps/web-console/app.js
index e5bee40..af56591 100755
--- a/apps/web-console/app.js
+++ b/apps/web-console/app.js
@@ -2549,7 +2549,14 @@ function updateSeatTwin(actuatorState) {
}
const REFERENCE_VEHICLE_ROOT = "/assets/models/byd-tang/";
-const REFERENCE_VEHICLE_URL = `${REFERENCE_VEHICLE_ROOT}byd-tang-2024.fbx`;
+const REFERENCE_VEHICLE_ASSET_VERSION = "77a0fae7";
+const REFERENCE_VEHICLE_LOAD_TIMEOUT_MS = 30000;
+
+function referenceVehicleAssetUrl(fileName) {
+ return `${REFERENCE_VEHICLE_ROOT}${encodeURIComponent(fileName)}?v=${REFERENCE_VEHICLE_ASSET_VERSION}`;
+}
+
+const REFERENCE_VEHICLE_URL = referenceVehicleAssetUrl("byd-tang-2024.fbx");
function referenceMaterialDescriptor(material) {
const textureNames = [
@@ -3643,73 +3650,92 @@ function loadReferenceVehicleModel(THREE, scene, vehicleSystems, fallback) {
reject(new Error("FBXLoader is unavailable"));
return;
}
+ let settled = false;
+ const settle = (callback, value) => {
+ if (settled) return false;
+ settled = true;
+ window.clearTimeout(timeoutId);
+ callback(value);
+ return true;
+ };
+ const timeoutId = window.setTimeout(() => {
+ settle(
+ reject,
+ new Error(`Reference vehicle load timed out after ${REFERENCE_VEHICLE_LOAD_TIMEOUT_MS} ms`),
+ );
+ }, REFERENCE_VEHICLE_LOAD_TIMEOUT_MS);
const manager = new THREE.LoadingManager();
manager.setURLModifier((url) => {
- const cleanUrl = String(url).replaceAll("\\", "/");
+ const cleanUrl = String(url).replaceAll("\\", "/").split(/[?#]/, 1)[0];
const fileName = decodeURIComponent(cleanUrl.split("/").pop() || "");
if (!/\.(png|jpe?g)$/i.test(fileName)) return url;
- return `${REFERENCE_VEHICLE_ROOT}${encodeURIComponent(fileName)}`;
+ return referenceVehicleAssetUrl(fileName);
});
const loader = new FBXLoaderClass(manager);
loader.setResourcePath(REFERENCE_VEHICLE_ROOT);
loader.load(
REFERENCE_VEHICLE_URL,
(vehicle) => {
- const normalized = normalizeReferenceVehicle(THREE, vehicle);
- const driverCushion = measureReferenceDriverCushion(THREE, vehicle);
- const passengerCushion = measureReferencePassengerCushion(THREE, vehicle);
- const removedFrontSeatTriangles = carveReferenceFrontSeats(THREE, vehicle);
- const referenceWindowPanes = extractReferenceWindowPanes(THREE, vehicle);
- const report = configureReferenceVehicleModel(THREE, vehicle);
- styleReferencePassiveGlass(THREE, vehicle);
- const passiveRearExterior = styleReferencePassiveRearExterior(THREE, vehicle);
- const referenceFrontLampMeshes = collectReferenceFrontLampMeshes(vehicle);
- emphasizeReferenceWindowPanes(THREE, referenceWindowPanes);
- const referenceFrontLampMaterials = emphasizeReferenceFrontLampMeshes(
- THREE,
- referenceFrontLampMeshes,
- );
- const referenceFrontLampHighlights = createReferenceFrontLampHighlights(
- THREE,
- referenceFrontLampMeshes,
- );
- const referenceFrontLampLensOutlines = createReferenceFrontLampLensOutlines(
- THREE,
- vehicle,
- );
- vehicleSystems.referenceWindowPanes = referenceWindowPanes;
- vehicleSystems.referenceFrontLampMaterials = referenceFrontLampMaterials;
- vehicleSystems.referenceFrontLampMeshes = referenceFrontLampMeshes;
- vehicleSystems.referenceFrontLampHighlights = referenceFrontLampHighlights;
- vehicleSystems.referenceFrontLampLensOutlines = referenceFrontLampLensOutlines;
- applyTwinVehicleTheme(vehicleSystems);
- vehicle.name = "REFERENCE_VEHICLE_OUTLINE";
- vehicle.userData.twinRole = "reference_vehicle";
- vehicle.traverse((object) => object.layers.set(1));
- scene.add(vehicle);
- vehicleSystems.fallbackExteriorObjects.forEach((object) => {
- object.visible = false;
- });
- vehicleSystems.fallbackInteriorObjects.forEach((object) => {
- object.visible = false;
- });
- console.info("[vehicle-twin] reference vehicle model loaded", JSON.stringify({
- meshes: report.meshes,
- size: normalized.size.toArray().map((value) => Number(value.toFixed(3))),
- removedFrontSeatTriangles,
- windowPanes: Object.fromEntries(
- Object.entries(referenceWindowPanes).map(([key, value]) => [key, value.length]),
- ),
- frontLampMaterials: referenceFrontLampMaterials.length,
- frontLampMeshes: referenceFrontLampMeshes.length,
- frontLampHighlights: referenceFrontLampHighlights.length,
- frontLampLensOutlines: referenceFrontLampLensOutlines.length,
- rearLampMeshes: passiveRearExterior.rearLampMeshes.length,
- rearBumperMeshes: passiveRearExterior.rearBumperMeshes.length,
- driverCushion,
- passengerCushion,
- }));
- resolve({ vehicle, report, normalized, driverCushion, passengerCushion });
+ if (settled) return;
+ try {
+ const normalized = normalizeReferenceVehicle(THREE, vehicle);
+ const driverCushion = measureReferenceDriverCushion(THREE, vehicle);
+ const passengerCushion = measureReferencePassengerCushion(THREE, vehicle);
+ const removedFrontSeatTriangles = carveReferenceFrontSeats(THREE, vehicle);
+ const referenceWindowPanes = extractReferenceWindowPanes(THREE, vehicle);
+ const report = configureReferenceVehicleModel(THREE, vehicle);
+ styleReferencePassiveGlass(THREE, vehicle);
+ const passiveRearExterior = styleReferencePassiveRearExterior(THREE, vehicle);
+ const referenceFrontLampMeshes = collectReferenceFrontLampMeshes(vehicle);
+ emphasizeReferenceWindowPanes(THREE, referenceWindowPanes);
+ const referenceFrontLampMaterials = emphasizeReferenceFrontLampMeshes(
+ THREE,
+ referenceFrontLampMeshes,
+ );
+ const referenceFrontLampHighlights = createReferenceFrontLampHighlights(
+ THREE,
+ referenceFrontLampMeshes,
+ );
+ const referenceFrontLampLensOutlines = createReferenceFrontLampLensOutlines(
+ THREE,
+ vehicle,
+ );
+ vehicleSystems.referenceWindowPanes = referenceWindowPanes;
+ vehicleSystems.referenceFrontLampMaterials = referenceFrontLampMaterials;
+ vehicleSystems.referenceFrontLampMeshes = referenceFrontLampMeshes;
+ vehicleSystems.referenceFrontLampHighlights = referenceFrontLampHighlights;
+ vehicleSystems.referenceFrontLampLensOutlines = referenceFrontLampLensOutlines;
+ applyTwinVehicleTheme(vehicleSystems);
+ vehicle.name = "REFERENCE_VEHICLE_OUTLINE";
+ vehicle.userData.twinRole = "reference_vehicle";
+ vehicle.traverse((object) => object.layers.set(1));
+ scene.add(vehicle);
+ vehicleSystems.fallbackExteriorObjects.forEach((object) => {
+ object.visible = false;
+ });
+ vehicleSystems.fallbackInteriorObjects.forEach((object) => {
+ object.visible = false;
+ });
+ console.info("[vehicle-twin] reference vehicle model loaded", JSON.stringify({
+ meshes: report.meshes,
+ size: normalized.size.toArray().map((value) => Number(value.toFixed(3))),
+ removedFrontSeatTriangles,
+ windowPanes: Object.fromEntries(
+ Object.entries(referenceWindowPanes).map(([key, value]) => [key, value.length]),
+ ),
+ frontLampMaterials: referenceFrontLampMaterials.length,
+ frontLampMeshes: referenceFrontLampMeshes.length,
+ frontLampHighlights: referenceFrontLampHighlights.length,
+ frontLampLensOutlines: referenceFrontLampLensOutlines.length,
+ rearLampMeshes: passiveRearExterior.rearLampMeshes.length,
+ rearBumperMeshes: passiveRearExterior.rearBumperMeshes.length,
+ driverCushion,
+ passengerCushion,
+ }));
+ settle(resolve, { vehicle, report, normalized, driverCushion, passengerCushion });
+ } catch (error) {
+ settle(reject, error);
+ }
},
(event) => {
if (!fallback || !event.total) return;
@@ -3717,7 +3743,7 @@ function loadReferenceVehicleModel(THREE, scene, vehicleSystems, fallback) {
const label = fallback.querySelector("span");
if (label) label.textContent = `正在加载整车参考模型 · ${progress}%`;
},
- reject,
+ (error) => settle(reject, error),
);
});
}
@@ -3726,7 +3752,33 @@ function initSeatTwin() {
const canvas = $("#seatTwinCanvas");
const stage = $("#seatTwin");
const fallback = $("#twinFallback");
- if (!canvas || !stage) return;
+ if (!canvas || !stage || state.seatTwin) return;
+ const stageHasLayout = () => {
+ const bounds = stage.getBoundingClientRect();
+ return stage.isConnected && bounds.width >= 2 && bounds.height >= 2;
+ };
+ if (!stageHasLayout()) {
+ if (stage.dataset.twinInitPending === "true") return;
+ stage.dataset.twinInitPending = "true";
+ let pendingObserver = null;
+ const retryInitialization = () => {
+ if (!stageHasLayout()) return;
+ pendingObserver?.disconnect();
+ window.removeEventListener("resize", scheduleRetry);
+ window.removeEventListener("cognitive-agent:module-change", scheduleRetry);
+ delete stage.dataset.twinInitPending;
+ initSeatTwin();
+ };
+ const scheduleRetry = () => window.requestAnimationFrame(retryInitialization);
+ if (window.ResizeObserver) {
+ pendingObserver = new ResizeObserver(retryInitialization);
+ pendingObserver.observe(stage);
+ }
+ window.addEventListener("resize", scheduleRetry);
+ window.addEventListener("cognitive-agent:module-change", scheduleRetry);
+ scheduleRetry();
+ return;
+ }
if (!window.THREE) {
fallback.classList.add("error");
fallback.innerHTML = '3D 引擎加载失败,精确状态仍可用';
@@ -3735,7 +3787,16 @@ function initSeatTwin() {
}
const THREE = window.THREE;
- const renderer = new THREE.WebGLRenderer({ canvas, antialias: true, powerPreference: "high-performance" });
+ let renderer;
+ try {
+ renderer = new THREE.WebGLRenderer({ canvas, antialias: true, powerPreference: "high-performance" });
+ } catch (error) {
+ console.error("[vehicle-twin] failed to initialize WebGL", error);
+ fallback.classList.add("error");
+ fallback.innerHTML = '3D 渲染器初始化失败,状态数据仍可用';
+ refreshIcons();
+ return;
+ }
renderer.autoClear = false;
renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
if ("outputColorSpace" in renderer) renderer.outputColorSpace = THREE.SRGBColorSpace;
@@ -3883,6 +3944,7 @@ function initSeatTwin() {
applyTwinSceneTheme(state.seatTwin);
});
+ canvas.dataset.referenceModelState = "loading";
loadReferenceVehicleModel(THREE, scene, vehicleSystems, fallback)
.then(({ vehicle, report, normalized, driverCushion, passengerCushion }) => {
if (!state.seatTwin) return;
@@ -3920,11 +3982,12 @@ function initSeatTwin() {
.toArray()
.map((value) => value.toFixed(2))
.join("x");
- canvas.dataset.referenceModelLoaded = "true";
+ canvas.dataset.referenceModelState = "loaded";
fallback.hidden = true;
})
.catch((error) => {
console.error("[vehicle-twin] failed to load reference vehicle model", error);
+ canvas.dataset.referenceModelState = "failed";
fallback.classList.add("error");
fallback.innerHTML = '实车模型加载失败,已切换轻量回退模型';
refreshIcons();
@@ -3940,17 +4003,64 @@ function initSeatTwin() {
});
}
+ let stageWasVisible = false;
function resize() {
- const width = Math.max(1, canvas.clientWidth);
- const height = Math.max(1, canvas.clientHeight);
+ const width = Math.max(1, Math.round(stage.clientWidth));
+ const height = Math.max(1, Math.round(stage.clientHeight));
renderer.setSize(width, height, false);
camera.aspect = width / height;
camera.updateProjectionMatrix();
state.seatTwin.narrowViewport = width < 600;
}
- new ResizeObserver(resize).observe(stage);
- resize();
+ function synchronizeTwinViewport({ reset = false } = {}) {
+ if (!stageHasLayout()) {
+ stageWasVisible = false;
+ return false;
+ }
+ resize();
+ if (reset || !stageWasVisible) resetView();
+ stageWasVisible = true;
+ return true;
+ }
+
+ const scheduleViewportSync = () => {
+ window.requestAnimationFrame(() => window.requestAnimationFrame(() => {
+ synchronizeTwinViewport();
+ }));
+ };
+ if (window.ResizeObserver) {
+ const stageObserver = new ResizeObserver(() => synchronizeTwinViewport());
+ stageObserver.observe(stage);
+ state.seatTwin.resizeObserver = stageObserver;
+ }
+ window.addEventListener("resize", scheduleViewportSync);
+ window.addEventListener("cognitive-agent:module-change", scheduleViewportSync);
+ canvas.addEventListener("webglcontextlost", (event) => {
+ event.preventDefault();
+ canvas.dataset.contextLost = "true";
+ fallback.hidden = false;
+ fallback.classList.add("error");
+ fallback.innerHTML = '3D 上下文已中断,正在等待恢复';
+ refreshIcons();
+ });
+ canvas.addEventListener("webglcontextrestored", () => {
+ delete canvas.dataset.contextLost;
+ synchronizeTwinViewport({ reset: true });
+ const modelState = canvas.dataset.referenceModelState;
+ fallback.hidden = modelState === "loaded";
+ if (modelState === "loading") {
+ fallback.classList.remove("error");
+ fallback.innerHTML = '正在加载整车参考模型';
+ refreshIcons();
+ } else if (modelState === "failed") {
+ fallback.classList.add("error");
+ fallback.innerHTML = '实车模型加载失败,已切换轻量回退模型';
+ refreshIcons();
+ window.setTimeout(() => { fallback.hidden = true; }, 3200);
+ }
+ });
+ synchronizeTwinViewport({ reset: true });
stage.addEventListener("pointerdown", (event) => {
state.seatTwin.dragging = true;
state.seatTwin.pointer = { x: event.clientX, y: event.clientY };
@@ -4052,6 +4162,12 @@ function initSeatTwin() {
function animate(timestamp = 0) {
const twin = state.seatTwin;
if (!twin) return;
+ if (!stageHasLayout() || canvas.dataset.contextLost === "true") {
+ stageWasVisible = false;
+ window.requestAnimationFrame(animate);
+ return;
+ }
+ if (!stageWasVisible) synchronizeTwinViewport({ reset: true });
Object.values(twin.models).forEach((model) => {
Object.keys(model.positions).forEach((axis) => {
const delta = model.targets[axis] - model.positions[axis];
@@ -6556,7 +6672,7 @@ document.addEventListener("DOMContentLoaded", async () => {
initJointTwinLayout();
initResultWorkspace();
refreshIcons();
- initSeatTwin();
+ window.requestAnimationFrame(initSeatTwin);
$("#requestForm").addEventListener("submit", submitRequest);
$("#utterance").addEventListener("keydown", (event) => {
if (event.key === "Enter" && !event.shiftKey && !event.isComposing) {
diff --git a/apps/web-console/index.html b/apps/web-console/index.html
index ff3258e..e94fdd4 100755
--- a/apps/web-console/index.html
+++ b/apps/web-console/index.html
@@ -19,14 +19,14 @@
-
+
-
+
diff --git a/apps/web-console/self-repair-seat3d.js b/apps/web-console/self-repair-seat3d.js
index 7edfe88..4aa7950 100644
--- a/apps/web-console/self-repair-seat3d.js
+++ b/apps/web-console/self-repair-seat3d.js
@@ -1,6 +1,33 @@
(function () {
"use strict";
+ function viewerHasLayout(viewer) {
+ const bounds = viewer.getBoundingClientRect();
+ return viewer.isConnected && bounds.width >= 2 && bounds.height >= 2;
+ }
+
+ function deferSeat3dUntilVisible(viewer, options) {
+ if (viewer.dataset.seat3dPending === "true") return;
+ viewer.dataset.seat3dPending = "true";
+ let observer = null;
+ const retry = () => {
+ if (!viewerHasLayout(viewer)) return;
+ observer?.disconnect();
+ window.removeEventListener("resize", scheduleRetry);
+ window.removeEventListener("cognitive-agent:module-change", scheduleRetry);
+ delete viewer.dataset.seat3dPending;
+ initSeat3d(options);
+ };
+ const scheduleRetry = () => window.requestAnimationFrame(retry);
+ if (window.ResizeObserver) {
+ observer = new ResizeObserver(retry);
+ observer.observe(viewer);
+ }
+ window.addEventListener("resize", scheduleRetry);
+ window.addEventListener("cognitive-agent:module-change", scheduleRetry);
+ scheduleRetry();
+ }
+
function initSeat3d(options) {
const {
canvasId,
@@ -15,6 +42,10 @@
const canvas = document.getElementById(canvasId);
const viewer = document.getElementById(viewerId);
if (!canvas || !viewer || viewer.dataset.seat3dInitialized === "true") return;
+ if (!viewerHasLayout(viewer)) {
+ deferSeat3dUntilVisible(viewer, options);
+ return;
+ }
viewer.dataset.seat3dInitialized = "true";
const markReady = (fallback = false) => {
@@ -387,6 +418,24 @@
camera.updateProjectionMatrix();
}
+ let viewerWasVisible = false;
+ function synchronizeViewport({ reset = false } = {}) {
+ if (!viewerHasLayout(viewer)) {
+ viewerWasVisible = false;
+ return false;
+ }
+ resize();
+ if (reset || !viewerWasVisible) resetOrbit();
+ viewerWasVisible = true;
+ return true;
+ }
+
+ const scheduleViewportSync = () => {
+ window.requestAnimationFrame(() => window.requestAnimationFrame(() => {
+ synchronizeViewport();
+ }));
+ };
+
function onHealingState(event) {
const detail = event.detail || {};
(detail.axes || []).forEach((axis) => {
@@ -404,6 +453,11 @@
function animate() {
window.requestAnimationFrame(animate);
+ if (!viewerHasLayout(viewer) || canvas.dataset.contextLost === "true") {
+ viewerWasVisible = false;
+ return;
+ }
+ if (!viewerWasVisible) synchronizeViewport({ reset: true });
for (let index = 0; index < current.axes.length; index += 1) {
current.axes[index] += (desired.axes[index] - current.axes[index]) * 0.055;
}
@@ -486,10 +540,23 @@
window.addEventListener(stateEvent, onHealingState);
window.addEventListener(resetEvent, resetOrbit);
- if (window.ResizeObserver) new ResizeObserver(resize).observe(viewer);
- window.addEventListener("resize", resize);
- resize();
- resetOrbit();
+ if (window.ResizeObserver) {
+ const resizeObserver = new ResizeObserver(() => synchronizeViewport());
+ resizeObserver.observe(viewer);
+ }
+ window.addEventListener("resize", scheduleViewportSync);
+ window.addEventListener("cognitive-agent:module-change", scheduleViewportSync);
+ canvas.addEventListener("webglcontextlost", (event) => {
+ event.preventDefault();
+ canvas.dataset.contextLost = "true";
+ viewer.classList.add("context-lost");
+ });
+ canvas.addEventListener("webglcontextrestored", () => {
+ delete canvas.dataset.contextLost;
+ viewer.classList.remove("context-lost");
+ synchronizeViewport({ reset: true });
+ });
+ synchronizeViewport({ reset: true });
animate();
window.requestAnimationFrame(() => markReady());
diff --git a/apps/web-console/service-worker.js b/apps/web-console/service-worker.js
index 4d14852..cb09d95 100644
--- a/apps/web-console/service-worker.js
+++ b/apps/web-console/service-worker.js
@@ -1,4 +1,4 @@
-const CACHE_VERSION = "cognitive-agent-pad-v116";
+const CACHE_VERSION = "cognitive-agent-pad-v117";
const SHELL_CACHE = `${CACHE_VERSION}-shell`;
const RUNTIME_CACHE = `${CACHE_VERSION}-runtime`;
const APP_SHELL = [
@@ -6,7 +6,7 @@ const APP_SHELL = [
"/index.html",
"/styles.css?v=dual-seat-9",
"/network.js?v=android-pad-1",
- "/app.js?v=dual-seat-80",
+ "/app.js?v=dual-seat-81",
"/gesture-control.js?v=android-pad-7",
"/pwa.js?v=android-pad-1",
"/console-v2.css?v=desktop-refactor-106",
@@ -17,8 +17,8 @@ const APP_SHELL = [
"/self-calibration.js?v=calibration-6",
"/self-repair.css?v=repair-21",
"/self-repair.js?v=repair-20",
- "/self-repair-seat3d.js?v=repair-18",
- "/assets/models/n7_seat.glb",
+ "/self-repair-seat3d.js?v=repair-19",
+ "/assets/models/n7_seat.glb?v=e7f50f03",
"/manifest.webmanifest",
"/icons/app-icon-192.png",
"/icons/app-icon-512.png",
diff --git a/artifacts/local-server/server.combined.log b/artifacts/local-server/server.combined.log
new file mode 100644
index 0000000..2ff5136
Binary files /dev/null and b/artifacts/local-server/server.combined.log differ
diff --git a/artifacts/local-server/server.pid b/artifacts/local-server/server.pid
new file mode 100644
index 0000000..3a909e4
--- /dev/null
+++ b/artifacts/local-server/server.pid
@@ -0,0 +1 @@
+9136
diff --git a/artifacts/local-server/server.stderr.log b/artifacts/local-server/server.stderr.log
new file mode 100644
index 0000000..e69de29
diff --git a/artifacts/local-server/server.stdout.log b/artifacts/local-server/server.stdout.log
new file mode 100644
index 0000000..e69de29
diff --git a/config/modes/vehicles/denza_n7/user/k-c78dff.yaml b/config/modes/vehicles/denza_n7/user/k-c78dff.yaml
deleted file mode 100644
index d0cfe7e..0000000
--- a/config/modes/vehicles/denza_n7/user/k-c78dff.yaml
+++ /dev/null
@@ -1,61 +0,0 @@
-id: k-c78dff
-name: K歌模式
-aliases:
-- K歌模式
-- K歌
-description: 用户固化的长期模式配置。
-icon: bookmark
-scope:
- vehicle_ids:
- - denza_n7
-operations:
-- domain: ambient_light
- capability: ambient_light.set_power
- target_scope: vehicle
- operation: activate
- parameters:
- state: 'on'
- reason: 开启氛围灯以营造K歌场景。
-- domain: ambient_light
- capability: ambient_light.set_illumination
- target_scope: vehicle
- operation: set
- parameters:
- color_hex: '#B84DFF'
- brightness_pct: 65
- reason: 使用明快紫色和中高亮度营造活跃舞台氛围。
-- domain: climate
- capability: climate.set_power
- target_scope: vehicle
- operation: activate
- parameters:
- state: 'on'
- reason: 空调当前关闭,需先开启以维持K歌时的座舱舒适度。
-- domain: climate
- capability: climate.set_temperature
- target_scope: driver
- operation: set
- parameters:
- temperature_c: 24
- reason: 采用舒适且保守的座舱温度。
-- domain: climate
- capability: climate.set_fan_level
- target_scope: vehicle
- operation: set
- parameters:
- level: 2
- reason: 采用低风量,兼顾通风并减少对歌声的干扰。
-- domain: climate
- capability: climate.set_ac
- target_scope: vehicle
- operation: activate
- parameters:
- state: 'on'
- reason: 启用制冷除湿以维持多人演唱时的舒适度。
-- domain: climate
- capability: climate.set_cycle_mode
- target_scope: vehicle
- operation: set
- parameters:
- mode: internal
- reason: 采用内循环以稳定座舱温度并减少外部噪声和气味。
diff --git a/config/modes/vehicles/denza_n7/user/mode-ceff921663.yaml b/config/modes/vehicles/denza_n7/user/mode-ceff921663.yaml
new file mode 100644
index 0000000..4a8da8e
--- /dev/null
+++ b/config/modes/vehicles/denza_n7/user/mode-ceff921663.yaml
@@ -0,0 +1,46 @@
+id: mode-ceff921663
+name: 躺平模式
+aliases:
+- 躺平模式
+- 躺平
+description: 用户固化的长期模式配置。
+icon: bookmark
+scope:
+ vehicle_ids:
+ - denza_n7
+operations:
+- domain: seat
+ capability: seat.set_longitudinal_position
+ target_scope: passenger
+ operation: set
+ parameters:
+ position_pct: 90
+ reason: 用户固化的座椅位置模式动作。
+- domain: seat
+ capability: seat.set_cushion_tilt
+ target_scope: passenger
+ operation: set
+ parameters:
+ position_pct: 40
+ reason: 用户固化的座椅位置模式动作。
+- domain: seat
+ capability: seat.set_backrest_recline
+ target_scope: passenger
+ operation: set
+ parameters:
+ position_pct: 80
+ reason: 用户固化的座椅位置模式动作。
+- domain: seat
+ capability: seat.set_legrest_height
+ target_scope: passenger
+ operation: set
+ parameters:
+ position_pct: 75
+ reason: 用户固化的座椅位置模式动作。
+- domain: seat
+ capability: seat.set_legrest_extension
+ target_scope: passenger
+ operation: set
+ parameters:
+ position_pct: 80
+ reason: 用户固化的座椅位置模式动作。
diff --git a/src/cognitive_agent/server.py b/src/cognitive_agent/server.py
index 81c129d..45388b6 100755
--- a/src/cognitive_agent/server.py
+++ b/src/cognitive_agent/server.py
@@ -243,7 +243,7 @@ class SeatDemoHandler(BaseHTTPRequestHandler):
if path.startswith("/api/requests/"):
self._serve_request(path.removeprefix("/api/requests/"))
return
- self._serve_static(path)
+ self._serve_static(path, parsed_url.query)
def do_POST(self) -> None: # noqa: N802 - stdlib handler API
path = unquote(urlparse(self.path).path)
@@ -942,17 +942,24 @@ class SeatDemoHandler(BaseHTTPRequestHandler):
return
self._json(json.loads(result_path.read_text(encoding="utf-8")))
- def _serve_static(self, path: str) -> None:
+ def _serve_static(self, path: str, query: str = "") -> None:
relative_path = "index.html" if path in {"", "/"} else path.lstrip("/")
- self._serve_static_file(relative_path)
+ versioned = bool(parse_qs(query).get("v"))
+ self._serve_static_file(relative_path, versioned=versioned)
- def _serve_static_file(self, relative_path: str) -> None:
+ def _serve_static_file(self, relative_path: str, *, versioned: bool = False) -> None:
candidate = (STATIC_ROOT / relative_path).resolve()
try:
candidate.relative_to(STATIC_ROOT.resolve())
except ValueError:
self._json({"error": "not_found"}, HTTPStatus.NOT_FOUND)
return
+ if not candidate.is_file() and (
+ Path(relative_path).suffix
+ or relative_path.startswith(("assets/", "vendor/", "icons/"))
+ ):
+ self._json({"error": "not_found"}, HTTPStatus.NOT_FOUND)
+ return
if not candidate.is_file():
candidate = STATIC_ROOT / "index.html"
content_type, _ = mimetypes.guess_type(candidate.name)
@@ -972,8 +979,12 @@ class SeatDemoHandler(BaseHTTPRequestHandler):
)
self.send_header("Content-Length", str(len(content)))
cache_control = "no-cache"
- if relative_path.startswith(("vendor/", "assets/", "icons/")):
+ if relative_path.startswith(("vendor/", "icons/")) or (
+ relative_path.startswith("assets/") and versioned
+ ):
cache_control = "public, max-age=31536000, immutable"
+ elif relative_path.startswith("assets/"):
+ cache_control = "no-cache"
elif candidate.name in {"index.html", "login.html", "service-worker.js"}:
cache_control = "no-cache"
self.send_header("Cache-Control", cache_control)
diff --git a/tests/e2e/test_seat_web_api.py b/tests/e2e/test_seat_web_api.py
index 4942e30..adcfea5 100755
--- a/tests/e2e/test_seat_web_api.py
+++ b/tests/e2e/test_seat_web_api.py
@@ -177,7 +177,7 @@ operations:
def test_static_console_and_runtime_endpoint(self) -> None:
with self.opener.open(f"{self.base_url}/", timeout=3) as response:
html = response.read().decode("utf-8")
- with self.opener.open(f"{self.base_url}/app.js?v=dual-seat-80", timeout=3) as response:
+ with self.opener.open(f"{self.base_url}/app.js?v=dual-seat-81", timeout=3) as response:
app_script = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/gesture-control.js?v=android-pad-7", timeout=3
@@ -199,6 +199,10 @@ operations:
f"{self.base_url}/self-extension.css?v=extension-18", timeout=3
) as response:
extension_styles = response.read().decode("utf-8").replace("\r\n", "\n")
+ with self.opener.open(
+ f"{self.base_url}/service-worker.js", timeout=3
+ ) as response:
+ service_worker = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/api/extension/health", timeout=3
) as response:
@@ -219,7 +223,7 @@ operations:
self.assertIn("CMD 0x431 · FB 0x41A · CH1", html)
self.assertIn("CMD 0x431 · FB 0x388 · CH1", html)
self.assertNotIn("透明车体 · 实体设备", html)
- self.assertIn('src="/app.js?v=dual-seat-80"', html)
+ self.assertIn('src="/app.js?v=dual-seat-81"', html)
self.assertIn('href="/styles.css?v=dual-seat-9"', html)
self.assertIn('src="/gesture-control.js?v=android-pad-7"', html)
self.assertNotIn('class="vehicle-system-hud"', html)
@@ -438,6 +442,23 @@ operations:
self.assertIn("function createReferenceFrontLampHighlights", app_script)
self.assertIn("referenceFrontLampMaterials", app_script)
self.assertIn("targets.windowPositions", app_script)
+ self.assertIn(
+ 'const REFERENCE_VEHICLE_ASSET_VERSION = "77a0fae7"', app_script
+ )
+ self.assertIn(
+ "const REFERENCE_VEHICLE_LOAD_TIMEOUT_MS = 30000", app_script
+ )
+ self.assertIn(
+ 'referenceVehicleAssetUrl("byd-tang-2024.fbx")', app_script
+ )
+ self.assertIn("const stageHasLayout = () =>", app_script)
+ self.assertIn("window.requestAnimationFrame(initSeatTwin)", app_script)
+ self.assertIn('canvas.addEventListener("webglcontextlost"', app_script)
+ self.assertIn('"cognitive-agent:module-change"', app_script)
+ self.assertIn('const CACHE_VERSION = "cognitive-agent-pad-v117"', service_worker)
+ self.assertIn(
+ '"/assets/models/n7_seat.glb?v=e7f50f03"', service_worker
+ )
self.assertIn("hardware_access_required", app_script)
self.assertIn('button.setAttribute("aria-label", "关闭摄像头")', gesture_script)
self.assertIn("function refreshCameraAvailability", gesture_script)
@@ -647,7 +668,7 @@ operations:
) as response:
extension_script = response.read().decode("utf-8")
with self.opener.open(
- f"{self.base_url}/app.js?v=dual-seat-80", timeout=3
+ f"{self.base_url}/app.js?v=dual-seat-81", timeout=3
) as response:
app_script = response.read().decode("utf-8")
diff --git a/tests/e2e/test_self_calibration_api.py b/tests/e2e/test_self_calibration_api.py
index 4f9b7b0..f7b35fa 100644
--- a/tests/e2e/test_self_calibration_api.py
+++ b/tests/e2e/test_self_calibration_api.py
@@ -147,6 +147,18 @@ class TestSelfCalibrationApi:
model = response.read()
content_type = response.headers["Content-Type"]
content_security_policy = response.headers["Content-Security-Policy"]
+ unversioned_cache_control = response.headers["Cache-Control"]
+ with urllib.request.urlopen(
+ f"{self.base_url}/assets/models/n7_seat.glb?v=e7f50f03",
+ timeout=3,
+ ) as response:
+ versioned_model_prefix = response.read(4)
+ versioned_cache_control = response.headers["Cache-Control"]
+ with pytest.raises(urllib.error.HTTPError) as missing_model:
+ urllib.request.urlopen(
+ f"{self.base_url}/assets/models/missing-seat.glb?v=missing",
+ timeout=3,
+ )
assert 'href="/self-calibration.css?v=calibration-10"' in html
assert 'src="/self-calibration.js?v=calibration-6"' in html
@@ -173,6 +185,10 @@ class TestSelfCalibrationApi:
assert '["self-calibration", "self-repair"].includes(module)' in console_script
assert 'setRole("admin", { allowModuleTransition: true })' in console_script
assert len(model) == 845_992
+ assert versioned_model_prefix == model[:4]
assert content_type.startswith("model/gltf-binary")
+ assert unversioned_cache_control == "no-cache"
+ assert versioned_cache_control == "public, max-age=31536000, immutable"
+ assert missing_model.value.code == 404
assert "img-src 'self' data: blob:;" in content_security_policy
assert "connect-src 'self' blob:;" in content_security_policy
diff --git a/tests/e2e/test_self_repair_api.py b/tests/e2e/test_self_repair_api.py
index 9bc020a..f599142 100644
--- a/tests/e2e/test_self_repair_api.py
+++ b/tests/e2e/test_self_repair_api.py
@@ -154,7 +154,7 @@ class TestSelfRepairApi:
) as response:
styles = response.read().decode("utf-8")
with urllib.request.urlopen(
- f"{self.base_url}/self-repair-seat3d.js?v=repair-18", timeout=3
+ f"{self.base_url}/self-repair-seat3d.js?v=repair-19", timeout=3
) as response:
seat3d = response.read().decode("utf-8")
with urllib.request.urlopen(
@@ -168,7 +168,7 @@ class TestSelfRepairApi:
assert 'SELF-REPAIR' in script
assert 'padding: var(--v2-module-title-block) 0 0' in styles
assert 'margin-inline: var(--v2-module-title-inline)' in styles
- assert 'src="/self-repair-seat3d.js?v=repair-18"' in html
+ assert 'src="/self-repair-seat3d.js?v=repair-19"' in html
assert "量产故障注入" in script
assert "运行与自修复日志" in script
assert "启动座椅运行" in script
@@ -203,6 +203,11 @@ class TestSelfRepairApi:
assert 'viewer.addEventListener("pointerdown"' in seat3d
assert 'window.addEventListener("pointermove"' in seat3d
assert "window.addEventListener(resetEvent" in seat3d
+ assert "function viewerHasLayout(viewer)" in seat3d
+ assert "function deferSeat3dUntilVisible(viewer, options)" in seat3d
+ assert "if (!viewerHasLayout(viewer))" in seat3d
+ assert 'window.addEventListener("cognitive-agent:module-change"' in seat3d
+ assert 'canvas.addEventListener("webglcontextlost"' in seat3d
assert '["self-calibration", "self-repair"].includes(module)' in console_script
assert 'roleSelect.disabled = ui.activeModule === "self-repair"' in console_script
diff --git a/tmp/pytest-feature-dynamic-mode-push/test_bridge_manager_does_not_r0/bridge.json b/tmp/pytest-feature-dynamic-mode-push/test_bridge_manager_does_not_r0/bridge.json
new file mode 100644
index 0000000..6938bfd
--- /dev/null
+++ b/tmp/pytest-feature-dynamic-mode-push/test_bridge_manager_does_not_r0/bridge.json
@@ -0,0 +1 @@
+{"heartbeat_epoch": 1786612896.954201, "bridge_state": "RUNNING", "current_request_id": "SELF_HEAL_BENCH_1"}
\ No newline at end of file
diff --git a/tmp/pytest-feature-dynamic-mode-push/test_standalone_runtime_opens_0/python.exe b/tmp/pytest-feature-dynamic-mode-push/test_standalone_runtime_opens_0/python.exe
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/tmp/pytest-feature-dynamic-mode-push/test_standalone_runtime_opens_0/python.exe
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/tmp/pytest-feature-dynamic-mode-push/test_standalone_runtime_opens_0/seat_bridge.py b/tmp/pytest-feature-dynamic-mode-push/test_standalone_runtime_opens_0/seat_bridge.py
new file mode 100644
index 0000000..6c284f1
--- /dev/null
+++ b/tmp/pytest-feature-dynamic-mode-push/test_standalone_runtime_opens_0/seat_bridge.py
@@ -0,0 +1,3 @@
+BRIDGE_VERSION = 'runtime-test-v1'
+def run_bridge(transport=None, stop_event=None):
+ stop_event.wait(2.0)
diff --git a/tmp/pytest-feature-dynamic-mode-push/test_standalone_runtime_opens_0/zlg_bridge.py b/tmp/pytest-feature-dynamic-mode-push/test_standalone_runtime_opens_0/zlg_bridge.py
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/tmp/pytest-feature-dynamic-mode-push/test_standalone_runtime_opens_0/zlg_bridge.py
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/tmp/pytest-feature-dynamic-mode-push/test_standalone_runtime_opens_0/zlgcan.dll b/tmp/pytest-feature-dynamic-mode-push/test_standalone_runtime_opens_0/zlgcan.dll
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/tmp/pytest-feature-dynamic-mode-push/test_standalone_runtime_opens_0/zlgcan.dll
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/tmp/pytest-feature-dynamic-mode-push/test_standalone_runtime_reject0/status.json b/tmp/pytest-feature-dynamic-mode-push/test_standalone_runtime_reject0/status.json
new file mode 100644
index 0000000..f4505df
--- /dev/null
+++ b/tmp/pytest-feature-dynamic-mode-push/test_standalone_runtime_reject0/status.json
@@ -0,0 +1 @@
+{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786612902.0072305, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 15, "qualified": false}, "frame_epochs": {"0x301": 1786612902.0072305, "0x302": 1786612902.0072305, "0x303": 1786612902.0072305, "0x304": 1786612902.0072305, "0x305": 1786612902.0072305, "0x306": 1786612902.0072305, "0x307": 1786612902.0072305}}
\ No newline at end of file
diff --git a/tmp/pytest-feature-dynamic-mode-push/test_standalone_runtime_restor0/status.json b/tmp/pytest-feature-dynamic-mode-push/test_standalone_runtime_restor0/status.json
new file mode 100644
index 0000000..e654981
--- /dev/null
+++ b/tmp/pytest-feature-dynamic-mode-push/test_standalone_runtime_restor0/status.json
@@ -0,0 +1 @@
+{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786612902.1554296, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 16, "qualified": true}, "frame_epochs": {"0x301": 1786612902.1554296, "0x302": 1786612902.1554296, "0x303": 1786612902.1554296, "0x304": 1786612902.1554296, "0x305": 1786612902.1554296, "0x306": 1786612902.1554296, "0x307": 1786612902.1554296}}
\ No newline at end of file
diff --git a/tmp/pytest-rebase-resolution-2/test_bridge_manager_does_not_r0/bridge.json b/tmp/pytest-rebase-resolution-2/test_bridge_manager_does_not_r0/bridge.json
new file mode 100644
index 0000000..9c8db28
--- /dev/null
+++ b/tmp/pytest-rebase-resolution-2/test_bridge_manager_does_not_r0/bridge.json
@@ -0,0 +1 @@
+{"heartbeat_epoch": 1786614297.8563914, "bridge_state": "RUNNING", "current_request_id": "SELF_HEAL_BENCH_1"}
\ No newline at end of file
diff --git a/tmp/pytest-rebase-resolution-2/test_standalone_runtime_opens_0/python.exe b/tmp/pytest-rebase-resolution-2/test_standalone_runtime_opens_0/python.exe
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/tmp/pytest-rebase-resolution-2/test_standalone_runtime_opens_0/python.exe
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/tmp/pytest-rebase-resolution-2/test_standalone_runtime_opens_0/seat_bridge.py b/tmp/pytest-rebase-resolution-2/test_standalone_runtime_opens_0/seat_bridge.py
new file mode 100644
index 0000000..6c284f1
--- /dev/null
+++ b/tmp/pytest-rebase-resolution-2/test_standalone_runtime_opens_0/seat_bridge.py
@@ -0,0 +1,3 @@
+BRIDGE_VERSION = 'runtime-test-v1'
+def run_bridge(transport=None, stop_event=None):
+ stop_event.wait(2.0)
diff --git a/tmp/pytest-rebase-resolution-2/test_standalone_runtime_opens_0/zlg_bridge.py b/tmp/pytest-rebase-resolution-2/test_standalone_runtime_opens_0/zlg_bridge.py
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/tmp/pytest-rebase-resolution-2/test_standalone_runtime_opens_0/zlg_bridge.py
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/tmp/pytest-rebase-resolution-2/test_standalone_runtime_opens_0/zlgcan.dll b/tmp/pytest-rebase-resolution-2/test_standalone_runtime_opens_0/zlgcan.dll
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/tmp/pytest-rebase-resolution-2/test_standalone_runtime_opens_0/zlgcan.dll
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/tmp/pytest-rebase-resolution-2/test_standalone_runtime_reject0/status.json b/tmp/pytest-rebase-resolution-2/test_standalone_runtime_reject0/status.json
new file mode 100644
index 0000000..b7499c2
--- /dev/null
+++ b/tmp/pytest-rebase-resolution-2/test_standalone_runtime_reject0/status.json
@@ -0,0 +1 @@
+{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786614302.9093528, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 15, "qualified": false}, "frame_epochs": {"0x301": 1786614302.9093528, "0x302": 1786614302.9093528, "0x303": 1786614302.9093528, "0x304": 1786614302.9093528, "0x305": 1786614302.9093528, "0x306": 1786614302.9093528, "0x307": 1786614302.9093528}}
\ No newline at end of file
diff --git a/tmp/pytest-rebase-resolution-2/test_standalone_runtime_restor0/status.json b/tmp/pytest-rebase-resolution-2/test_standalone_runtime_restor0/status.json
new file mode 100644
index 0000000..d811a48
--- /dev/null
+++ b/tmp/pytest-rebase-resolution-2/test_standalone_runtime_restor0/status.json
@@ -0,0 +1 @@
+{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786614303.057585, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 16, "qualified": true}, "frame_epochs": {"0x301": 1786614303.057585, "0x302": 1786614303.057585, "0x303": 1786614303.057585, "0x304": 1786614303.057585, "0x305": 1786614303.057585, "0x306": 1786614303.057585, "0x307": 1786614303.057585}}
\ No newline at end of file
diff --git a/tmp/pytest-rebase-resolution/test_bridge_manager_does_not_r0/bridge.json b/tmp/pytest-rebase-resolution/test_bridge_manager_does_not_r0/bridge.json
new file mode 100644
index 0000000..aee58ce
--- /dev/null
+++ b/tmp/pytest-rebase-resolution/test_bridge_manager_does_not_r0/bridge.json
@@ -0,0 +1 @@
+{"heartbeat_epoch": 1786614211.5981486, "bridge_state": "RUNNING", "current_request_id": "SELF_HEAL_BENCH_1"}
\ No newline at end of file
diff --git a/tmp/pytest-rebase-resolution/test_standalone_runtime_opens_0/python.exe b/tmp/pytest-rebase-resolution/test_standalone_runtime_opens_0/python.exe
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/tmp/pytest-rebase-resolution/test_standalone_runtime_opens_0/python.exe
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/tmp/pytest-rebase-resolution/test_standalone_runtime_opens_0/seat_bridge.py b/tmp/pytest-rebase-resolution/test_standalone_runtime_opens_0/seat_bridge.py
new file mode 100644
index 0000000..6c284f1
--- /dev/null
+++ b/tmp/pytest-rebase-resolution/test_standalone_runtime_opens_0/seat_bridge.py
@@ -0,0 +1,3 @@
+BRIDGE_VERSION = 'runtime-test-v1'
+def run_bridge(transport=None, stop_event=None):
+ stop_event.wait(2.0)
diff --git a/tmp/pytest-rebase-resolution/test_standalone_runtime_opens_0/zlg_bridge.py b/tmp/pytest-rebase-resolution/test_standalone_runtime_opens_0/zlg_bridge.py
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/tmp/pytest-rebase-resolution/test_standalone_runtime_opens_0/zlg_bridge.py
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/tmp/pytest-rebase-resolution/test_standalone_runtime_opens_0/zlgcan.dll b/tmp/pytest-rebase-resolution/test_standalone_runtime_opens_0/zlgcan.dll
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/tmp/pytest-rebase-resolution/test_standalone_runtime_opens_0/zlgcan.dll
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/tmp/pytest-rebase-resolution/test_standalone_runtime_reject0/status.json b/tmp/pytest-rebase-resolution/test_standalone_runtime_reject0/status.json
new file mode 100644
index 0000000..3243a72
--- /dev/null
+++ b/tmp/pytest-rebase-resolution/test_standalone_runtime_reject0/status.json
@@ -0,0 +1 @@
+{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786614216.6407876, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 15, "qualified": false}, "frame_epochs": {"0x301": 1786614216.6407876, "0x302": 1786614216.6407876, "0x303": 1786614216.6407876, "0x304": 1786614216.6407876, "0x305": 1786614216.6407876, "0x306": 1786614216.6407876, "0x307": 1786614216.6407876}}
\ No newline at end of file
diff --git a/tmp/pytest-rebase-resolution/test_standalone_runtime_restor0/status.json b/tmp/pytest-rebase-resolution/test_standalone_runtime_restor0/status.json
new file mode 100644
index 0000000..c62eff2
--- /dev/null
+++ b/tmp/pytest-rebase-resolution/test_standalone_runtime_restor0/status.json
@@ -0,0 +1 @@
+{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786614216.7809346, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 16, "qualified": true}, "frame_epochs": {"0x301": 1786614216.7809346, "0x302": 1786614216.7809346, "0x303": 1786614216.7809346, "0x304": 1786614216.7809346, "0x305": 1786614216.7809346, "0x306": 1786614216.7809346, "0x307": 1786614216.7809346}}
\ No newline at end of file
diff --git a/tmp/pytest-self-orchestration-fix-20260813/test_bridge_manager_does_not_r0/bridge.json b/tmp/pytest-self-orchestration-fix-20260813/test_bridge_manager_does_not_r0/bridge.json
new file mode 100644
index 0000000..9563725
--- /dev/null
+++ b/tmp/pytest-self-orchestration-fix-20260813/test_bridge_manager_does_not_r0/bridge.json
@@ -0,0 +1 @@
+{"heartbeat_epoch": 1786628979.608127, "bridge_state": "RUNNING", "current_request_id": "SELF_HEAL_BENCH_1"}
\ No newline at end of file
diff --git a/tmp/pytest-self-orchestration-fix-20260813/test_standalone_runtime_opens_0/python.exe b/tmp/pytest-self-orchestration-fix-20260813/test_standalone_runtime_opens_0/python.exe
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/tmp/pytest-self-orchestration-fix-20260813/test_standalone_runtime_opens_0/python.exe
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/tmp/pytest-self-orchestration-fix-20260813/test_standalone_runtime_opens_0/seat_bridge.py b/tmp/pytest-self-orchestration-fix-20260813/test_standalone_runtime_opens_0/seat_bridge.py
new file mode 100644
index 0000000..6c284f1
--- /dev/null
+++ b/tmp/pytest-self-orchestration-fix-20260813/test_standalone_runtime_opens_0/seat_bridge.py
@@ -0,0 +1,3 @@
+BRIDGE_VERSION = 'runtime-test-v1'
+def run_bridge(transport=None, stop_event=None):
+ stop_event.wait(2.0)
diff --git a/tmp/pytest-self-orchestration-fix-20260813/test_standalone_runtime_opens_0/zlg_bridge.py b/tmp/pytest-self-orchestration-fix-20260813/test_standalone_runtime_opens_0/zlg_bridge.py
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/tmp/pytest-self-orchestration-fix-20260813/test_standalone_runtime_opens_0/zlg_bridge.py
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/tmp/pytest-self-orchestration-fix-20260813/test_standalone_runtime_opens_0/zlgcan.dll b/tmp/pytest-self-orchestration-fix-20260813/test_standalone_runtime_opens_0/zlgcan.dll
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/tmp/pytest-self-orchestration-fix-20260813/test_standalone_runtime_opens_0/zlgcan.dll
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/tmp/pytest-self-orchestration-fix-20260813/test_standalone_runtime_reject0/status.json b/tmp/pytest-self-orchestration-fix-20260813/test_standalone_runtime_reject0/status.json
new file mode 100644
index 0000000..0620643
--- /dev/null
+++ b/tmp/pytest-self-orchestration-fix-20260813/test_standalone_runtime_reject0/status.json
@@ -0,0 +1 @@
+{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786628984.6589825, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 15, "qualified": false}, "frame_epochs": {"0x301": 1786628984.6589825, "0x302": 1786628984.6589825, "0x303": 1786628984.6589825, "0x304": 1786628984.6589825, "0x305": 1786628984.6589825, "0x306": 1786628984.6589825, "0x307": 1786628984.6589825}}
\ No newline at end of file
diff --git a/tmp/pytest-self-orchestration-fix-20260813/test_standalone_runtime_restor0/status.json b/tmp/pytest-self-orchestration-fix-20260813/test_standalone_runtime_restor0/status.json
new file mode 100644
index 0000000..634e685
--- /dev/null
+++ b/tmp/pytest-self-orchestration-fix-20260813/test_standalone_runtime_restor0/status.json
@@ -0,0 +1 @@
+{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786628984.8052018, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 16, "qualified": true}, "frame_epochs": {"0x301": 1786628984.8052018, "0x302": 1786628984.8052018, "0x303": 1786628984.8052018, "0x304": 1786628984.8052018, "0x305": 1786628984.8052018, "0x306": 1786628984.8052018, "0x307": 1786628984.8052018}}
\ No newline at end of file
diff --git a/tmp/pytest-self-repair-redesign-final-2/test_bridge_manager_does_not_r0/bridge.json b/tmp/pytest-self-repair-redesign-final-2/test_bridge_manager_does_not_r0/bridge.json
new file mode 100644
index 0000000..b8abc4d
--- /dev/null
+++ b/tmp/pytest-self-repair-redesign-final-2/test_bridge_manager_does_not_r0/bridge.json
@@ -0,0 +1 @@
+{"heartbeat_epoch": 1786608369.3573637, "bridge_state": "RUNNING", "current_request_id": "SELF_HEAL_BENCH_1"}
\ No newline at end of file
diff --git a/tmp/pytest-self-repair-redesign-final-2/test_standalone_runtime_opens_0/python.exe b/tmp/pytest-self-repair-redesign-final-2/test_standalone_runtime_opens_0/python.exe
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/tmp/pytest-self-repair-redesign-final-2/test_standalone_runtime_opens_0/python.exe
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/tmp/pytest-self-repair-redesign-final-2/test_standalone_runtime_opens_0/seat_bridge.py b/tmp/pytest-self-repair-redesign-final-2/test_standalone_runtime_opens_0/seat_bridge.py
new file mode 100644
index 0000000..6c284f1
--- /dev/null
+++ b/tmp/pytest-self-repair-redesign-final-2/test_standalone_runtime_opens_0/seat_bridge.py
@@ -0,0 +1,3 @@
+BRIDGE_VERSION = 'runtime-test-v1'
+def run_bridge(transport=None, stop_event=None):
+ stop_event.wait(2.0)
diff --git a/tmp/pytest-self-repair-redesign-final-2/test_standalone_runtime_opens_0/zlg_bridge.py b/tmp/pytest-self-repair-redesign-final-2/test_standalone_runtime_opens_0/zlg_bridge.py
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/tmp/pytest-self-repair-redesign-final-2/test_standalone_runtime_opens_0/zlg_bridge.py
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/tmp/pytest-self-repair-redesign-final-2/test_standalone_runtime_opens_0/zlgcan.dll b/tmp/pytest-self-repair-redesign-final-2/test_standalone_runtime_opens_0/zlgcan.dll
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/tmp/pytest-self-repair-redesign-final-2/test_standalone_runtime_opens_0/zlgcan.dll
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/tmp/pytest-self-repair-redesign-final-2/test_standalone_runtime_reject0/status.json b/tmp/pytest-self-repair-redesign-final-2/test_standalone_runtime_reject0/status.json
new file mode 100644
index 0000000..f88f41d
--- /dev/null
+++ b/tmp/pytest-self-repair-redesign-final-2/test_standalone_runtime_reject0/status.json
@@ -0,0 +1 @@
+{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786608374.4077742, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 15, "qualified": false}, "frame_epochs": {"0x301": 1786608374.4077742, "0x302": 1786608374.4077742, "0x303": 1786608374.4077742, "0x304": 1786608374.4077742, "0x305": 1786608374.4077742, "0x306": 1786608374.4077742, "0x307": 1786608374.4077742}}
\ No newline at end of file
diff --git a/tmp/pytest-self-repair-redesign-final-2/test_standalone_runtime_restor0/status.json b/tmp/pytest-self-repair-redesign-final-2/test_standalone_runtime_restor0/status.json
new file mode 100644
index 0000000..8df1726
--- /dev/null
+++ b/tmp/pytest-self-repair-redesign-final-2/test_standalone_runtime_restor0/status.json
@@ -0,0 +1 @@
+{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786608374.5544136, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 16, "qualified": true}, "frame_epochs": {"0x301": 1786608374.5544136, "0x302": 1786608374.5544136, "0x303": 1786608374.5544136, "0x304": 1786608374.5544136, "0x305": 1786608374.5544136, "0x306": 1786608374.5544136, "0x307": 1786608374.5544136}}
\ No newline at end of file
diff --git a/tmp/pytest-self-repair-redesign/test_bridge_manager_does_not_r0/bridge.json b/tmp/pytest-self-repair-redesign/test_bridge_manager_does_not_r0/bridge.json
new file mode 100644
index 0000000..bad4b5c
--- /dev/null
+++ b/tmp/pytest-self-repair-redesign/test_bridge_manager_does_not_r0/bridge.json
@@ -0,0 +1 @@
+{"heartbeat_epoch": 1786607635.6544752, "bridge_state": "RUNNING", "current_request_id": "SELF_HEAL_BENCH_1"}
\ No newline at end of file
diff --git a/tmp/pytest-self-repair-redesign/test_standalone_runtime_opens_0/python.exe b/tmp/pytest-self-repair-redesign/test_standalone_runtime_opens_0/python.exe
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/tmp/pytest-self-repair-redesign/test_standalone_runtime_opens_0/python.exe
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/tmp/pytest-self-repair-redesign/test_standalone_runtime_opens_0/seat_bridge.py b/tmp/pytest-self-repair-redesign/test_standalone_runtime_opens_0/seat_bridge.py
new file mode 100644
index 0000000..6c284f1
--- /dev/null
+++ b/tmp/pytest-self-repair-redesign/test_standalone_runtime_opens_0/seat_bridge.py
@@ -0,0 +1,3 @@
+BRIDGE_VERSION = 'runtime-test-v1'
+def run_bridge(transport=None, stop_event=None):
+ stop_event.wait(2.0)
diff --git a/tmp/pytest-self-repair-redesign/test_standalone_runtime_opens_0/zlg_bridge.py b/tmp/pytest-self-repair-redesign/test_standalone_runtime_opens_0/zlg_bridge.py
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/tmp/pytest-self-repair-redesign/test_standalone_runtime_opens_0/zlg_bridge.py
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/tmp/pytest-self-repair-redesign/test_standalone_runtime_opens_0/zlgcan.dll b/tmp/pytest-self-repair-redesign/test_standalone_runtime_opens_0/zlgcan.dll
new file mode 100644
index 0000000..30d74d2
--- /dev/null
+++ b/tmp/pytest-self-repair-redesign/test_standalone_runtime_opens_0/zlgcan.dll
@@ -0,0 +1 @@
+test
\ No newline at end of file
diff --git a/tmp/pytest-self-repair-redesign/test_standalone_runtime_reject0/status.json b/tmp/pytest-self-repair-redesign/test_standalone_runtime_reject0/status.json
new file mode 100644
index 0000000..36ecd6f
--- /dev/null
+++ b/tmp/pytest-self-repair-redesign/test_standalone_runtime_reject0/status.json
@@ -0,0 +1 @@
+{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786607640.7259998, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 15, "qualified": false}, "frame_epochs": {"0x301": 1786607640.7259998, "0x302": 1786607640.7259998, "0x303": 1786607640.7259998, "0x304": 1786607640.7259998, "0x305": 1786607640.7259998, "0x306": 1786607640.7259998, "0x307": 1786607640.7259998}}
\ No newline at end of file
diff --git a/tmp/pytest-self-repair-redesign/test_standalone_runtime_restor0/status.json b/tmp/pytest-self-repair-redesign/test_standalone_runtime_restor0/status.json
new file mode 100644
index 0000000..f2d3488
--- /dev/null
+++ b/tmp/pytest-self-repair-redesign/test_standalone_runtime_restor0/status.json
@@ -0,0 +1 @@
+{"bridge_version": "runtime-test-v1", "heartbeat_epoch": 1786607640.8686898, "current_request_id": null, "system": {"firmware_revision": 15}, "firmware_identity": {"firmware_build_id": 16, "qualified": true}, "frame_epochs": {"0x301": 1786607640.8686898, "0x302": 1786607640.8686898, "0x303": 1786607640.8686898, "0x304": 1786607640.8686898, "0x305": 1786607640.8686898, "0x306": 1786607640.8686898, "0x307": 1786607640.8686898}}
\ No newline at end of file