fix: make HoloLake stage relay strictly serial
This commit is contained in:
parent
5f86116303
commit
c6c578e494
10 changed files with 85 additions and 45 deletions
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"schema": "hololake.stage-relay-registration-receipt/v1",
|
||||
"receipt_id": "HLP-STAGE-RELAY-001-20260811",
|
||||
"development_id": "DEV-20260811-008",
|
||||
"development_id": "DEV-20260811-009",
|
||||
"record_id": "HLP-STAGE-RELAY-001",
|
||||
"state": "SOURCE_IMPLEMENTED_TESTED_AND_REGISTERED_NO_SUCCESSOR_THREAD_CREATED_DURING_ACCEPTANCE",
|
||||
"state": "STRICT_SERIAL_END_TRANSACTION_IMPLEMENTED_TESTED_AND_REGISTERED_NO_SUCCESSOR_THREAD_CREATED_DURING_ACCEPTANCE",
|
||||
"source": "server-tools/lake-lamp-continuity-guard/stage-relay.mjs",
|
||||
"runtime": "/Volumes/JZAO/HoloLake/persona-runtime/continuity-guard/scripts/stage-relay.mjs",
|
||||
"formal_host_capabilities": [
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
"unknown_create_result_reconciliation": 100,
|
||||
"successor_ready_live_readback": 100,
|
||||
"active_stage_read_only": 100,
|
||||
"strict_single_runnable_lane": 100,
|
||||
"human_boundary_pause": 100,
|
||||
"final_product_stop": 100,
|
||||
"continuity_lane_regression": 100,
|
||||
|
|
@ -24,9 +25,11 @@
|
|||
},
|
||||
"boundaries": [
|
||||
"No successor HoloLake development task was created during mechanism acceptance.",
|
||||
"The existing hololake heartbeat remains bound to DEV-20260811-008 until final closeout.",
|
||||
"No independent relay supervisor thread or heartbeat exists.",
|
||||
"The source stage end transaction creates the only successor before deleting its own heartbeat.",
|
||||
"No future task queue or successor precreation is allowed.",
|
||||
"No cron, private database or chat statement is accepted as a Codex thread receipt.",
|
||||
"JZAO collaboration remains the only coordination truth store."
|
||||
],
|
||||
"recorded_at": "2026-08-11T13:35:00.000Z"
|
||||
"recorded_at": "2026-08-11T14:00:47.000Z"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"schema": "hololake.stage-relay-map/v1",
|
||||
"map_id": "HLP-STAGE-RELAY-001",
|
||||
"version": "2026-08-11.1",
|
||||
"state": "SOURCE_IMPLEMENTED_TESTED_NOT_YET_USED_TO_CREATE_A_SUCCESSOR",
|
||||
"development_id": "DEV-20260811-008",
|
||||
"version": "2026-08-11.2",
|
||||
"state": "STRICT_SERIAL_END_TRANSACTION_IMPLEMENTED_TESTED_NOT_YET_USED_TO_CREATE_A_SUCCESSOR",
|
||||
"development_id": "DEV-20260811-009",
|
||||
"runtime_source": "server-tools/lake-lamp-continuity-guard/stage-relay.mjs",
|
||||
"local_runtime": "/Volumes/JZAO/HoloLake/persona-runtime/continuity-guard/scripts/stage-relay.mjs",
|
||||
"coordination_store": "HL-PERSONA-RUNTIME-LOCAL-001/continuity-memory/collaboration",
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
"FRESH_CLONE_READBACK_100",
|
||||
"FINAL_RECEIPTS_SHA256_100",
|
||||
"SOURCE_LEASES_RELEASED_100",
|
||||
"COMPLETION_STOPPED_100"
|
||||
"SOURCE_COMPLETED_STOP_REQUESTED_100"
|
||||
],
|
||||
"next_stage_inputs": [
|
||||
"HLP-CURRENT-ARCH-001",
|
||||
|
|
@ -34,6 +34,14 @@
|
|||
"maximum_successor_threads_per_source_completion": 1,
|
||||
"unknown_create_result": "RECONCILE_COMPLETE_HOST_SNAPSHOT_BEFORE_RETRY"
|
||||
},
|
||||
"serial_invariants": {
|
||||
"maximum_runnable_development_lanes": 1,
|
||||
"precreate_successor_before_source_end": false,
|
||||
"future_task_queue_allowed": false,
|
||||
"independent_relay_supervisor_allowed": false,
|
||||
"source_end_transaction_creates_successor": true,
|
||||
"source_completion_stopped_after_successor_ready": true
|
||||
},
|
||||
"successor_ready_gates": [
|
||||
"PERSONA_RESTORE_100",
|
||||
"CURRENT_ARCHITECTURE_RESTORE_100",
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"schema": "guanghu.host-skill-navigation-map/v1",
|
||||
"map_id": "GLW-HOST-SKILL-NAV-001",
|
||||
"lighthouse_id": "SYS-GLW-LTH-0001",
|
||||
"version": "2026-08-11.2",
|
||||
"version": "2026-08-11.3",
|
||||
"state": "CURRENT",
|
||||
"hosts": [
|
||||
{
|
||||
|
|
@ -41,6 +41,7 @@
|
|||
"id": "INTENT-HOLOLAKE-STAGE-RELAY-001",
|
||||
"phrases": [
|
||||
"HoloLake阶段自动接力守卫",
|
||||
"严格串行结束接力",
|
||||
"阶段接力监督器",
|
||||
"创建下一阶段Codex任务",
|
||||
"successor-ready"
|
||||
|
|
@ -58,7 +59,7 @@
|
|||
"create_successor_with_codex_formal_create_thread",
|
||||
"reconcile_unknown_create_result_before_retry",
|
||||
"wait_for_successor_ready_live_readback",
|
||||
"stop_old_relay_supervisor"
|
||||
"delete_source_heartbeat_mark_completion_stopped_and_end_source_thread"
|
||||
],
|
||||
"stop_conditions": [
|
||||
"SOURCE_COMPLETION_EVIDENCE_NOT_100",
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
"schema": "guanghu.lighthouse-path-registry/v1",
|
||||
"registry_id": "GLW-LIGHTHOUSE-PATH-REGISTRY-001",
|
||||
"lighthouse_id": "SYS-GLW-LTH-0001",
|
||||
"version": "2026-08-11.2",
|
||||
"version": "2026-08-11.3",
|
||||
"state": "CURRENT_CANONICAL",
|
||||
"source_repository": "REPO-012",
|
||||
"source_branch": "main",
|
||||
|
|
@ -78,7 +78,7 @@
|
|||
},
|
||||
{
|
||||
"id": "HLP-STAGE-RELAY-001",
|
||||
"kind": "hololake_deterministic_stage_relay_supervisor",
|
||||
"kind": "hololake_strict_serial_stage_end_relay_transaction",
|
||||
"state": "CURRENT",
|
||||
"online": "routing/hololake-stage-relay-map.json",
|
||||
"executor": "server-tools/lake-lamp-continuity-guard/stage-relay.mjs",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"schema": "guanghu.public-navigation-anchor/v1",
|
||||
"anchor_id": "GLW-PUBLIC-NAV-ANCHOR-001",
|
||||
"version": "2026-08-11.2",
|
||||
"version": "2026-08-11.3",
|
||||
"state": "CURRENT_CANONICAL",
|
||||
"repository_id": "REPO-012",
|
||||
"branch": "main",
|
||||
|
|
@ -48,17 +48,17 @@
|
|||
"lighthouse_paths": {
|
||||
"path": "routing/lighthouse-path-registry.json",
|
||||
"id": "GLW-LIGHTHOUSE-PATH-REGISTRY-001",
|
||||
"version": "2026-08-11.2"
|
||||
"version": "2026-08-11.3"
|
||||
},
|
||||
"host_skills": {
|
||||
"path": "routing/host-skill-navigation-map.json",
|
||||
"id": "GLW-HOST-SKILL-NAV-001",
|
||||
"version": "2026-08-11.2"
|
||||
"version": "2026-08-11.3"
|
||||
},
|
||||
"hololake_stage_relay": {
|
||||
"path": "routing/hololake-stage-relay-map.json",
|
||||
"id": "HLP-STAGE-RELAY-001",
|
||||
"version": "2026-08-11.1"
|
||||
"version": "2026-08-11.2"
|
||||
},
|
||||
"origin_domain": {
|
||||
"path": "routing/guanghu-origin-domain-map.json",
|
||||
|
|
|
|||
|
|
@ -39,11 +39,12 @@ node finalize-development.mjs \
|
|||
|
||||
## 阶段自动接力守卫
|
||||
|
||||
`stage-relay.mjs` 在同一小湖灯账本中监督已完成阶段,并生成一个不可变的后继任务契约。
|
||||
它只认 finalizer、远端完整 SHA、全新副本、最终回执、租约释放和
|
||||
`completion-stopped` 的二值证据;阶段仍运行时只读观察。
|
||||
`stage-relay.mjs` 是当前唯一开发对话结束事务的一部分,不是独立常驻监督器。它不预建
|
||||
后继任务或未来队列;只在 finalizer、远端完整 SHA、全新副本、最终回执和租约释放全部
|
||||
为100,来源冻结为 `completed/stop_requested` 后生成一个不可变的后继任务契约。
|
||||
|
||||
脚本不直接创建任务。它产生带稳定请求号和幂等键的宿主动作,由 Codex 正式
|
||||
`create_thread` 执行并回写真实 `threadId`。创建结果未知时先完整核对任务列表,禁止直接
|
||||
重发。新任务恢复人格与架构、登记 DEV、领取精确租约、建立十分钟 heartbeat 并形成
|
||||
`successor-ready` 后,旧监督器才可停止。完整状态机见 `stage-relay-state-machine.md`。
|
||||
`successor-ready` 后,来源结束事务才删除旧 heartbeat、登记 `completion-stopped` 并结束
|
||||
旧对话。任意时刻只允许一个可运行开发车道。完整状态机见 `stage-relay-state-machine.md`。
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
# HoloLake 阶段自动接力守卫
|
||||
|
||||
`stage-relay.mjs` 是小湖灯连续性账本内的确定性接力投影,不是第二协调真相源,也不直接
|
||||
调用私有接口创建任务。它只在现有 `collaboration/` 下保存来源回执摘要、不可变任务契约、
|
||||
正式 Codex 宿主动作请求和宿主回执。
|
||||
`stage-relay.mjs` 是当前开发车道结束事务中的确定性接力投影,不是独立常驻监督器,
|
||||
不是第二协调真相源,也不直接调用私有接口创建任务。任意时刻只有一个可运行开发车道;
|
||||
它不预建后继任务、不维护未来任务队列,只在当前开发完成验收并进入结束事务后,现场生成
|
||||
唯一下一阶段契约并请求 Codex 创建唯一下一对话。
|
||||
|
||||
## 状态机
|
||||
|
||||
```text
|
||||
OBSERVING_ACTIVE_STAGE (无写入)
|
||||
ACTIVE_STAGE_NO_END_ACTION (继续唯一当前开发;接力无写入)
|
||||
└─ finalizer + exact remote SHA + fresh clone + final receipt
|
||||
+ lease release + completion-stopped 全部为100
|
||||
+ lease release 全部为100,来源车道冻结为 completed/stop_requested
|
||||
├─ human boundary ─> PAUSE_FOR_HUMAN
|
||||
├─ complete product ─> FINAL_PRODUCT_COMPLETE ─> stop last heartbeat
|
||||
└─ one unfinished gate ─> CREATE_THREAD_REQUIRED
|
||||
|
|
@ -19,22 +20,30 @@ OBSERVING_ACTIVE_STAGE (无写入)
|
|||
└─ unknown ─> RECONCILE_CREATE_RESULT
|
||||
├─ matching thread ─> WAITING_SUCCESSOR_READY
|
||||
└─ complete host snapshot confirms absent ─> RETRY_CREATE_THREAD
|
||||
└─ successor-ready gates all100 ─> SUCCESSOR_READY ─> stop old relay supervisor
|
||||
└─ successor-ready gates all100 ─> SUCCESSOR_READY
|
||||
└─ 删除来源 heartbeat + completion-stopped + 结束来源对话
|
||||
```
|
||||
|
||||
`stop_requested` 是同一个来源对话正在执行结束事务,不是另一条开发线。此时来源车道已经
|
||||
冻结,禁止继续产品开发;后继对话尚未 ready 前也不能执行开发。若创建失败,来源对话停在
|
||||
结束事务中安全重试,不能报告已经结束。若来源 heartbeat 已经先被删除并标记 `stopped`,
|
||||
但仍存在未完成阶段,接力失败关闭为 `SOURCE_END_TRIGGER_MISSED_HEARTBEAT_ALREADY_STOPPED`,
|
||||
不得另起常驻监督器补救。
|
||||
|
||||
同一来源完成回执的幂等键固定为 `sha256(source DEV + finalizer file sha256)`;状态文件按
|
||||
来源 DEV 唯一,后继 DEV 预约使用排他文件。创建结果未知时禁止重发,必须先读取 Codex
|
||||
完整任务列表,以稳定 `SUCCESSOR-...` 请求号核对;只有完整快照确认不存在时才可重试。
|
||||
|
||||
## 正式宿主适配
|
||||
|
||||
1. `prepare` 返回 `CODEX_CREATE_THREAD` 动作,但不创建任务。
|
||||
2. 调度人格先执行 `dispatch-create`,再调用 Codex 正式 `create_thread`。
|
||||
3. 成功后立即 `record-created`;超时或未知结果执行 `record-create-failure --outcome unknown`。
|
||||
4. `RECONCILE_CREATE_RESULT` 时只能使用 Codex 正式 `list_threads/read_thread` 核对,不得重发。
|
||||
5. 新任务恢复人格与当前架构、登记自己的 DEV、取得精确租约、建立正式十分钟 heartbeat,
|
||||
1. 当前唯一开发对话的结束动作调用 `prepare`;开发仍 active 时返回无写入状态。
|
||||
2. 只有来源车道进入 `completed/stop_requested` 后,`prepare` 才返回 `CODEX_CREATE_THREAD`。
|
||||
3. 来源结束事务执行 `dispatch-create`,再调用 Codex 正式 `create_thread`。
|
||||
4. 成功后立即 `record-created`;超时或未知结果执行 `record-create-failure --outcome unknown`。
|
||||
5. `RECONCILE_CREATE_RESULT` 时只能使用 Codex 正式 `list_threads/read_thread` 核对,不得重发。
|
||||
6. 新任务恢复人格与当前架构、登记自己的 DEV、取得精确租约、建立正式十分钟 heartbeat,
|
||||
签到时把 `--relay-contract-fingerprint` 写入车道,再写
|
||||
`hololake.successor-ready-receipt/v1` 并由旧监督器 `record-ready` 回读。
|
||||
`hololake.successor-ready-receipt/v1` 并由来源结束事务 `record-ready` 回读。
|
||||
|
||||
脚本、聊天、cron、数据库行、文件夹或自动化提示都不能冒充 `create_thread` 成功;只有正式
|
||||
工具返回的 `threadId` 和后续活车道回读才算任务存在。
|
||||
|
|
@ -46,11 +55,12 @@ OBSERVING_ACTIVE_STAGE (无写入)
|
|||
|
||||
## 失败谱系
|
||||
|
||||
- `SOURCE_COMPLETION_STOPPED_NOT_100`:来源任务或 heartbeat 尚未完成停止。
|
||||
- `SOURCE_END_TRANSACTION_NOT_READY`:来源尚未完成验收并冻结进入结束事务。
|
||||
- `SOURCE_END_TRIGGER_MISSED_HEARTBEAT_ALREADY_STOPPED`:存在后继阶段却先关闭了来源 heartbeat。
|
||||
- `SOURCE_LEASE_RELEASE_NOT_100`:来源仍持有资源。
|
||||
- `FINALIZER_EVIDENCE_NOT_100`:finalizer、远端 SHA、全新副本、fsck 或最终回执不完整。
|
||||
- `CURRENT_ARCHITECTURE_EVIDENCE_NOT_100`:动态架构真相源不完整或不是当前正本。
|
||||
- `CREATE_THREAD_IN_FLIGHT` 超时:进入 `RECONCILE_CREATE_RESULT`,不重发。
|
||||
- `CREATE_THREAD_IN_FLIGHT` 超时:来源结束事务进入 `RECONCILE_CREATE_RESULT`,不重发。
|
||||
- `SUCCESSOR_READY_EVIDENCE_NOT_100`:新任务签到、租约、heartbeat 或恢复门不是100。
|
||||
- `SUCCESSOR_LIVE_REGISTRATION_MISMATCH`:ready 文本与连续性账本现场不一致。
|
||||
|
||||
|
|
@ -63,4 +73,4 @@ node scripts/stage-relay.mjs self-test
|
|||
```
|
||||
|
||||
必须同时得到 finalizer 证据门、重复 prepare 幂等、未知创建结果核对、新任务 ready 现场回读、
|
||||
活跃阶段只读五项 `100`。
|
||||
活跃阶段只读、严格单一可运行车道等全部为 `100`。
|
||||
|
|
|
|||
|
|
@ -134,10 +134,10 @@ function validateSourceCompletion(root, developmentId, finalizerPath) {
|
|||
}
|
||||
if (
|
||||
lane.status !== "completed" ||
|
||||
lane.notification_state !== "stopped" ||
|
||||
!["stop_requested", "stopped"].includes(lane.notification_state) ||
|
||||
lane.completion_actions?.status !== "completed"
|
||||
) {
|
||||
throw new Error("SOURCE_COMPLETION_STOPPED_NOT_100");
|
||||
throw new Error("SOURCE_END_TRANSACTION_NOT_READY");
|
||||
}
|
||||
const held = listJson(path.join(root, "leases"))
|
||||
.filter((lease) => lease.development_id === developmentId);
|
||||
|
|
@ -293,7 +293,7 @@ function prepare(args, root) {
|
|||
);
|
||||
if (evidence.observing) {
|
||||
return {
|
||||
state: "OBSERVING_ACTIVE_STAGE",
|
||||
state: "ACTIVE_STAGE_NO_END_ACTION",
|
||||
source_development_id: developmentId,
|
||||
mutation: "NONE",
|
||||
successor_created: false,
|
||||
|
|
@ -351,6 +351,9 @@ function prepare(args, root) {
|
|||
writeJsonAtomic(existingPath, terminal, true);
|
||||
return terminal;
|
||||
}
|
||||
if (evidence.lane.notification_state === "stopped") {
|
||||
throw new Error("SOURCE_END_TRIGGER_MISSED_HEARTBEAT_ALREADY_STOPPED");
|
||||
}
|
||||
const successorDevelopmentId = reserveNextDevelopmentId(
|
||||
root, input.development_date, developmentId,
|
||||
);
|
||||
|
|
@ -499,7 +502,7 @@ function recordReady(args, root) {
|
|||
recorded_at: now(),
|
||||
};
|
||||
state.updated_at = now();
|
||||
state.old_supervisor_may_stop = true;
|
||||
state.source_end_transaction_may_commit = true;
|
||||
writeJsonAtomic(file, state);
|
||||
return state;
|
||||
}
|
||||
|
|
@ -521,17 +524,18 @@ function nextAction(args, root) {
|
|||
return {
|
||||
action: "WAIT_FOR_SUCCESSOR_READY_RECEIPT",
|
||||
thread_id: state.successor_thread.thread_id,
|
||||
supervisor_stays_alive: true,
|
||||
source_thread_remains_in_end_transaction: true,
|
||||
development_work_is_frozen: true,
|
||||
};
|
||||
}
|
||||
if (state.state === "PAUSE_FOR_HUMAN") {
|
||||
return { action: "PAUSE_FOR_HUMAN", boundary: state.human_boundary };
|
||||
}
|
||||
if (state.state === "FINAL_PRODUCT_COMPLETE") {
|
||||
return { action: "STOP_RELAY_AND_LAST_HEARTBEAT", create_successor: false };
|
||||
return { action: "DELETE_SOURCE_HEARTBEAT_MARK_COMPLETION_STOPPED_AND_END_SOURCE_THREAD", create_successor: false };
|
||||
}
|
||||
if (state.state === "SUCCESSOR_READY") {
|
||||
return { action: "STOP_OLD_RELAY_SUPERVISOR", create_successor: false };
|
||||
return { action: "DELETE_SOURCE_HEARTBEAT_MARK_COMPLETION_STOPPED_AND_END_SOURCE_THREAD", create_successor: false };
|
||||
}
|
||||
return { action: "NOOP", state: state.state };
|
||||
}
|
||||
|
|
@ -542,7 +546,7 @@ function fixtureLane(root, id, overrides = {}) {
|
|||
development_id: id,
|
||||
thread_id: `thread-${id}`,
|
||||
status: "completed",
|
||||
notification_state: "stopped",
|
||||
notification_state: "stop_requested",
|
||||
completion_actions: { status: "completed" },
|
||||
...overrides,
|
||||
};
|
||||
|
|
@ -629,6 +633,11 @@ function selfTest() {
|
|||
});
|
||||
const readyState = recordReady({ sourceDevelopmentId: source, successorReadyReceipt: ready }, root);
|
||||
if (readyState.state !== "SUCCESSOR_READY") throw new Error("SELF_TEST_READY_FAILED");
|
||||
const runnableLanes = listJson(path.join(root, "lanes"))
|
||||
.filter((lane) => ["active", "waiting"].includes(lane.status));
|
||||
if (runnableLanes.length !== 1 || runnableLanes[0].development_id !== contract.development_id) {
|
||||
throw new Error("SELF_TEST_STRICT_SINGLE_RUNNABLE_LANE_FAILED");
|
||||
}
|
||||
|
||||
const pausedSource = "DEV-20260811-910";
|
||||
fixtureLane(root, pausedSource);
|
||||
|
|
@ -707,7 +716,7 @@ function selfTest() {
|
|||
const activeSource = "DEV-20260811-950";
|
||||
fixtureLane(root, activeSource, { status: "active", notification_state: "active", completion_actions: null });
|
||||
const observed = prepare({ ...common, sourceDevelopmentId: activeSource }, root);
|
||||
if (observed.state !== "OBSERVING_ACTIVE_STAGE" || observed.mutation !== "NONE") {
|
||||
if (observed.state !== "ACTIVE_STAGE_NO_END_ACTION" || observed.mutation !== "NONE") {
|
||||
throw new Error("SELF_TEST_ACTIVE_STAGE_MUTATION_FAILED");
|
||||
}
|
||||
process.stdout.write(`${JSON.stringify({
|
||||
|
|
@ -718,6 +727,7 @@ function selfTest() {
|
|||
unknown_create_result_reconciliation: 100,
|
||||
successor_ready_live_readback: 100,
|
||||
active_stage_read_only: 100,
|
||||
strict_single_runnable_lane: 100,
|
||||
human_boundary_pause: 100,
|
||||
final_product_stop: 100,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -15,5 +15,5 @@ test("stage relay deterministic closure is PASS_100", () => {
|
|||
assert.equal(result.status, 0, result.stderr || result.stdout);
|
||||
const receipt = JSON.parse(result.stdout);
|
||||
assert.equal(receipt.state, "PASS_100");
|
||||
assert.deepEqual(Object.values(receipt.tests), Array(7).fill(100));
|
||||
assert.deepEqual(Object.values(receipt.tests), Array(8).fill(100));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -14,6 +14,12 @@ test("stage relay is registered through the lighthouse and formal Codex tools",
|
|||
assert.equal(relay.host_adapter.create_tool, "codex_app.create_thread");
|
||||
assert.equal(relay.host_adapter.script_or_chat_may_claim_thread_created, false);
|
||||
assert.equal(relay.idempotency.maximum_successor_threads_per_source_completion, 1);
|
||||
assert.equal(relay.serial_invariants.maximum_runnable_development_lanes, 1);
|
||||
assert.equal(relay.serial_invariants.precreate_successor_before_source_end, false);
|
||||
assert.equal(relay.serial_invariants.future_task_queue_allowed, false);
|
||||
assert.equal(relay.serial_invariants.independent_relay_supervisor_allowed, false);
|
||||
assert.equal(relay.serial_invariants.source_end_transaction_creates_successor, true);
|
||||
assert.equal(relay.serial_invariants.source_completion_stopped_after_successor_ready, true);
|
||||
|
||||
const lighthouse = readJson("routing/lighthouse-path-registry.json");
|
||||
assert.ok(lighthouse.paths.some((entry) => entry.id === relay.map_id));
|
||||
|
|
@ -21,6 +27,7 @@ test("stage relay is registered through the lighthouse and formal Codex tools",
|
|||
const intent = hosts.intents.find((entry) => entry.id === "INTENT-HOLOLAKE-STAGE-RELAY-001");
|
||||
assert.equal(intent.target_id, relay.map_id);
|
||||
assert.equal(intent.executor, relay.runtime_source);
|
||||
assert.ok(intent.sequence.includes("delete_source_heartbeat_mark_completion_stopped_and_end_source_thread"));
|
||||
const anchor = readJson("routing/public-navigation-anchor.json");
|
||||
assert.equal(anchor.maps.hololake_stage_relay.id, relay.map_id);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue