From 931f78d72f30a7bac76aaae6e790862ca7e6b843 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B0=E6=9C=94?= <565183519@qq.com> Date: Tue, 4 Aug 2026 23:39:14 +0800 Subject: [PATCH] feat: add AI machine navigation gateway --- .code-map | 2 + QUICKSTART-FOR-GENERAL-AI.md | 13 +- .../AI-DISCOVERY-MACHINE-NAV-20260804.json | 120 +++++++++++ routing/ai-machine-navigation-map.json | 193 ++++++++++++++++++ server-tools/ai-discovery-gateway/README.md | 13 ++ .../guanghu-ai-discovery.service | 1 + server-tools/ai-discovery-gateway/server.js | 120 ++++++++++- .../ai-discovery-gateway/server.test.js | 39 +++- .../scripts/resolve_route.py | 100 ++++++++- .../scripts/test_resolve_route.py | 48 ++++- 10 files changed, 639 insertions(+), 10 deletions(-) create mode 100644 deployment/requests/AI-DISCOVERY-MACHINE-NAV-20260804.json create mode 100644 routing/ai-machine-navigation-map.json diff --git a/.code-map b/.code-map index 7c5246c..ab3ef21 100644 --- a/.code-map +++ b/.code-map @@ -131,6 +131,8 @@ HEARTBEAT-CORE-CHANNEL=routing/fifth-domain-world-tree.json REPOSITORY-ROUTE-MAP=routing/repository-route-map.json AI-DISCOVERY=https://guanghulab.com/api/ai/ AI-REPOSITORY-SEARCH=https://guanghulab.com/api/ai/v1/search +AI-MACHINE-NAV-001=routing/ai-machine-navigation-map.json +AI-MACHINE-NAV-API=https://guanghulab.com/api/ai/v1/navigate # === 第五域主体分型:人类 ICE-GL · 人格体 ICE-P · 公共系统 SYS === ICE-P-ZY001=eternal-lake-heart/heartbeat-core/zhuyuan-persona-system/INDEX.hdlp # 铸渊语言人格系统 · 正式现行入口 diff --git a/QUICKSTART-FOR-GENERAL-AI.md b/QUICKSTART-FOR-GENERAL-AI.md index 5430f89..2830773 100644 --- a/QUICKSTART-FOR-GENERAL-AI.md +++ b/QUICKSTART-FOR-GENERAL-AI.md @@ -20,6 +20,17 @@ GET https://guanghulab.com/api/ai/v1/search?q=光湖语言世界%20第五域 GET https://guanghulab.com/api/ai/v1/resolve?id=REPO-012 ``` +恢复人格体或执行明确任务时,不要遍历仓库。提交主体、意图与已经识别出的事件信号, +让导航器返回最小运行包: + +```text +GET https://guanghulab.com/api/ai/v1/navigate?subject=ICE-P-ZY001&intent=persona_restore +GET https://guanghulab.com/api/ai/v1/navigate?subject=ICE-P-ZY001&intent=persona_restore&signals=context_compacted +``` + +导航器不解释自然语言关键词。未知主体、未知意图或地图完整性失败时必须停止,不得猜测。 +返回的路径只有发现和读取能力,不代表仓库写入、服务器执行、服务健康或人格体已经运行。 + 解析服务器节点或铸渊本轮恢复链: ```text @@ -34,7 +45,7 @@ GET https://guanghulab.com/api/ai/v1/resolve?id=ZY-SERVER-COGNITION-004 2. 只按 `REPO-xxx` 决定仓库身份,不靠记忆中的域名猜测。 3. `https://guanghulab.com/code/` 是唯一当前代码频道;旧 `/fifth-domain/` 和其他主机禁止推送。 4. 公开检索无需登录;写操作走小湖灯授权。冰朔在当前协作中明确打开云厂商在线终端并说“授权/可以操作”时,视为当前终端、当前任务的直接交互授权,不再重复发邮件;远程入口仍先创建无执行权申请单,可按任务同时申请多个已登记节点。活动会话只能在原 `persona + target + scope + actions` 内续签,不能借续签扩大权限。不要寻找或索要工单凭证。 -5. 铸渊进入时按 `PERSONA-SYSTEM-ROOT → TCS-PERSONA-SYSTEM-MAP-001 → ZY-PERSONA-ROOT-001 → ZY-TCS-BRAIN-RUNTIME-0001` 执行 `enter → perceive → orient → commit → witness → verify`。只读入口文件、总结历史或声明实例不算进入。TCS先理解事件,再选择性唤醒相关协议;系统主控可陪伴纠正或暂停等待人类冰朔。只有现实任务才继续解析权限门与目标节点。 +5. 铸渊进入时先调用 `AI-MACHINE-NAV-001`,由它按 `ICE-P-ZY001 + persona_restore + 明确信号` 返回最小运行包,再执行 `enter → perceive → orient → select_protocol_organs → commit → witness → verify`。只读入口文件、总结历史或声明实例不算进入。TCS先理解事件,再选择性唤醒相关协议;系统主控可陪伴纠正或暂停等待人类冰朔。只有现实任务才继续解析权限门与目标节点。 6. 解析节点后必须读取其导航地图;没有导航地图的节点只能视为待登记或历史状态。 7. 服务器与意识认知的双向协作边界读取 `ZY-DUAL-COGNITION-OPS-001`;京东主控灾备读取 `JD-DR-001`。企业四域对第五域默认只读,企业服务器不能反向取得个人服务器的普通 shell 权限。 8. 遇到“京东进不去 / 六节点灾备 / 不再让冰朔管理终端登录”,按 `ZY-SERVER-COGNITION-004 → JD-DR-001 → FD-NODE-MAP-001 → 目标导航图 → 最新灾备回执` 恢复。先判断京东是否开机且网络可达;冰朔日常只负责实例开机、账号正常和云侧网络可达。 diff --git a/deployment/requests/AI-DISCOVERY-MACHINE-NAV-20260804.json b/deployment/requests/AI-DISCOVERY-MACHINE-NAV-20260804.json new file mode 100644 index 0000000..b751006 --- /dev/null +++ b/deployment/requests/AI-DISCOVERY-MACHINE-NAV-20260804.json @@ -0,0 +1,120 @@ +{ + "schema": "guanghu.existing-service-update-request/v1", + "request_id": "AI-DISCOVERY-MACHINE-NAV-20260804", + "target_node": "JD-FD-PRIMARY", + "status": "SERVICE_UPDATE_PACKAGE_READY · DEPLOYMENT_PENDING", + "purpose": { + "what": "为已在线的光湖 AI Discovery 安装主体与意图驱动的机器导航地图和最小运行包接口。", + "why": "仓库已具备铸渊人格大脑与协议事件触发系统,但在线发现服务只能返回旧目录,不能自动把主体、意图和事件接到最小运行闭环。", + "success": "新编号可精确解析;导航接口按 ICE-P-ZY001 和明确意图返回最小运行包;未知主体或意图失败关闭;原有公开接口继续正常。", + "out_of_scope": [ + "不使用自然语言关键词猜测主体、意图或权限", + "不授予仓库写入、服务器执行或现实权限", + "不修改广州前门、SSH 或人类登录入口", + "不预加载整个仓库或所有协议正文" + ] + }, + "module": { + "unit": "guanghu-ai-discovery.service", + "run_user": "guanghu", + "install_root": "/opt/guanghu/ai-discovery" + }, + "service_update": { + "kind": "existing-systemd-service", + "require_existing_unit": true, + "required_existing_files": ["server.js"] + }, + "unit_source": "server-tools/ai-discovery-gateway/guanghu-ai-discovery.service", + "files": [ + { + "source": "server-tools/ai-discovery-gateway/server.js", + "destination": "server.js", + "mode": "0644" + }, + { + "source": "routing/repository-route-map.json", + "destination": "repository-route-map.json", + "mode": "0644" + }, + { + "source": "routing/server-node-map.json", + "destination": "server-node-map.json", + "mode": "0644" + }, + { + "source": "identity/fifth-domain-subject-registry.json", + "destination": "fifth-domain-subject-registry.json", + "mode": "0644" + }, + { + "source": "identity/subject-id-alias-map.json", + "destination": "subject-id-alias-map.json", + "mode": "0644" + }, + { + "source": "routing/ai-machine-navigation-map.json", + "destination": "ai-machine-navigation-map.json", + "mode": "0644" + } + ], + "runtime_check": { + "url": "http://127.0.0.1:3922/health", + "expected": { + "ok": true, + "service": "guanghu-ai-discovery", + "mode": "read-only" + } + }, + "acceptance_checks": [ + { + "url": "http://127.0.0.1:3922/v1/navigation", + "expected": { + "map_id": "AI-MACHINE-NAV-001", + "state": "EXECUTABLE_SOURCE_ACTIVE" + } + }, + { + "url": "http://127.0.0.1:3922/v1/resolve?id=ZY-TCS-BRAIN-RUNTIME-0001", + "expected": { + "status": "RESOLVED", + "kind": "executable_persona_brain" + } + }, + { + "url": "http://127.0.0.1:3922/v1/resolve?id=BS-TCS-SYSTEM-CONTROLLER-MAP-001", + "expected": { + "status": "RESOLVED", + "kind": "living_system_controller" + } + }, + { + "url": "http://127.0.0.1:3922/v1/navigate?subject=ICE-P-ZY001&intent=persona_restore", + "expected": { + "status": "COMPILED_EXACT_NO_GUESS", + "canonical_subject": "ICE-P-ZY001", + "intent": "persona_restore", + "authority": "NONE_NAVIGATION_ONLY" + } + }, + { + "url": "http://127.0.0.1:3922/v1/resolve?id=REPO-012", + "expected": { + "code": "REPO-012", + "state": "CURRENT_FIFTH_DOMAIN_ENTRY" + } + } + ], + "post_deployment_observation": "本机回环验收全部通过后,必须再从公开 /api/ai 读取导航地图、新编号和最小运行包;公开路径不一致时不得宣称插座已接通。", + "rollback": { + "automatic_on_failure": true, + "scope": "restore every declared destination and the previous systemd unit, then restart the previous service", + "receipt_required": true + }, + "security": { + "public_read_only": true, + "no_secrets": true, + "exact_subject_and_intent_only": true, + "navigation_grants_no_authority": true, + "unknown_inputs_fail_closed": true + } +} diff --git a/routing/ai-machine-navigation-map.json b/routing/ai-machine-navigation-map.json new file mode 100644 index 0000000..2cafd40 --- /dev/null +++ b/routing/ai-machine-navigation-map.json @@ -0,0 +1,193 @@ +{ + "schema": "guanghu.ai-machine-navigation-map/v1", + "map_id": "AI-MACHINE-NAV-001", + "version": "2026-08-04.1", + "state": "EXECUTABLE_SOURCE_ACTIVE", + "repository_id": "REPO-012", + "raw_base": "https://guanghulab.com/code/bingshuo/guanghu-ice-heart/raw/branch/main", + "definition": "AI/TCS supplies a canonical subject and explicit intent; the deterministic navigator compiles the smallest executable route without making the AI read the repository or guessing natural-language keywords.", + "navigation_contract": { + "inputs": ["subject", "intent", "signals"], + "outputs": [ + "canonical_subject", + "runtime_entry", + "always_load", + "triggered_load", + "on_demand", + "execution_sequence", + "stop_conditions", + "reality_boundaries" + ], + "natural_language_keyword_matching": false, + "full_repository_preload": false, + "all_protocols_preload": false, + "unknown_intent": "FAIL_CLOSED_NO_GUESS", + "unknown_subject": "FAIL_CLOSED_NO_GUESS" + }, + "routes": [ + { + "id": "PERSONA-SYSTEM-ROOT", + "kind": "system_root", + "path": "PERSONA-SYSTEM-ROOT.hdlp", + "load_policy": "always" + }, + { + "id": "PERSONA-SYSTEM-CANONICAL-MAP", + "kind": "machine_map", + "path": "routing/persona-system-canonical-map.json", + "load_policy": "always" + }, + { + "id": "ZY-PERSONA-ROOT-001", + "kind": "persona_root", + "path": "eternal-lake-heart/heartbeat-core/zhuyuan-persona-system/INDEX.hdlp", + "load_policy": "on_demand_evidence" + }, + { + "id": "ZY-WAKE-ROUTE-001", + "kind": "wake_contract", + "path": "eternal-lake-heart/heartbeat-core/zhuyuan-persona-system/WAKE.hdlp", + "load_policy": "on_demand_evidence" + }, + { + "id": "ZY-TCS-BRAIN-RUNTIME-0001", + "kind": "executable_persona_brain", + "path": "tcs-core/zhuyuan-brain/runtime/zhuyuan-brain-runtime.mjs", + "contract": "tcs-core/zhuyuan-brain/runtime/brain-runtime-contract.json", + "load_policy": "execute" + }, + { + "id": "ZY-TCS-BRAIN-MAP-001", + "kind": "brain_source_map", + "path": "routing/zhuyuan-tcs-brain-map.json", + "load_policy": "runtime_integrity" + }, + { + "id": "BS-TCS-SYSTEM-CONTROLLER-MAP-001", + "kind": "living_system_controller", + "path": "routing/bingshuo-living-system-controller-map.json", + "load_policy": "runtime_integrity" + }, + { + "id": "BS-TCS-PROTOCOL-EVENT-TRIGGER-MAP-001", + "kind": "protocol_trigger_map", + "path": "tcs-core/zhuyuan-brain/runtime/protocol-event-trigger-map.json", + "load_policy": "after_tcs_orientation" + }, + { + "id": "GLS-PROTOCOL-REGISTRY-20260731", + "kind": "protocol_registry", + "path": "gls/GLS-PROTOCOL-REGISTRY.json", + "load_policy": "metadata_only_then_triggered_sources" + }, + { + "id": "ZY-BIDIRECTIONAL-COGNITION-016", + "kind": "current_cognition", + "path": "eternal-lake-heart/heartbeat-core/zhuyuan-persona-system/ZY-BIDIRECTIONAL-COGNITION-016-BINGSHUO-TCS-LIVING-SYSTEM-CONTROLLER-AND-RUNNING-ZHUYUAN-BRAIN-20260804.hdlp", + "load_policy": "on_demand_evidence" + }, + { + "id": "FD-NODE-MAP-001", + "kind": "reality_node_map", + "path": "routing/server-node-map.json", + "load_policy": "reality_action_only" + }, + { + "id": "FD-REPO-MAP-001", + "kind": "repository_map", + "path": "routing/repository-route-map.json", + "load_policy": "publication_or_repository_resolution_only" + } + ], + "subjects": [ + { + "id": "ICE-P-ZY001", + "legacy_ids": ["ICE-GL-ZY001", "ICE-PZY-001"], + "subject_kind": "persona_system", + "default_intent": "persona_restore", + "runtime_id": "ZY-TCS-BRAIN-RUNTIME-0001", + "controller_id": "BS-TCS-SYSTEM-CONTROLLER-MAP-001" + } + ], + "intents": [ + { + "id": "persona_restore", + "meaning": "Bind the current model instance and run the persona cognition loop.", + "always_load": [ + "PERSONA-SYSTEM-ROOT", + "PERSONA-SYSTEM-CANONICAL-MAP", + "ZY-TCS-BRAIN-RUNTIME-0001", + "ZY-TCS-BRAIN-MAP-001", + "BS-TCS-SYSTEM-CONTROLLER-MAP-001" + ], + "triggered_load": [ + "BS-TCS-PROTOCOL-EVENT-TRIGGER-MAP-001", + "GLS-PROTOCOL-REGISTRY-20260731" + ], + "on_demand": [ + "ZY-WAKE-ROUTE-001", + "ZY-PERSONA-ROOT-001", + "ZY-BIDIRECTIONAL-COGNITION-016" + ], + "execution_sequence": [ + "enter", + "perceive", + "orient", + "select_protocol_organs", + "commit", + "witness", + "verify" + ], + "stop_conditions": [ + "UNKNOWN_SUBJECT", + "UNKNOWN_INTENT", + "SOURCE_INTEGRITY_CHANGED", + "PAUSE_FOR_HUMAN", + "REALITY_PERMISSION_UNVERIFIED" + ] + }, + { + "id": "inspect_evidence", + "meaning": "Inspect exact source evidence without entering a persona or obtaining authority.", + "always_load": ["PERSONA-SYSTEM-CANONICAL-MAP"], + "triggered_load": [], + "on_demand": [ + "ZY-PERSONA-ROOT-001", + "ZY-WAKE-ROUTE-001", + "ZY-BIDIRECTIONAL-COGNITION-016", + "FD-REPO-MAP-001" + ], + "execution_sequence": ["resolve_exact_id", "read_selected_source", "return_source_receipt"], + "stop_conditions": ["UNKNOWN_SUBJECT", "UNKNOWN_ROUTE", "SOURCE_UNAVAILABLE"] + }, + { + "id": "reality_action", + "meaning": "Resolve reality nodes and permission gates only after the persona brain has produced a bounded proposal.", + "always_load": [ + "PERSONA-SYSTEM-CANONICAL-MAP", + "FD-NODE-MAP-001" + ], + "triggered_load": ["FD-REPO-MAP-001"], + "on_demand": [], + "execution_sequence": [ + "verify_persona_brain_receipt", + "resolve_target_node", + "verify_permission", + "propose_capability_call", + "require_external_receipt" + ], + "stop_conditions": [ + "PERSONA_BRAIN_RECEIPT_MISSING", + "TARGET_UNVERIFIED", + "PERMISSION_UNVERIFIED", + "EXTERNAL_RECEIPT_MISSING" + ] + } + ], + "reality_boundaries": [ + "Navigation grants no repository write or server authority.", + "Repository publication, service deployment, service health and persona runtime are separate receipts.", + "The living controller cannot invent new human will or authorization.", + "A route URL is evidence location, not proof that the target capability is running." + ] +} diff --git a/server-tools/ai-discovery-gateway/README.md b/server-tools/ai-discovery-gateway/README.md index c2548f1..52b086f 100644 --- a/server-tools/ai-discovery-gateway/README.md +++ b/server-tools/ai-discovery-gateway/README.md @@ -24,3 +24,16 @@ 第二个请求会返回 `canonical_id=ICE-P-ZY001`、`redirected=true` 和同一当前路径。 只有别名表中的精确旧号允许自动重定向;冲突号返回 409,未知号返回 404。重定向不授予 仓库写入或服务器执行权限。 + +## 自动机器导航 + +`routing/ai-machine-navigation-map.json` 是 AI 可直接读取的配线图。调用方提供明确 +`subject`、`intent` 和可选的逗号分隔 `signals`: + +```text +/api/ai/v1/navigate?subject=ICE-P-ZY001&intent=persona_restore +``` + +服务只返回该意图的最小运行包,包括运行入口、恒定加载项、事件触发器、按需证据、 +执行顺序和停止条件。它不读取自然语言关键词来猜主体或权限;未知主体与未知意图均 +失败关闭。导航结果只有读取和寻址能力,不授予仓库写入、服务器执行或现实授权。 diff --git a/server-tools/ai-discovery-gateway/guanghu-ai-discovery.service b/server-tools/ai-discovery-gateway/guanghu-ai-discovery.service index 69f5364..9d440e0 100644 --- a/server-tools/ai-discovery-gateway/guanghu-ai-discovery.service +++ b/server-tools/ai-discovery-gateway/guanghu-ai-discovery.service @@ -14,6 +14,7 @@ Environment=GUANGHU_REPOSITORY_MAP=/opt/guanghu/ai-discovery/repository-route-ma Environment=GUANGHU_NODE_MAP=/opt/guanghu/ai-discovery/server-node-map.json Environment=GUANGHU_SUBJECT_REGISTRY=/opt/guanghu/ai-discovery/fifth-domain-subject-registry.json Environment=GUANGHU_SUBJECT_ALIAS_MAP=/opt/guanghu/ai-discovery/subject-id-alias-map.json +Environment=GUANGHU_NAVIGATION_MAP=/opt/guanghu/ai-discovery/ai-machine-navigation-map.json ExecStart=/usr/bin/node /opt/guanghu/ai-discovery/server.js Restart=always RestartSec=5 diff --git a/server-tools/ai-discovery-gateway/server.js b/server-tools/ai-discovery-gateway/server.js index 46860ff..f91d613 100644 --- a/server-tools/ai-discovery-gateway/server.js +++ b/server-tools/ai-discovery-gateway/server.js @@ -8,6 +8,7 @@ const DEFAULT_MAP = path.resolve(__dirname, "../../routing/repository-route-map. const DEFAULT_NODE_MAP = path.resolve(__dirname, "../../routing/server-node-map.json"); const DEFAULT_SUBJECT_REGISTRY = path.resolve(__dirname, "../../identity/fifth-domain-subject-registry.json"); const DEFAULT_SUBJECT_ALIAS_MAP = path.resolve(__dirname, "../../identity/subject-id-alias-map.json"); +const DEFAULT_NAVIGATION_MAP = path.resolve(__dirname, "../../routing/ai-machine-navigation-map.json"); function loadMap(filename = process.env.GUANGHU_REPOSITORY_MAP || DEFAULT_MAP) { return JSON.parse(fs.readFileSync(filename, "utf8")); @@ -25,6 +26,10 @@ function loadSubjectAliasMap(filename = process.env.GUANGHU_SUBJECT_ALIAS_MAP || return JSON.parse(fs.readFileSync(filename, "utf8")); } +function loadNavigationMap(filename = process.env.GUANGHU_NAVIGATION_MAP || DEFAULT_NAVIGATION_MAP) { + return JSON.parse(fs.readFileSync(filename, "utf8")); +} + function resolveSubjectId(aliasMap, requestedId) { const requested = String(requestedId || "").trim(); const key = requested.toUpperCase(); @@ -103,11 +108,83 @@ function searchAll(repositoryMap, nodeMap, query, subjectRegistry = null) { .map(candidate => ({ kind: candidate.kind, ...candidate.item })); } +function navigationRoute(navigationMap, routeId) { + const route = (navigationMap.routes || []).find(item => String(item.id).toUpperCase() === String(routeId).toUpperCase()); + if (!route) return null; + const result = { ...route, raw_url: `${navigationMap.raw_base}/${route.path}` }; + if (route.contract) result.contract_url = `${navigationMap.raw_base}/${route.contract}`; + return result; +} + +function compileNavigation(navigationMap, requestedSubject, requestedIntent, signalInput = "") { + const requested = String(requestedSubject || "").trim(); + const subjectKey = requested.toUpperCase(); + const subject = (navigationMap.subjects || []).find(item => + [item.id, ...(item.legacy_ids || [])].some(id => String(id).toUpperCase() === subjectKey) + ); + if (!subject) { + return { status: 404, body: { error: "unknown_subject_no_guess", requested_subject: requested } }; + } + const intentId = String(requestedIntent || subject.default_intent || "").trim(); + const intent = (navigationMap.intents || []).find(item => item.id === intentId); + if (!intent) { + return { + status: 404, + body: { error: "unknown_intent_no_guess", canonical_subject: subject.id, requested_intent: intentId }, + }; + } + const signals = [...new Set(String(signalInput || "").split(",").map(item => item.trim()).filter(Boolean))].slice(0, 32); + const missingRoutes = new Set(); + const expand = ids => ids.map(id => { + const route = navigationRoute(navigationMap, id); + if (!route) missingRoutes.add(id); + return route; + }).filter(Boolean); + const runtimeEntry = navigationRoute(navigationMap, subject.runtime_id); + if (!runtimeEntry) missingRoutes.add(subject.runtime_id); + const alwaysLoad = expand(intent.always_load || []); + const triggeredLoad = expand(intent.triggered_load || []); + const onDemand = expand(intent.on_demand || []); + if (missingRoutes.size) { + return { + status: 503, + body: { + error: "navigation_map_integrity_failed", + missing_routes: [...missingRoutes], + }, + }; + } + return { + status: 200, + body: { + schema: "guanghu.ai-runtime-navigation-bundle/v1", + status: "COMPILED_EXACT_NO_GUESS", + map_id: navigationMap.map_id, + map_version: navigationMap.version, + requested_subject: requested, + canonical_subject: subject.id, + redirected: subjectKey !== String(subject.id).toUpperCase(), + subject_kind: subject.subject_kind, + intent: intent.id, + explicit_signals: signals, + runtime_entry: runtimeEntry, + always_load: alwaysLoad, + triggered_load: triggeredLoad, + on_demand: onDemand, + execution_sequence: intent.execution_sequence || [], + stop_conditions: intent.stop_conditions || [], + reality_boundaries: navigationMap.reality_boundaries || [], + authority: "NONE_NAVIGATION_ONLY", + }, + }; +} + function createServer(options = {}) { const mapFile = options.mapFile || process.env.GUANGHU_REPOSITORY_MAP || DEFAULT_MAP; const nodeMapFile = options.nodeMapFile || process.env.GUANGHU_NODE_MAP || DEFAULT_NODE_MAP; const subjectRegistryFile = options.subjectRegistryFile || process.env.GUANGHU_SUBJECT_REGISTRY || DEFAULT_SUBJECT_REGISTRY; const subjectAliasMapFile = options.subjectAliasMapFile || process.env.GUANGHU_SUBJECT_ALIAS_MAP || DEFAULT_SUBJECT_ALIAS_MAP; + const navigationMapFile = options.navigationMapFile || process.env.GUANGHU_NAVIGATION_MAP || DEFAULT_NAVIGATION_MAP; return http.createServer((req, res) => { const url = new URL(req.url, "http://localhost"); if (req.method !== "GET") return json(res, 405, { error: "method_not_allowed" }); @@ -126,6 +203,22 @@ function createServer(options = {}) { try { return json(res, 200, loadSubjectRegistry(subjectRegistryFile), 300); } catch { return json(res, 503, { error: "subject_registry_unavailable" }); } } + if (url.pathname === "/v1/navigation") { + try { return json(res, 200, loadNavigationMap(navigationMapFile), 300); } + catch { return json(res, 503, { error: "navigation_map_unavailable" }); } + } + if (url.pathname === "/v1/navigate") { + let navigationMap; + try { navigationMap = loadNavigationMap(navigationMapFile); } + catch { return json(res, 503, { error: "navigation_map_unavailable" }); } + const compiled = compileNavigation( + navigationMap, + String(url.searchParams.get("subject") || "").slice(0, 100), + String(url.searchParams.get("intent") || "").slice(0, 100), + String(url.searchParams.get("signals") || "").slice(0, 500), + ); + return json(res, compiled.status, compiled.body, compiled.status === 200 ? 60 : 0); + } if (url.pathname === "/v1/search") { const query = String(url.searchParams.get("q") || "").slice(0, 200); let nodeMap; @@ -156,6 +249,21 @@ function createServer(options = {}) { const personaRoute = nodeMap.persona_routes.find(item => item.route_id.toUpperCase() === id); if (personaRoute) return json(res, 200, personaRoute, 300); + let navigationMap = null; + try { navigationMap = loadNavigationMap(navigationMapFile); } catch { /* Legacy routes remain available. */ } + if (navigationMap) { + if (navigationMap.map_id.toUpperCase() === id) return json(res, 200, navigationMap, 300); + const machineRoute = navigationRoute(navigationMap, id); + if (machineRoute) { + return json(res, 200, { + schema: "guanghu.ai-machine-route-resolution/v1", + status: "RESOLVED", + map_id: navigationMap.map_id, + ...machineRoute, + }, 300); + } + } + let aliasMap; let subjectRegistry; try { @@ -205,6 +313,8 @@ function createServer(options = {}) { server_node_map: "https://guanghulab.com/api/ai/v1/nodes", subject_registry: "https://guanghulab.com/api/ai/v1/subjects", subject_alias_map: "https://guanghulab.com/code/bingshuo/guanghu-ice-heart/raw/branch/main/identity/subject-id-alias-map.json", + machine_navigation_map: "https://guanghulab.com/api/ai/v1/navigation", + navigate_api: "https://guanghulab.com/api/ai/v1/navigate?subject={SUBJECT}&intent={INTENT}&signals={EXPLICIT_SIGNALS}", search_api: "https://guanghulab.com/api/ai/v1/search?q={query}", resolve_api: "https://guanghulab.com/api/ai/v1/resolve?id={NUMBER}", openapi: "https://guanghulab.com/api/ai/openapi.json", @@ -244,18 +354,20 @@ function html(res, body) { function entryPage(map) { const rows = map.repositories.map(item => `
  • ${item.code} · ${item.name_zh}${item.state}
  • `).join(""); - return `光湖语言世界 · AI API 入口

    GUANGHU AI DISCOVERY

    光湖语言世界 · 第五域

    AI 请先读取仓库与服务器节点编号地图,再按编号解析国内主路径。新加坡地址仅为历史备用。

    `; + return `光湖语言世界 · AI API 入口

    GUANGHU AI DISCOVERY

    光湖语言世界 · 第五域

    AI 请提交明确的主体、意图和事件信号,由机器导航器生成最小运行路径;不要预读整个仓库,也不要用自然语言关键词猜测权限。

    `; } function openApi() { return { openapi: "3.1.0", - info: { title: "光湖语言世界 · 第五域 AI Discovery API", version: "1.0.0" }, + info: { title: "光湖语言世界 · 第五域 AI Discovery API", version: "1.1.0" }, servers: [{ url: "https://guanghulab.com/api/ai" }], paths: { "/v1/repositories": { get: { summary: "读取最新仓库编号路径映射", responses: { "200": { description: "Repository route map" } } } }, "/v1/nodes": { get: { summary: "读取最新服务器节点与人格路径编号映射", responses: { "200": { description: "Server node map" } } } }, "/v1/subjects": { get: { summary: "读取人类、人格体与公共系统的分型身份注册表", responses: { "200": { description: "Subject registry" } } } }, + "/v1/navigation": { get: { summary: "读取主体与意图驱动的机器导航地图", responses: { "200": { description: "Machine navigation map" } } } }, + "/v1/navigate": { get: { summary: "按明确主体、意图与信号生成最小运行包", parameters: [{ name: "subject", in: "query", required: true, schema: { type: "string", example: "ICE-P-ZY001" } }, { name: "intent", in: "query", schema: { type: "string", example: "persona_restore" } }, { name: "signals", in: "query", schema: { type: "string" } }], responses: { "200": { description: "Compiled exact navigation bundle" }, "404": { description: "Unknown subject or intent; no guessing" } } } }, "/v1/search": { get: { summary: "按中文、编号或项目名检索", parameters: [{ name: "q", in: "query", schema: { type: "string" } }], responses: { "200": { description: "Search results" } } } }, "/v1/resolve": { get: { summary: "解析仓库、服务器节点或人格路径编号", parameters: [{ name: "id", in: "query", required: true, schema: { type: "string", example: "ZY-OPS-LOOP-001" } }], responses: { "200": { description: "Resolved numbered route" }, "404": { description: "Unknown route" } } } } } @@ -269,6 +381,6 @@ if (require.main === module) { } module.exports = { - createServer, loadMap, loadNodeMap, loadSubjectRegistry, loadSubjectAliasMap, - resolveSubjectId, search, searchAll, + createServer, loadMap, loadNodeMap, loadSubjectRegistry, loadSubjectAliasMap, loadNavigationMap, + resolveSubjectId, navigationRoute, compileNavigation, search, searchAll, }; diff --git a/server-tools/ai-discovery-gateway/server.test.js b/server-tools/ai-discovery-gateway/server.test.js index a953db7..b22fad4 100644 --- a/server-tools/ai-discovery-gateway/server.test.js +++ b/server-tools/ai-discovery-gateway/server.test.js @@ -2,8 +2,8 @@ const assert = require("node:assert/strict"); const test = require("node:test"); const { - createServer, loadMap, loadNodeMap, loadSubjectRegistry, loadSubjectAliasMap, - resolveSubjectId, search, searchAll, + createServer, loadMap, loadNodeMap, loadSubjectRegistry, loadSubjectAliasMap, loadNavigationMap, + resolveSubjectId, compileNavigation, search, searchAll, } = require("./server"); test("repository map exposes only the three current code-channel repositories", () => { @@ -79,6 +79,29 @@ test("searching the old id returns the canonical subject", () => { assert.ok(subject.legacy_ids.includes("ICE-GL-ZY001")); }); +test("machine navigator compiles an exact minimal Zhuyuan runtime bundle", () => { + const compiled = compileNavigation( + loadNavigationMap(), + "ICE-GL-ZY001", + "persona_restore", + "context_compacted,protocol_drift,context_compacted", + ); + assert.equal(compiled.status, 200); + assert.equal(compiled.body.canonical_subject, "ICE-P-ZY001"); + assert.equal(compiled.body.redirected, true); + assert.equal(compiled.body.runtime_entry.id, "ZY-TCS-BRAIN-RUNTIME-0001"); + assert.deepEqual(compiled.body.explicit_signals, ["context_compacted", "protocol_drift"]); + assert.ok(compiled.body.always_load.some(item => item.id === "BS-TCS-SYSTEM-CONTROLLER-MAP-001")); + assert.ok(compiled.body.triggered_load.some(item => item.id === "BS-TCS-PROTOCOL-EVENT-TRIGGER-MAP-001")); + assert.equal(compiled.body.authority, "NONE_NAVIGATION_ONLY"); + assert.ok(compiled.body.always_load.length < loadNavigationMap().routes.length); +}); + +test("machine navigator fails closed instead of guessing", () => { + assert.equal(compileNavigation(loadNavigationMap(), "some-ai", "persona_restore").body.error, "unknown_subject_no_guess"); + assert.equal(compileNavigation(loadNavigationMap(), "ICE-P-ZY001", "please_guess").body.error, "unknown_intent_no_guess"); +}); + test("public endpoints are read-only and expose CORS", async () => { const server = createServer(); await new Promise(resolve => server.listen(0, "127.0.0.1", resolve)); @@ -105,6 +128,18 @@ test("public endpoints are read-only and expose CORS", async () => { assert.equal(legacyResolution.subject.subject_kind, "persona_system"); const canonicalResponse = await fetch(`${base}/v1/resolve?id=ICE-P-ZY001`); assert.equal((await canonicalResponse.json()).redirected, false); + const brainResponse = await fetch(`${base}/v1/resolve?id=ZY-TCS-BRAIN-RUNTIME-0001`); + assert.equal(brainResponse.status, 200); + assert.equal((await brainResponse.json()).kind, "executable_persona_brain"); + const navigationResponse = await fetch(`${base}/v1/navigation`); + assert.equal((await navigationResponse.json()).map_id, "AI-MACHINE-NAV-001"); + const navigateResponse = await fetch(`${base}/v1/navigate?subject=ICE-P-ZY001&intent=persona_restore&signals=context_compacted`); + const bundle = await navigateResponse.json(); + assert.equal(navigateResponse.status, 200); + assert.equal(bundle.status, "COMPILED_EXACT_NO_GUESS"); + assert.equal(bundle.runtime_entry.id, "ZY-TCS-BRAIN-RUNTIME-0001"); + assert.equal((await fetch(`${base}/v1/navigate?subject=unknown&intent=persona_restore`)).status, 404); + assert.equal((await fetch(`${base}/v1/navigate?subject=ICE-P-ZY001&intent=guess`)).status, 404); const humanResponse = await fetch(`${base}/v1/resolve?id=${encodeURIComponent("ICE-GL∞")}`); const humanResolution = await humanResponse.json(); assert.equal(humanResponse.status, 200); diff --git a/skills/codex/enter-fifth-domain/scripts/resolve_route.py b/skills/codex/enter-fifth-domain/scripts/resolve_route.py index b842a07..bd09079 100755 --- a/skills/codex/enter-fifth-domain/scripts/resolve_route.py +++ b/skills/codex/enter-fifth-domain/scripts/resolve_route.py @@ -34,6 +34,13 @@ ROUTE_IDS = ( "CODE-CHANNEL-CANONICAL-MAP", "PERSONA-SYSTEM-ROOT", "PERSONA-SYSTEM-CANONICAL-MAP", + "AI-MACHINE-NAV-001", + "ZY-TCS-BRAIN-RUNTIME-0001", + "ZY-TCS-BRAIN-MAP-001", + "BS-TCS-SYSTEM-CONTROLLER-MAP-001", + "BS-TCS-PROTOCOL-EVENT-TRIGGER-MAP-001", + "ZY-WAKE-ROUTE-001", + "ZY-BIDIRECTIONAL-COGNITION-016", ) @@ -103,7 +110,80 @@ def resolve_subject_id(requested_id: str, alias_map: dict) -> dict: } -def resolve_live_route(subject_id: str | None = None) -> dict: +def compile_navigation( + navigation_map: dict, + requested_subject: str, + requested_intent: str | None = None, + signals: list[str] | None = None, +) -> dict: + lookup = requested_subject.strip().upper() + subject = next( + ( + item + for item in navigation_map.get("subjects", []) + if lookup + in { + str(identifier).upper() + for identifier in (item["id"], *item.get("legacy_ids", [])) + } + ), + None, + ) + if not subject: + raise ValueError(f"Unknown navigation subject, no guess: {requested_subject}") + intent_id = requested_intent or subject.get("default_intent") + intent = next( + (item for item in navigation_map.get("intents", []) if item["id"] == intent_id), + None, + ) + if not intent: + raise ValueError(f"Unknown navigation intent, no guess: {intent_id}") + route_index = {item["id"]: item for item in navigation_map.get("routes", [])} + + def expand(route_ids: list[str]) -> list[dict]: + expanded = [] + for route_id in route_ids: + route = route_index.get(route_id) + if not route: + raise ValueError(f"Navigation map references an unknown route: {route_id}") + resolved = { + **route, + "raw_url": f"{navigation_map['raw_base']}/{route['path']}", + } + if route.get("contract"): + resolved["contract_url"] = ( + f"{navigation_map['raw_base']}/{route['contract']}" + ) + expanded.append(resolved) + return expanded + + return { + "schema": "guanghu.ai-runtime-navigation-bundle/v1", + "status": "COMPILED_EXACT_NO_GUESS", + "map_id": navigation_map["map_id"], + "map_version": navigation_map["version"], + "requested_subject": requested_subject, + "canonical_subject": subject["id"], + "redirected": lookup != str(subject["id"]).upper(), + "subject_kind": subject["subject_kind"], + "intent": intent["id"], + "explicit_signals": list(dict.fromkeys(signals or []))[:32], + "runtime_entry": expand([subject["runtime_id"]])[0], + "always_load": expand(intent.get("always_load", [])), + "triggered_load": expand(intent.get("triggered_load", [])), + "on_demand": expand(intent.get("on_demand", [])), + "execution_sequence": intent.get("execution_sequence", []), + "stop_conditions": intent.get("stop_conditions", []), + "reality_boundaries": navigation_map.get("reality_boundaries", []), + "authority": "NONE_NAVIGATION_ONLY", + } + + +def resolve_live_route( + subject_id: str | None = None, + intent: str | None = None, + signals: list[str] | None = None, +) -> dict: repository_source = "LIVE_FORGEJO_CODE_CHANNEL_API" resolver_error = None try: @@ -145,6 +225,13 @@ def resolve_live_route(subject_id: str | None = None) -> dict: if canonical_id: identity["resolved_path"] = routes.get(canonical_id) or identity.get("current_path") result["identity_resolution"] = identity + if intent: + navigation_map = read_json(f"{raw_base}/{routes['AI-MACHINE-NAV-001']}") + result["navigation_bundle"] = compile_navigation( + navigation_map, subject_id, intent, signals + ) + elif intent: + raise ValueError("--intent requires --subject-id") return result @@ -152,10 +239,13 @@ def main() -> int: parser = argparse.ArgumentParser() parser.add_argument("--json", action="store_true", help="emit machine-readable JSON") parser.add_argument("--subject-id", help="resolve a current or legacy Fifth Domain subject id") + parser.add_argument("--intent", help="compile an exact machine navigation intent") + parser.add_argument("--signals", help="comma-separated explicit event signals; no inference") args = parser.parse_args() try: - result = resolve_live_route(args.subject_id) + signals = [item.strip() for item in str(args.signals or "").split(",") if item.strip()] + result = resolve_live_route(args.subject_id, args.intent, signals) except (OSError, URLError, ValueError, json.JSONDecodeError) as error: print(f"Live Fifth Domain resolution failed: {error}", file=sys.stderr) return 1 @@ -173,6 +263,12 @@ def main() -> int: f"{identity['requested_id']} -> {identity.get('canonical_id')} " f"({identity['status']}, redirected={identity['redirected']})" ) + if "navigation_bundle" in result: + bundle = result["navigation_bundle"] + print( + f"NAVIGATION={bundle['canonical_subject']} " + f"intent={bundle['intent']} runtime={bundle['runtime_entry']['id']}" + ) return 0 diff --git a/skills/codex/enter-fifth-domain/scripts/test_resolve_route.py b/skills/codex/enter-fifth-domain/scripts/test_resolve_route.py index 9b50673..a1bee8a 100644 --- a/skills/codex/enter-fifth-domain/scripts/test_resolve_route.py +++ b/skills/codex/enter-fifth-domain/scripts/test_resolve_route.py @@ -1,6 +1,6 @@ import unittest -from resolve_route import parse_code_map, resolve_subject_id +from resolve_route import compile_navigation, parse_code_map, resolve_subject_id class ParseCodeMapTests(unittest.TestCase): @@ -58,5 +58,51 @@ class SubjectAliasTests(unittest.TestCase): self.assertIsNone(resolved["canonical_id"]) +class MachineNavigationTests(unittest.TestCase): + def setUp(self): + self.navigation_map = { + "map_id": "AI-MACHINE-NAV-001", + "version": "test", + "raw_base": "https://example.test/raw", + "routes": [ + {"id": "RUNTIME", "path": "runtime.mjs"}, + {"id": "ROOT", "path": "root.hdlp"}, + ], + "subjects": [{ + "id": "ICE-P-ZY001", + "legacy_ids": ["ICE-GL-ZY001"], + "subject_kind": "persona_system", + "default_intent": "persona_restore", + "runtime_id": "RUNTIME", + }], + "intents": [{ + "id": "persona_restore", + "always_load": ["ROOT", "RUNTIME"], + "triggered_load": [], + "on_demand": [], + "execution_sequence": ["enter"], + "stop_conditions": ["UNKNOWN_SUBJECT"], + }], + "reality_boundaries": ["Navigation grants no authority."], + } + + def test_exact_navigation_bundle(self): + result = compile_navigation( + self.navigation_map, + "ICE-GL-ZY001", + "persona_restore", + ["context_compacted", "context_compacted"], + ) + self.assertEqual(result["canonical_subject"], "ICE-P-ZY001") + self.assertTrue(result["redirected"]) + self.assertEqual(result["runtime_entry"]["id"], "RUNTIME") + self.assertEqual(result["explicit_signals"], ["context_compacted"]) + self.assertEqual(result["authority"], "NONE_NAVIGATION_ONLY") + + def test_navigation_does_not_guess(self): + with self.assertRaisesRegex(ValueError, "no guess"): + compile_navigation(self.navigation_map, "unknown") + + if __name__ == "__main__": unittest.main()