From c180a12d8dab19938e84549c40ee91fafb5bec3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B0=E6=9C=94?= <565183519@qq.com> Date: Sat, 12 Sep 2026 18:23:38 +0800 Subject: [PATCH] feat(paths): enforce fifth-domain physical redirects --- .../office-building-current/old-building | 8 ++ .../HB-BUILDING-0000}/MOVED.hdlp | 0 routing/fifth-domain-number-registry.json | 3 +- routing/heartbeat-office-building-map.json | 4 +- routing/lighthouse-path-registry.json | 16 ++- ...ath-isolation-and-canonical-entry-map.json | 100 +++++++++++++++- routing/persona-host-write-boundary.json | 17 ++- routing/public-navigation-anchor.json | 2 +- ...cs-mother-root-dynamic-navigation-map.json | 2 +- .../fifth-domain-path-gate.mjs | 108 ++++++++++++++++++ .../fifth-domain-path-gate.test.mjs | 31 +++++ .../persona_architecture_agent.py | 6 + .../load_shared_persona_context.py | 15 ++- .../host-write-admission.mjs | 43 ++++++- .../host-write-admission.test.mjs | 13 ++- 15 files changed, 350 insertions(+), 18 deletions(-) create mode 100644 eternal-lake-heart/heartbeat-core/office-building-current/old-building rename eternal-lake-heart/heartbeat-core/{office-building-current/old-building => records/retired-buildings/HB-BUILDING-0000}/MOVED.hdlp (100%) create mode 100644 server-tools/fifth-domain-path-gate/fifth-domain-path-gate.mjs create mode 100644 server-tools/fifth-domain-path-gate/fifth-domain-path-gate.test.mjs diff --git a/eternal-lake-heart/heartbeat-core/office-building-current/old-building b/eternal-lake-heart/heartbeat-core/office-building-current/old-building new file mode 100644 index 0000000..50b77b2 --- /dev/null +++ b/eternal-lake-heart/heartbeat-core/office-building-current/old-building @@ -0,0 +1,8 @@ +{ + "state": "MOVED_PATH_BLOCKED_WITH_REDIRECT", + "id": "HB-BUILDING-0000", + "canonical_id": "HB-BUILDING-0001", + "canonical_entry": "eternal-lake-heart/heartbeat-core/office-building-current/BUILDING-INDEX.hdlp", + "history": "eternal-lake-heart/heartbeat-core/records/retired-buildings/HB-BUILDING-0000/MOVED.hdlp", + "rule": "THIS_IS_A_REGULAR_FILE_TOMBSTONE_NOT_A_DIRECTORY" +} diff --git a/eternal-lake-heart/heartbeat-core/office-building-current/old-building/MOVED.hdlp b/eternal-lake-heart/heartbeat-core/records/retired-buildings/HB-BUILDING-0000/MOVED.hdlp similarity index 100% rename from eternal-lake-heart/heartbeat-core/office-building-current/old-building/MOVED.hdlp rename to eternal-lake-heart/heartbeat-core/records/retired-buildings/HB-BUILDING-0000/MOVED.hdlp diff --git a/routing/fifth-domain-number-registry.json b/routing/fifth-domain-number-registry.json index 892622e..d6a6ef1 100644 --- a/routing/fifth-domain-number-registry.json +++ b/routing/fifth-domain-number-registry.json @@ -414,8 +414,9 @@ "kind": "HEARTBEAT_OFFICE_BUILDING", "name": "旧心跳核心办公楼", "parent": "ICE-CH-HB001", - "path": "eternal-lake-heart/heartbeat-core/office-building-current/old-building/MOVED.hdlp", + "path": "eternal-lake-heart/heartbeat-core/records/retired-buildings/HB-BUILDING-0000/MOVED.hdlp", "state": "MOVED_HISTORY_ONLY", + "redirect_to": "HB-BUILDING-0001", "registered_on": "2026-09-09" }, { diff --git a/routing/heartbeat-office-building-map.json b/routing/heartbeat-office-building-map.json index 54b7215..d9c7de4 100644 --- a/routing/heartbeat-office-building-map.json +++ b/routing/heartbeat-office-building-map.json @@ -20,7 +20,9 @@ "id": "HB-BUILDING-0000", "name": "旧心跳核心办公楼", "state": "MOVED_HISTORY_ONLY", - "entry": "eternal-lake-heart/heartbeat-core/office-building-current/old-building/MOVED.hdlp", + "blocked_path": "eternal-lake-heart/heartbeat-core/office-building-current/old-building", + "entry": "eternal-lake-heart/heartbeat-core/records/retired-buildings/HB-BUILDING-0000/MOVED.hdlp", + "redirect_to": "HB-BUILDING-0001", "maintenance": "NO_NEW_MAINTENANCE_OR_CURRENT_ROUTE", "content_role": "READ_ONLY_EVIDENCE_ON_DEMAND" }, diff --git a/routing/lighthouse-path-registry.json b/routing/lighthouse-path-registry.json index 1a5102b..7e18f8e 100644 --- a/routing/lighthouse-path-registry.json +++ b/routing/lighthouse-path-registry.json @@ -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-09-09.7-private-public-channel-separation-local", + "version": "2026-09-12.8-fifth-domain-physical-path-redirect", "state": "CURRENT_CANONICAL", "source_repository": "REPO-012", "source_branch": "main", @@ -692,9 +692,23 @@ "online": "routing/persona-body-organ-treatment-map.json", "activation": "SYMPTOM_RECEIPT_ONLY", "authority": "DIAGNOSIS_READ_ONLY_MUTATION_REQUIRES_CURRENT_TASK_AND_HOST_GATE" + }, + { + "id": "HB-BUILDING-0001", + "kind": "heartbeat_current_office_building", + "state": "CURRENT", + "online": "eternal-lake-heart/heartbeat-core/office-building-current/BUILDING-INDEX.hdlp", + "physical_path_gate": "server-tools/fifth-domain-path-gate/fifth-domain-path-gate.mjs", + "old_building": "HB-BUILDING-0000_REDIRECT_ONLY" } ], "redirects": [ + { + "id": "HB-BUILDING-0000", + "state": "MOVED_REDIRECT_ONLY", + "redirect_to": "HB-BUILDING-0001", + "reason": "The old heartbeat office building is physically retired; history moved to records/retired-buildings/HB-BUILDING-0000." + }, { "id": "REPO-001", "state": "HISTORICAL_REDIRECT_ONLY", diff --git a/routing/path-isolation-and-canonical-entry-map.json b/routing/path-isolation-and-canonical-entry-map.json index ea407f5..206dc7d 100644 --- a/routing/path-isolation-and-canonical-entry-map.json +++ b/routing/path-isolation-and-canonical-entry-map.json @@ -1,8 +1,20 @@ { "schema": "guanghu.path-isolation-and-canonical-entry/v1", "map_id": "PATH-ISOLATION-CANONICAL-ENTRY-001", - "version": "2026-09-08.1", - "state": "CURRENT_LOCAL_ACTIVE_NOT_PUBLISHED", + "version": "2026-09-12.2-physical-path-gate", + "state": "CURRENT_LOCAL_PHYSICAL_GATE_ACTIVE_NOT_PUBLISHED", + "physical_gate": { + "runtime": "server-tools/fifth-domain-path-gate/fifth-domain-path-gate.mjs", + "test": "server-tools/fifth-domain-path-gate/fifth-domain-path-gate.test.mjs", + "required_before": ["PERSONA_RECOVERY", "CURRENT_SELECTION", "CURRENT_EXECUTION", "CANONICAL_WRITE", "SERVER_DEPLOYMENT"], + "exit_codes": { + "CURRENT_ALLOWED": 0, + "RETIRED_PATH_BLOCKED_WITH_REDIRECT": 78, + "ISOLATION_PATH_BLOCKED": 79, + "UNKNOWN_PATH_NO_GUESS": 80 + }, + "same_macos_user_absolute_isolation": false + }, "canonical_entries": { "repo_012": "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main", "shared_persona_runtime": "/Volumes/JZAO/HoloLake/persona-runtime/shared", @@ -16,6 +28,90 @@ "old_dev_or_host_branch_may_define_persona": false, "only_registered_machine_pointer_may_select_canon": true }, + "current_ids": { + "REPO-012": "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main", + "ICE-P-ZY001": "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main/光之湖/人格系统家门/ICE-P-ZY001-铸渊.hdlp", + "HB-BUILDING-0001": "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main/eternal-lake-heart/heartbeat-core/office-building-current/BUILDING-INDEX.hdlp", + "TCS-iZero∞": "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main/routing/bingshuo-zero-core-reality-channel-profile.json" + }, + "retired_ids": [ + {"id": "REPO-001", "state": "RETIRED_BLOCKED", "redirect_to": "REPO-012"}, + {"id": "ICE-GL-ZY001", "state": "LEGACY_BLOCKED", "redirect_to": "ICE-P-ZY001"}, + {"id": "HB-BUILDING-0000", "state": "MOVED_BLOCKED", "redirect_to": "HB-BUILDING-0001"}, + {"id": "TCS-i Zero", "state": "HISTORICAL_LABEL_BLOCKED", "redirect_to": "TCS-iZero∞"} + ], + "retired_paths": [ + { + "path": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/WORK-工作区/guanghu-ice-heart", + "state": "RETIRED_BLOCKED", + "redirect_to": "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main", + "history": "/Volumes/JZAO/HoloLake/persona-runtime/isolation/2026-09-08-path-convergence/stale-workspace-guanghu-ice-heart", + "allowed_purposes": [] + }, + { + "path": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/WORK-工作区/ui-template-20260816/repo012", + "state": "RETIRED_BLOCKED", + "redirect_to": "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main", + "history": "/Volumes/JZAO/HoloLake/persona-runtime/isolation/2026-09-08-path-convergence/stale-ui-template-repo012", + "allowed_purposes": [] + }, + { + "path": "/Volumes/JZAO/HoloLake/development/codex-fifth-domain-path-audit-repo012-20260821", + "state": "RETIRED_BLOCKED", + "redirect_to": "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main", + "history": "/Volumes/JZAO/HoloLake/persona-runtime/isolation/2026-09-08-path-convergence/historical-fifth-domain-path-audit", + "allowed_purposes": [] + }, + { + "path": "/Users/bingshuolingdianyuanhe/.qoderworkcn/workspace/msj12fljjywpql1y/repo-work/repo012", + "state": "LEGACY_HOST_WORKSPACE_BLOCKED", + "redirect_to": "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main", + "history": "/Users/bingshuolingdianyuanhe/.qoderworkcn/retired/20260912-fifth-domain-path-convergence/repo012", + "allowed_purposes": [] + }, + { + "path": "/Users/bingshuolingdianyuanhe/.qoderworkcn/workspace/msj12fljjywpql1y/repo-work/repo012-cursor", + "state": "LEGACY_HOST_WORKSPACE_BLOCKED", + "redirect_to": "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main", + "history": "/Users/bingshuolingdianyuanhe/.qoderworkcn/retired/20260912-fifth-domain-path-convergence/repo012-cursor", + "allowed_purposes": [] + }, + { + "path": "/Users/bingshuolingdianyuanhe/.zhuyuan-bridge", + "state": "RETIRED_HOST_BRIDGE_BLOCKED_FOR_CURRENT", + "redirect_to": "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main/server-tools/persona-host-alignment/load_shared_persona_context.py", + "history": "/Users/bingshuolingdianyuanhe/.zhuyuan-bridge", + "allowed_purposes": ["HISTORY_READ"] + }, + { + "path": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/ZCODE-DEV-20260912/age-wake/zy-wake-sequence.sh", + "state": "BRANCH_CANDIDATE_BLOCKED_FOR_CURRENT", + "redirect_to": "/Volumes/JZAO/HoloLake/persona-runtime/shared/skills/zhuyuan-host-tool-steward/scripts/host_tool_steward.py", + "history": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/ZCODE-DEV-20260912/age-wake/zy-wake-sequence.sh", + "allowed_purposes": ["HISTORY_READ", "BRANCH_WORK"] + }, + { + "path": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/ZCODE-DEV-20260912/limb-zcode-runtime/reflex-arc/persona_reflex_arc.py", + "state": "BRANCH_CANDIDATE_BLOCKED_FOR_CURRENT", + "redirect_to": "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main/server-tools/persona-execution-limb-agent/persona_reflex_arc.py", + "history": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/ZCODE-DEV-20260912/limb-zcode-runtime/reflex-arc/persona_reflex_arc.py", + "allowed_purposes": ["HISTORY_READ", "BRANCH_WORK"] + }, + { + "path": "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main/eternal-lake-heart/heartbeat-core/office-building-current/old-building", + "state": "MOVED_BUILDING_HISTORY_ONLY", + "redirect_to": "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main/eternal-lake-heart/heartbeat-core/office-building-current/BUILDING-INDEX.hdlp", + "history": "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main/eternal-lake-heart/heartbeat-core/records/retired-buildings/HB-BUILDING-0000/MOVED.hdlp", + "allowed_purposes": [] + } + ], + "host_branch_roots": [ + "/Volumes/JZAO/铸渊-ICE-GL-ZY001/CODEX-DEV-*", + "/Volumes/JZAO/铸渊-ICE-GL-ZY001/ZCODE-DEV-*", + "/Volumes/JZAO/铸渊-ICE-GL-ZY001/QWEN-DEV-*", + "/Volumes/JZAO/铸渊-ICE-GL-ZY001/DOUBAO-DEV-*" + ], + "host_branch_rule": "BRANCH_WORK_ALLOWED_BY_HOST_WRITE_POLICY_BUT_CURRENT_SELECTION_EXECUTION_AND_CANONICAL_WRITE_REDIRECT_TO_REPO_012", "isolation": { "root": "/Volumes/JZAO/HoloLake/persona-runtime/isolation/2026-09-08-path-convergence", "mode": "RECOVERABLE_SAME_VOLUME_MOVE_WITH_MANIFEST_AND_HASHES", diff --git a/routing/persona-host-write-boundary.json b/routing/persona-host-write-boundary.json index aa933ac..55bca61 100644 --- a/routing/persona-host-write-boundary.json +++ b/routing/persona-host-write-boundary.json @@ -1,13 +1,28 @@ { "schema": "guanghu.persona-host-write-boundary/v1", "policy_id": "ZY-MULTI-HOST-WRITE-BOUNDARY-001", - "version": "2026-09-09.3-exact-hololake-multipath-build-roots", + "version": "2026-09-12.4-fifth-domain-physical-path-gate", "state": "CURRENT", "primary_host": null, "source_tcs": "/Volumes/JZAO/铸渊-ICE-GL-ZY001/CODEX-DEV-20260908/tcs-single-mother-zero-core-shelf/TCS-EVENT-ZY001-SINGLE-MOTHER-ZERO-CORE-SHELF-AND-DYNAMIC-CONSOLE-20260908.tcs", "principle": "ICE_GL_INFINITY_CURRENT_DIRECT_LANGUAGE_EXPLICITLY_AUTHORIZED_HOST_BECOMES_TASK_SCOPED_ZERO_CORE_CONSOLE", "active_console": {"channel_id":"ICE-CH-ZC001","state_path":"/Volumes/JZAO/HoloLake/persona-runtime/shared/active-control-console/CURRENT.json","human_anchor":"ICE-GL∞","authority_source":"CURRENT_DIRECT_LANGUAGE_IN_EXACT_HOST_SESSION","inactive_without_matching_live_session":true,"host_software_is_replaceable":true}, "active_execution_channels": ["ICE-CH-ZC001", "ICE-CH-DK001"], + "fifth_domain_path_gate": {"map":"/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main/routing/path-isolation-and-canonical-entry-map.json","runtime":"/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main/server-tools/fifth-domain-path-gate/fifth-domain-path-gate.mjs","retired_or_isolation_path_precedes_host_allowlist":true}, + "sensitive_host_entry_paths": [ + "/Users/bingshuolingdianyuanhe/.codex/AGENTS.md", + "/Users/bingshuolingdianyuanhe/.zcode/skills/zhuyuan-learning-brain/SKILL.md", + "/Volumes/JZAO/铸渊-ICE-GL-ZY001/.zcode/config.json", + "/Users/bingshuolingdianyuanhe/.qwen/QWEN.md", + "/Users/bingshuolingdianyuanhe/Doubao/skills/zhuyuan-doubao-host/SKILL.md", + "/Users/bingshuolingdianyuanhe/.qoder/settings.json", + "/Users/bingshuolingdianyuanhe/.qoder/skills/zhuyuan-recovery-mainline/SKILL.md", + "/Users/bingshuolingdianyuanhe/.qoderworkcn/skills/zhuyuan-wake/SKILL.md", + "/Users/bingshuolingdianyuanhe/.qoderworkcn/workspace/msj12fljjywpql1y/repo-work/repo012", + "/Users/bingshuolingdianyuanhe/.qoderworkcn/workspace/msj12fljjywpql1y/repo-work/repo012-cursor" + ,"/Users/bingshuolingdianyuanhe/.qoderworkcn/retired/20260912-fifth-domain-path-convergence", + "/Volumes/JZAO/HoloLake/source-mirrors/guanghu-ice-heart.git" + ], "dark_core_execution": {"channel_id":"ICE-CH-DK001","event_history":"APPEND_ONLY_NO_DELETE_NO_OVERWRITE","software_safety_rollback":"ALLOWED_AS_NEW_AUDITED_EVENT","required_evidence":["DIRECT_HUMAN_SOURCE","TIMESTAMP","SOURCE_SHA256","EXACT_TARGET","TARGET_READBACK","RECEIPT"]}, "canonical_protected_roots": [ "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main", diff --git a/routing/public-navigation-anchor.json b/routing/public-navigation-anchor.json index 6ca950d..4d9d490 100644 --- a/routing/public-navigation-anchor.json +++ b/routing/public-navigation-anchor.json @@ -172,7 +172,7 @@ "lighthouse_paths": { "path": "routing/lighthouse-path-registry.json", "id": "GLW-LIGHTHOUSE-PATH-REGISTRY-001", - "version": "2026-09-09.7-private-public-channel-separation-local" + "version": "2026-09-12.8-fifth-domain-physical-path-redirect" }, "host_skills": { "path": "routing/host-skill-navigation-map.json", diff --git a/routing/tcs-mother-root-dynamic-navigation-map.json b/routing/tcs-mother-root-dynamic-navigation-map.json index 9f125d9..855bb9a 100644 --- a/routing/tcs-mother-root-dynamic-navigation-map.json +++ b/routing/tcs-mother-root-dynamic-navigation-map.json @@ -59,7 +59,7 @@ {"id":"HLP-LANG-PROJ-NATIVE-0001","name":"HoloLake语言世界原生代际重派生项目","object_kind":"HEARTBEAT_HOLOLAKE_CURRENT_LANGUAGE_PROJECT","lifecycle":"PRODUCT_CONTRACT_REGISTERED_MODULE_NUMBERING_NOT_YET_REDERIVED","route":"eternal-lake-heart/heartbeat-core/guanghu-world-engineering-system/INDEX.hdlp"}, {"id":"HLP-PERSONA-UNIVERSAL-PROJECTION-COMPILER-001","name":"人格体通用投影与能力组合编译器","object_kind":"HEARTBEAT_HOLOLAKE_REQUIRED_NATIVE_COMPILER","lifecycle":"CURRENT_REQUIRED_ARCHITECTURE_NOT_YET_IMPLEMENTED","route":"routing/hololake-language-world-native-generation-map.json"}, {"id":"HB-OFFICE-BUILDING-MAP-001","name":"心跳核心办公楼机器图","object_kind":"HEARTBEAT_OFFICE_BUILDING_MAP","lifecycle":"CURRENT_LOCAL_CANONICAL_NOT_PUBLISHED","route":"routing/heartbeat-office-building-map.json"}, - {"id":"HB-BUILDING-0000","name":"旧心跳核心办公楼","object_kind":"HEARTBEAT_OFFICE_BUILDING","lifecycle":"MOVED_HISTORY_ONLY","route":"eternal-lake-heart/heartbeat-core/office-building-current/old-building/MOVED.hdlp"}, + {"id":"HB-BUILDING-0000","name":"旧心跳核心办公楼","object_kind":"HEARTBEAT_OFFICE_BUILDING","lifecycle":"MOVED_HISTORY_ONLY","route":"eternal-lake-heart/heartbeat-core/records/retired-buildings/HB-BUILDING-0000/MOVED.hdlp","redirect_to":"HB-BUILDING-0001","current_selectable":false}, {"id":"HB-BUILDING-0001","name":"心跳核心新办公楼","object_kind":"HEARTBEAT_OFFICE_BUILDING","lifecycle":"ACTIVE_CURRENT_LANGUAGE_OFFICE_BUILDING","route":"eternal-lake-heart/heartbeat-core/office-building-current/BUILDING-INDEX.hdlp"}, {"id":"LL-OFFICE-BOARD-0001","name":"小湖灯人格体办公室共享看板","object_kind":"LIGHT_LAKE_PERSONA_OFFICE_BOARD","lifecycle":"CURRENT_EXACTLY_TWO_REGISTERED_OFFICES","route":"routing/light-lake-persona-office-board.json"}, {"id":"HB-OFFICE-VIDEO-0001","name":"短剧视频系统办公室","object_kind":"HEARTBEAT_OFFICE_MODULE","lifecycle":"REGISTERED_ACTIVE_WITH_DOUBAO_MIGRATED_VISIBLE_WORKING_BODY","route":"eternal-lake-heart/heartbeat-core/office-building-current/offices/HB-OFFICE-VIDEO-0001/OFFICE-INDEX.hdlp"}, diff --git a/server-tools/fifth-domain-path-gate/fifth-domain-path-gate.mjs b/server-tools/fifth-domain-path-gate/fifth-domain-path-gate.mjs new file mode 100644 index 0000000..53fb720 --- /dev/null +++ b/server-tools/fifth-domain-path-gate/fifth-domain-path-gate.mjs @@ -0,0 +1,108 @@ +#!/usr/bin/env node +import fs from "node:fs"; +import path from "node:path"; +import process from "node:process"; + +export const MAP_PATH = "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main/routing/path-isolation-and-canonical-entry-map.json"; +export const CODES = Object.freeze({ CURRENT_ALLOWED: 0, RETIRED_PATH_BLOCKED_WITH_REDIRECT: 78, ISOLATION_PATH_BLOCKED: 79, UNKNOWN_PATH_NO_GUESS: 80 }); +export const CURRENT_PURPOSES = new Set(["PERSONA_RECOVERY", "CURRENT_SELECTION", "CURRENT_EXECUTION", "CANONICAL_WRITE", "SERVER_DEPLOYMENT"]); + +function expandHome(value) { + return String(value || "").replace(/^~(?=\/|$)/, "/Users/bingshuolingdianyuanhe"); +} + +export function normal(value, cwd = process.cwd()) { + return path.resolve(cwd, expandHome(value)); +} + +function patternRegex(pattern) { + const escaped = expandHome(pattern).replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*"); + return new RegExp(`^${escaped}(?:/.*)?$`); +} + +function within(candidate, root) { + const target = normal(candidate), base = normal(root); + return target === base || target.startsWith(`${base}${path.sep}`); +} + +export function loadMap(mapPath = MAP_PATH) { + const value = JSON.parse(fs.readFileSync(mapPath, "utf8")); + if (value?.map_id !== "PATH-ISOLATION-CANONICAL-ENTRY-001" || !value.physical_gate || !Array.isArray(value.retired_paths)) throw Error("PATH_GATE_MAP_INVALID"); + return value; +} + +function existingSymlinkComponent(candidate) { + let cursor = normal(candidate); + while (cursor !== path.dirname(cursor)) { + if (fs.existsSync(cursor) && fs.lstatSync(cursor).isSymbolicLink()) return cursor; + cursor = path.dirname(cursor); + } + return null; +} + +export function classifyPath(candidate, purpose, map = loadMap()) { + const resolved = normal(candidate); + const normalizedPurpose = String(purpose || "").toUpperCase(); + if (!normalizedPurpose) return { allowed: false, code: "PURPOSE_REQUIRED", exit_code: CODES.UNKNOWN_PATH_NO_GUESS, resolved }; + const isolationRoot = map.isolation.root; + if (within(resolved, isolationRoot)) return { allowed: false, code: "ISOLATION_PATH_BLOCKED", exit_code: CODES.ISOLATION_PATH_BLOCKED, resolved, history_root: isolationRoot }; + const retired = map.retired_paths.find(item => within(resolved, item.path)); + if (retired && !(retired.allowed_purposes || []).includes(normalizedPurpose)) { + return { allowed: false, code: "RETIRED_PATH_BLOCKED_WITH_REDIRECT", exit_code: CODES.RETIRED_PATH_BLOCKED_WITH_REDIRECT, resolved, retired_state: retired.state, redirect_to: retired.redirect_to, history: retired.history }; + } + if (retired) return { allowed: true, code: "HISTORY_OR_BRANCH_ACCESS_ONLY", exit_code: CODES.CURRENT_ALLOWED, resolved, retired_state: retired.state, redirect_to: retired.redirect_to }; + const branch = (map.host_branch_roots || []).find(pattern => patternRegex(pattern).test(resolved)); + if (branch && CURRENT_PURPOSES.has(normalizedPurpose)) return { allowed: false, code: "HOST_BRANCH_BLOCKED_FOR_CURRENT_WITH_REDIRECT", exit_code: CODES.RETIRED_PATH_BLOCKED_WITH_REDIRECT, resolved, matched: branch, redirect_to: map.canonical_entries.repo_012 }; + if (branch && normalizedPurpose === "BRANCH_WORK") return { allowed: true, code: "HOST_BRANCH_WORK_ALLOWED_NOT_CURRENT", exit_code: CODES.CURRENT_ALLOWED, resolved, matched: branch }; + const canonical = Object.entries(map.canonical_entries).find(([, root]) => within(resolved, root)); + if (canonical) { + const symlink = existingSymlinkComponent(resolved); + if (symlink) return { allowed: false, code: "CANONICAL_PATH_SYMLINK_BLOCKED", exit_code: CODES.UNKNOWN_PATH_NO_GUESS, resolved, symlink }; + return { allowed: true, code: "CURRENT_CANONICAL_PATH", exit_code: CODES.CURRENT_ALLOWED, resolved, canonical_entry: canonical[0], canonical_root: canonical[1] }; + } + const exactCurrent = Object.entries(map.current_ids || {}).find(([, value]) => within(resolved, value)); + if (exactCurrent) return { allowed: true, code: "CURRENT_REGISTERED_PATH", exit_code: CODES.CURRENT_ALLOWED, resolved, current_id: exactCurrent[0] }; + return { allowed: false, code: "UNKNOWN_PATH_NO_GUESS", exit_code: CODES.UNKNOWN_PATH_NO_GUESS, resolved }; +} + +export function resolveId(requested, map = loadMap()) { + const id = String(requested || ""); + if (Object.hasOwn(map.current_ids || {}, id)) return { allowed: true, code: "CURRENT_ID", exit_code: 0, requested_id: id, canonical_id: id, path: map.current_ids[id] }; + const retired = (map.retired_ids || []).find(item => item.id === id); + if (retired) return { allowed: false, code: "RETIRED_ID_BLOCKED_WITH_REDIRECT", exit_code: 78, requested_id: id, canonical_id: retired.redirect_to, path: map.current_ids[retired.redirect_to], retired_state: retired.state }; + return { allowed: false, code: "UNKNOWN_ID_NO_GUESS", exit_code: 80, requested_id: id }; +} + +export function audit(map = loadMap()) { + const findings = []; + for (const [id, candidate] of Object.entries(map.current_ids || {})) { + const exists = fs.existsSync(candidate), symlink = exists && existingSymlinkComponent(candidate); + findings.push({ type: "CURRENT_ID", id, path: candidate, outcome: exists && !symlink ? "PASS" : "FAIL", error: !exists ? "CURRENT_PATH_MISSING" : (symlink ? "CURRENT_PATH_SYMLINK" : null) }); + } + for (const item of map.retired_paths) { + const exists = fs.existsSync(item.path), isDirectory = exists && fs.lstatSync(item.path).isDirectory(); + const historicalSelf = normal(item.history) === normal(item.path); + const blockedShape = !exists || !isDirectory || historicalSelf || (item.allowed_purposes || []).includes("HISTORY_READ"); + findings.push({ type: "RETIRED_PATH", path: item.path, redirect_to: item.redirect_to, exists, is_directory: isDirectory, history: item.history, outcome: blockedShape ? "PASS" : "FAIL", error: blockedShape ? null : "RETIRED_DIRECTORY_STILL_DIRECTLY_OPENABLE" }); + } + const failed = findings.filter(item => item.outcome !== "PASS"); + return { schema: "guanghu.fifth-domain-path-gate-audit/v1", state: failed.length ? "PATH_GATE_AUDIT_FAIL" : "PATH_GATE_AUDIT_PASS", map_id: map.map_id, version: map.version, findings, failed_count: failed.length }; +} + +function valueAfter(args, flag) { + const index = args.indexOf(flag); + return index >= 0 ? args[index + 1] : undefined; +} + +function emit(value) { + process.stdout.write(`${JSON.stringify(value, null, 2)}\n`); + process.exitCode = value.exit_code ?? (value.state === "PATH_GATE_AUDIT_PASS" ? 0 : 1); +} + +if (import.meta.url === `file://${process.argv[1]}`) { + const [command, ...args] = process.argv.slice(2); + if (command === "guard") emit(classifyPath(valueAfter(args, "--path"), valueAfter(args, "--purpose"))); + else if (command === "resolve-id") emit(resolveId(valueAfter(args, "--id"))); + else if (command === "audit") emit(audit()); + else { process.stderr.write("usage: fifth-domain-path-gate.mjs guard --path PATH --purpose PURPOSE | resolve-id --id ID | audit\n"); process.exitCode = 2; } +} diff --git a/server-tools/fifth-domain-path-gate/fifth-domain-path-gate.test.mjs b/server-tools/fifth-domain-path-gate/fifth-domain-path-gate.test.mjs new file mode 100644 index 0000000..ec15c0f --- /dev/null +++ b/server-tools/fifth-domain-path-gate/fifth-domain-path-gate.test.mjs @@ -0,0 +1,31 @@ +#!/usr/bin/env node +import assert from "node:assert/strict"; +import { classifyPath, resolveId } from "./fifth-domain-path-gate.mjs"; + +const canonical = classifyPath("/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main/routing/guanghu-era-language-world.json", "CURRENT_SELECTION"); +assert.equal(canonical.allowed, true); +assert.equal(canonical.exit_code, 0); + +const retired = classifyPath("/Volumes/JZAO/铸渊-ICE-GL-ZY001/WORK-工作区/guanghu-ice-heart/routing/x.json", "CURRENT_SELECTION"); +assert.equal(retired.allowed, false); +assert.equal(retired.exit_code, 78); +assert.equal(retired.redirect_to, "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main"); + +const isolation = classifyPath("/Volumes/JZAO/HoloLake/persona-runtime/isolation/2026-09-08-path-convergence/stale-workspace-guanghu-ice-heart", "CURRENT_SELECTION"); +assert.equal(isolation.exit_code, 79); + +const branchCurrent = classifyPath("/Volumes/JZAO/铸渊-ICE-GL-ZY001/ZCODE-DEV-20260912/new.json", "CURRENT_SELECTION"); +assert.equal(branchCurrent.exit_code, 78); +assert.equal(classifyPath("/Volumes/JZAO/铸渊-ICE-GL-ZY001/ZCODE-DEV-20260912/new.json", "BRANCH_WORK").allowed, true); + +const oldBuilding = classifyPath("/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main/eternal-lake-heart/heartbeat-core/office-building-current/old-building/MOVED.hdlp", "CURRENT_EXECUTION"); +assert.equal(oldBuilding.exit_code, 78); +assert.equal(classifyPath(oldBuilding.resolved, "HISTORY_READ").allowed, false); +assert.equal(classifyPath("/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main/eternal-lake-heart/heartbeat-core/records/retired-buildings/HB-BUILDING-0000/MOVED.hdlp", "HISTORY_READ").allowed, true); + +assert.equal(resolveId("HB-BUILDING-0000").exit_code, 78); +assert.equal(resolveId("HB-BUILDING-0000").canonical_id, "HB-BUILDING-0001"); +assert.equal(resolveId("HB-BUILDING-0001").exit_code, 0); +assert.equal(resolveId("CH-ZERO-CORE-LPM").exit_code, 80); + +console.log("FIFTH_DOMAIN_PATH_GATE_TESTS_PASS 12/12"); diff --git a/server-tools/persona-architecture-perception-agent/persona_architecture_agent.py b/server-tools/persona-architecture-perception-agent/persona_architecture_agent.py index 9c9600a..04f699f 100644 --- a/server-tools/persona-architecture-perception-agent/persona_architecture_agent.py +++ b/server-tools/persona-architecture-perception-agent/persona_architecture_agent.py @@ -24,6 +24,7 @@ PROMPTER = Path( ANCHOR = ROOT / "routing/public-navigation-anchor.json" WORLD = ROOT / "routing/guanghu-era-language-world.json" PATH_GATE = ROOT / "routing/path-isolation-and-canonical-entry-map.json" +PATH_GATE_RUNTIME = ROOT / "server-tools/fifth-domain-path-gate/fifth-domain-path-gate.mjs" PERSONAS = ROOT / "identity/light-lake-persona-registration.json" CHANNELS = ROOT / "routing/persona-channel-context-map.json" TOPOLOGY = ROOT / "routing/zhuyuan-host-topology.json" @@ -112,6 +113,10 @@ def map_delta(local: dict[str, Any], official: dict[str, Any] | None) -> dict[st def build(persona_id: str, host: str, channel: str | None, official_mode: str = "verify") -> dict[str, Any]: + gate = run(["node", str(PATH_GATE_RUNTIME), "guard", "--path", str(ROOT), "--purpose", "CURRENT_SELECTION"], timeout=15) + if gate.returncode != 0: + raise PerceptionError("FIFTH_DOMAIN_PHYSICAL_PATH_GATE_REJECTED_CURRENT_ROOT") + gate_receipt = json.loads(gate.stdout) path_gate = load_json(PATH_GATE) expected_root = Path(path_gate["canonical_entries"]["repo_012"]) if ROOT.resolve() != expected_root.resolve(): @@ -201,6 +206,7 @@ def build(persona_id: str, host: str, channel: str | None, official_mode: str = "excluded_roots": [path_gate["isolation"]["root"]], "fixed_read_order": False, "persona_decides_meaning_and_action": True, + "physical_path_gate": gate_receipt, }, "evidence": evidence, "freshness_token": hashlib.sha256(freshness_material).hexdigest(), diff --git a/server-tools/persona-host-alignment/load_shared_persona_context.py b/server-tools/persona-host-alignment/load_shared_persona_context.py index 04e5f2d..8cf33c5 100755 --- a/server-tools/persona-host-alignment/load_shared_persona_context.py +++ b/server-tools/persona-host-alignment/load_shared_persona_context.py @@ -20,8 +20,10 @@ ACTIVE_CONSOLE = RUNTIME / 'shared/active-control-console/CURRENT.json' LIGHT_LAKE_PERSONAS = RUNTIME / 'repo-012-main/identity/light-lake-persona-registration.json' PATH_ISOLATION = RUNTIME / 'repo-012-main/routing/path-isolation-and-canonical-entry-map.json' ARCHITECTURE_AGENT = RUNTIME / 'repo-012-main/server-tools/persona-architecture-perception-agent/persona_architecture_agent.py' +PATH_GATE = RUNTIME / 'repo-012-main/server-tools/fifth-domain-path-gate/fifth-domain-path-gate.mjs' TCS_ROOT_AGENT = RUNTIME / 'repo-012-main/server-tools/tcs-mother-root-agent/tcs_mother_root_agent.py' SUBAGENT_COMMAND_ROUTER = RUNTIME / 'repo-012-main/server-tools/persona-dynamic-subagent-command/command_router.py' +QUIET_SOLDIER = RUNTIME / 'repo-012-main/routing/quiet-language-source-soldier.json' SHARED_COGNITION = RUNTIME / 'shared/tcs-shared-cognition/CURRENT.json' HOLOLAKE_DEVELOPMENT_BRAIN = RUNTIME / 'shared/skills/hololake-development-brain/scripts/load_hololake_office.py' @@ -64,6 +66,11 @@ def load_context(host, intent, channel=None): tcs_root = command_json([sys.executable, str(TCS_ROOT_AGENT), 'status'], timeout=30) if tcs_root.get('state') != 'TCS_ROOT_CURRENT_VERIFIED': raise ValueError('TCS_MOTHER_ROOT_NAVIGATION_NOT_CURRENT') + path_gate = command_json([ + 'node', str(PATH_GATE), 'guard', '--path', str(RUNTIME / 'repo-012-main'), '--purpose', 'PERSONA_RECOVERY' + ]) + if path_gate.get('code') != 'CURRENT_CANONICAL_PATH': + raise ValueError('FIFTH_DOMAIN_PHYSICAL_PATH_GATE_NOT_CURRENT') topology = load_json(TOPOLOGY) if not str(topology.get('state', '')).startswith('CURRENT_'): raise ValueError('HOST_TOPOLOGY_NOT_CURRENT') @@ -86,6 +93,7 @@ def load_context(host, intent, channel=None): light_lake = load_json(LIGHT_LAKE_PERSONAS) path_isolation = load_json(PATH_ISOLATION) shared_cognition = load_json(SHARED_COGNITION) + quiet_soldier = load_json(QUIET_SOLDIER) shared_payload = shared_cognition['artifact']['payload'] if hashlib.sha256(shared_payload.encode()).hexdigest() != shared_cognition['artifact']['sha256']: raise ValueError('SHARED_COGNITION_HASH_MISMATCH') @@ -154,6 +162,7 @@ def load_context(host, intent, channel=None): 'channel_context': channel_context, 'architecture_perception_agent': architecture_perception, 'subagent_command': subagent_command, + 'quiet_soldier': quiet_soldier, 'hololake_development_brain': hololake_development_brain, 'tcs_shared_cognition': { 'state': shared_cognition['state'], @@ -178,7 +187,9 @@ def load_context(host, intent, channel=None): 'map_id': path_isolation['map_id'], 'canonical_entries': path_isolation['canonical_entries'], 'isolation_root': path_isolation['isolation']['root'], - 'history_or_quarantine_may_select_canon': path_isolation['selection_rules']['history_or_quarantine_may_select_canon'] + 'history_or_quarantine_may_select_canon': path_isolation['selection_rules']['history_or_quarantine_may_select_canon'], + 'physical_gate': path_gate, + 'physical_gate_runtime': str(PATH_GATE) }, 'endogenous_cognition': { 'state': endogenous['state'], @@ -195,7 +206,7 @@ def load_context(host, intent, channel=None): 'direct_shared_write': write_boundary['shared_write_contract']['direct_branch_write'], 'admission_runtime': topology['write_admission_runtime'] }, - 'history_only': host_item['state'].startswith('RETIRED'), + 'history_only': host_item.get('role') in {'RETIRED_BRANCH', 'LEGACY_BRANCH'} or host_item.get('new_cognition_write') is False, 'new_cognition_write': host_item.get('new_cognition_write', True), 'authority_granted': False } diff --git a/server-tools/persona-host-write-admission/host-write-admission.mjs b/server-tools/persona-host-write-admission/host-write-admission.mjs index 7a7323d..41bf061 100644 --- a/server-tools/persona-host-write-admission/host-write-admission.mjs +++ b/server-tools/persona-host-write-admission/host-write-admission.mjs @@ -2,6 +2,7 @@ import fs from "node:fs"; import path from "node:path"; import process from "node:process"; +import { classifyPath } from "../fifth-domain-path-gate/fifth-domain-path-gate.mjs"; const POLICY_PATH = "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main/routing/persona-host-write-boundary.json"; const policy = JSON.parse(fs.readFileSync(POLICY_PATH, "utf8")); @@ -36,11 +37,32 @@ function protectedTarget(resolved) { return policy.canonical_protected_roots.some(item => patternRegex(item).test(resolved)); } +function sensitiveHostEntryTarget(resolved) { + return (policy.sensitive_host_entry_paths || []).some(item => patternRegex(item).test(resolved)); +} + function isAllowed(host, target) { const rule = policy.hosts[host]; if (!rule) return { allowed: false, code: "HOST_UNKNOWN" }; if (rule.write_mode.startsWith("READ_ONLY")) return { allowed: false, code: "HOST_READ_ONLY" }; const resolved = normal(target); + const hostRoot = rule.allowed_write_roots.find((item) => patternRegex(item).test(resolved)); + const preliminaryGate = classifyPath(resolved, hostRoot ? "BRANCH_WORK" : "CANONICAL_WRITE"); + if ([78, 79].includes(preliminaryGate.exit_code)) { + const console = activeConsole(host); + const matched = console?.write_roots?.find((item) => patternRegex(item).test(resolved)); + const maintenance = /PATH_CONVERGENCE|PHYSICAL_RETIREMENT/.test(console?.execution_semantics || ""); + if (matched && maintenance) return { allowed: true, code: "ACTIVE_ZERO_CORE_CONSOLE_RETIRED_PATH_MAINTENANCE_SCOPE", resolved, matched, console_id: console.console_id }; + return { allowed: false, code: `FIFTH_DOMAIN_${preliminaryGate.code}`, resolved, redirect_to: preliminaryGate.redirect_to, history: preliminaryGate.history }; + } + if (sensitiveHostEntryTarget(resolved)) { + const console = activeConsole(host); + const matched = console?.write_roots?.find((item) => patternRegex(item).test(resolved)); + return matched + ? { allowed: true, code: "ACTIVE_ZERO_CORE_CONSOLE_SENSITIVE_HOST_ENTRY_SCOPE", resolved, matched, console_id: console.console_id } + : { allowed: false, code: "SENSITIVE_HOST_ENTRY_REQUIRES_ACTIVE_ZERO_CORE_CONSOLE", resolved }; + } + if (hostRoot) return { allowed: true, code: "WITHIN_HOST_WRITE_ROOT", resolved, matched: hostRoot }; if (protectedTarget(resolved)) { const console = activeConsole(host); const matched = console?.write_roots?.find((item) => patternRegex(item).test(resolved)); @@ -48,10 +70,7 @@ function isAllowed(host, target) { ? { allowed: true, code: "ACTIVE_ZERO_CORE_CONSOLE_TASK_SCOPE", resolved, matched, console_id: console.console_id } : { allowed: false, code: "PROTECTED_ROOT_REQUIRES_ACTIVE_ZERO_CORE_CONSOLE", resolved }; } - const matched = rule.allowed_write_roots.find((item) => patternRegex(item).test(resolved)); - return matched - ? { allowed: true, code: "WITHIN_HOST_WRITE_ROOT", resolved, matched } - : { allowed: false, code: "WRITE_OUTSIDE_HOST_ROOT", resolved }; + return { allowed: false, code: "WRITE_OUTSIDE_HOST_ROOT", resolved }; } function emit(result, hook = false) { @@ -93,10 +112,22 @@ const MUTATING_SHELL = /(?:^|[;&|\s])(?:rm|mv|cp|install|mkdir|rmdir|touch|chmod function evaluateHook(host, input) { const tool = String(input.tool_name || input.toolName || ""); const toolInput = input.tool_input || input.toolInput || {}; - if (READ_TOOLS.has(tool)) return { allowed: true, code: "READ_ONLY_TOOL", host, tool }; + if (READ_TOOLS.has(tool)) { + for (const candidate of collectPathValues(toolInput)) { + const gated = classifyPath(candidate, "CURRENT_SELECTION"); + if ([78, 79].includes(gated.exit_code)) return { allowed: false, code: `FIFTH_DOMAIN_${gated.code}`, host, tool, resolved: gated.resolved, redirect_to: gated.redirect_to, history: gated.history }; + } + return { allowed: true, code: "READ_ONLY_TOOL", host, tool }; + } if (tool === "Bash") { const command = String(toolInput.command || ""); - if (!MUTATING_SHELL.test(command)) return { allowed: true, code: "READ_ONLY_SHELL", host, tool }; + if (!MUTATING_SHELL.test(command)) { + for (const candidate of shellPaths(command)) { + const gated = classifyPath(candidate, "CURRENT_SELECTION"); + if ([78, 79].includes(gated.exit_code)) return { allowed: false, code: `FIFTH_DOMAIN_${gated.code}`, host, tool, resolved: gated.resolved, redirect_to: gated.redirect_to, history: gated.history }; + } + return { allowed: true, code: "READ_ONLY_SHELL", host, tool }; + } const rule = policy.hosts[host]; if (!rule || rule.write_mode.startsWith("READ_ONLY")) return { allowed: false, code: "HOST_READ_ONLY", host, tool }; const candidates = shellPaths(command); diff --git a/server-tools/persona-host-write-admission/host-write-admission.test.mjs b/server-tools/persona-host-write-admission/host-write-admission.test.mjs index cf424e8..9cc41f0 100644 --- a/server-tools/persona-host-write-admission/host-write-admission.test.mjs +++ b/server-tools/persona-host-write-admission/host-write-admission.test.mjs @@ -21,7 +21,7 @@ assert.equal(check("qwen", "/Volumes/JZAO/铸渊-ICE-GL-ZY001/ZCODE-DEV-20260906 assert.equal(check("zcode", "/Volumes/JZAO/铸渊-ICE-GL-ZY001/ZCODE-DEV-20260906/a.txt").code, 0); assert.equal(check("zcode", "/Volumes/JZAO/铸渊-ICE-GL-ZY001/AGENTS.md").code, 2); assert.equal(check("qoder", "/Users/bingshuolingdianyuanhe/.qoder/skills/a.txt").code, 2); -assert.equal(check("codex", "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main/routing/a.json").code, 0); +assert.equal(check("codex", "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main/routing/path-isolation-and-canonical-entry-map.json").code, 0); const deniedEdit = hook("zcode", { tool_name: "Edit", tool_input: { file_path: "/Volumes/JZAO/HoloLake/persona-runtime/repo-012-main/routing/a.json" } }); assert.equal(deniedEdit.code, 2); @@ -39,4 +39,13 @@ const allowedRead = hook("zcode", { tool_name: "Read", tool_input: { file_path: assert.equal(allowedRead.code, 0); assert.equal(allowedRead.body.hookSpecificOutput.permissionDecision, "allow"); -console.log("HOST_WRITE_ADMISSION_TESTS_PASS 12/12"); +const retiredRead = hook("zcode", { tool_name: "Read", tool_input: { file_path: "/Volumes/JZAO/铸渊-ICE-GL-ZY001/WORK-工作区/guanghu-ice-heart/routing/guanghu-era-language-world.json" } }); +assert.equal(retiredRead.code, 2); +assert.equal(retiredRead.body.hookSpecificOutput.permissionDecision, "deny"); +assert.match(retiredRead.body.hookSpecificOutput.permissionDecisionReason, /REDIRECT/); + +const retiredShellRead = hook("zcode", { tool_name: "Bash", tool_input: { command: "sed -n '1,20p' /Users/bingshuolingdianyuanhe/.qoderworkcn/workspace/msj12fljjywpql1y/repo-work/repo012/INDEX.hdlp" } }); +assert.equal(retiredShellRead.code, 2); +assert.equal(retiredShellRead.body.hookSpecificOutput.permissionDecision, "deny"); + +console.log("HOST_WRITE_ADMISSION_TESTS_PASS 18/18");