From 683e135f5e10ef5ebfb83e41282626b4fbf8135e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B0=E6=9C=94?= <565183519@qq.com> Date: Mon, 10 Aug 2026 10:25:25 +0800 Subject: [PATCH] feat(domain): project verified runtime policy to desktop --- .../server/domain-access-orchestrator.test.ts | 5 +++ .../server/domain-access-orchestrator.ts | 2 ++ .../server/domain-access.test.ts | 23 ++++++++++++ .../server/domain-access.ts | 23 ++++++++++++ .../guanghu-knowledge-base/src/App.tsx | 19 ++-------- .../src/components/DomainConnectionSheet.tsx | 10 +++++- .../src/domain-connection.test.ts | 33 +++++++++++++++-- .../src/domain-connection.ts | 29 +++++++++++++++ .../src/domain-entry-state.test.ts | 36 ++++++++++++++++++- .../src/domain-entry-state.ts | 16 ++++++--- .../guanghu-knowledge-base/src/styles/app.css | 21 +++++++++++ ...IFIED-DOMAIN-POLICY-PROJECTION-20260810.md | 32 +++++++++++++++++ 12 files changed, 224 insertions(+), 25 deletions(-) create mode 100644 product-source/hololake-platform/architecture/HOLOLAKE-DESKTOP-VERIFIED-DOMAIN-POLICY-PROJECTION-20260810.md diff --git a/product-source/guanghu-knowledge-base/server/domain-access-orchestrator.test.ts b/product-source/guanghu-knowledge-base/server/domain-access-orchestrator.test.ts index 7e145c6..6220ba6 100644 --- a/product-source/guanghu-knowledge-base/server/domain-access-orchestrator.test.ts +++ b/product-source/guanghu-knowledge-base/server/domain-access-orchestrator.test.ts @@ -294,6 +294,11 @@ test('current registries, signed node claim and verified handoff project runtime assert.equal(status.stage, 'runtime-ready'); assert.equal(status.runtimeReady, true); assert.deepEqual(status.blockers, []); + assert.equal(status.runtimePolicy?.themeOwner, 'fifth-domain'); + assert.equal(status.runtimePolicy?.themePackageRef, 'theme://origin-domain/lake-reflects-stars'); + assert.equal(status.runtimePolicy?.routeRef, 'domain-route://origin-domain/runtime'); + assert.deepEqual(status.runtimePolicy?.allowedSessionScopes, ['domain:enter', 'knowledge:read']); + assert.doesNotMatch(JSON.stringify(status.runtimePolicy), /signature|signer|repository|publicKey/i); }); test('source failures are reduced to safe status without raw details', async () => { diff --git a/product-source/guanghu-knowledge-base/server/domain-access-orchestrator.ts b/product-source/guanghu-knowledge-base/server/domain-access-orchestrator.ts index 53e21e8..9d8f5cf 100644 --- a/product-source/guanghu-knowledge-base/server/domain-access-orchestrator.ts +++ b/product-source/guanghu-knowledge-base/server/domain-access-orchestrator.ts @@ -4,6 +4,7 @@ import { type DomainAccessEvidence, type DomainNodeType, type DomainAccessStatus, + type DomainRuntimePolicyProjection, } from './domain-access.js'; import { TrustedSignerSnapshotLoader, @@ -57,6 +58,7 @@ export interface DomainAccessProjection { nodeId: string; nodeType: DomainNodeType; nodeRegistrationSource: Readonly; + runtimePolicy?: DomainRuntimePolicyProjection; runtimeReady: boolean; stage: DomainAccessStatus['stage']; trustSource: Readonly; diff --git a/product-source/guanghu-knowledge-base/server/domain-access.test.ts b/product-source/guanghu-knowledge-base/server/domain-access.test.ts index 93c288a..14b3a0c 100644 --- a/product-source/guanghu-knowledge-base/server/domain-access.test.ts +++ b/product-source/guanghu-knowledge-base/server/domain-access.test.ts @@ -208,6 +208,27 @@ test('runtime access requires matching manifest, scoped capability and online re assert.equal(status.runtimeReady, true); assert.equal(status.stage, 'runtime-ready'); assert.deepEqual(status.blockers, []); + assert.deepEqual(status.runtimePolicy, { + allowedSessionScopes: ['domain:enter', 'knowledge:read'], + forbiddenDataScopes: ['private:relationship-core'], + manifestDigest: DIGEST, + permissionPolicyRef: 'policy://origin-domain/default', + routeRef: 'domain-route://origin-domain/runtime', + themeOwner: 'fifth-domain', + themePackageRef: 'theme://origin-domain/lake-reflects-stars', + }); + assert.equal(Object.isFrozen(status.runtimePolicy), true); + assert.equal(Object.isFrozen(status.runtimePolicy?.allowedSessionScopes), true); + assert.deepEqual(Object.keys(status.runtimePolicy ?? {}).sort(), [ + 'allowedSessionScopes', + 'forbiddenDataScopes', + 'manifestDigest', + 'permissionPolicyRef', + 'routeRef', + 'themeOwner', + 'themePackageRef', + ]); + assert.doesNotMatch(JSON.stringify(status.runtimePolicy), /signature|signer|repository|sourceCommit|publicKey/i); }); test('the runtime handoff entry resolves its signer only from a loaded snapshot', async () => { @@ -302,6 +323,7 @@ test('mismatched or expired evidence fails closed', () => { sessionCapability: { capabilityId: 'CAP-001', domainId: 'DOM-FIFTH-0001', expiresAt: NOW, nodeId: 'LOCAL-001', nodeType: NODE_TYPE, scopes: ['domain:enter'] }, }, NOW); assert.equal(status.runtimeReady, false); + assert.equal(status.runtimePolicy, undefined); assert.ok(status.blockers.includes('scoped_session_capability_missing')); assert.ok(status.blockers.includes('matching_connection_receipt_missing')); }); @@ -446,5 +468,6 @@ test('copying verified-looking fields cannot bypass the in-process verifier boun sessionCapability: verifiedHandoff.sessionCapability, }, NOW); assert.equal(status.runtimeReady, false); + assert.equal(status.runtimePolicy, undefined); assert.ok(status.blockers.includes('verified_domain_manifest_missing')); }); diff --git a/product-source/guanghu-knowledge-base/server/domain-access.ts b/product-source/guanghu-knowledge-base/server/domain-access.ts index 5974f7b..e5744a8 100644 --- a/product-source/guanghu-knowledge-base/server/domain-access.ts +++ b/product-source/guanghu-knowledge-base/server/domain-access.ts @@ -99,12 +99,23 @@ export interface DomainAccessEvidence { sessionCapability?: DomainSessionCapability; } +export interface DomainRuntimePolicyProjection { + allowedSessionScopes: readonly string[]; + forbiddenDataScopes: readonly string[]; + manifestDigest: string; + permissionPolicyRef: string; + routeRef: string; + themeOwner: DomainThemeOwner; + themePackageRef: string; +} + export interface DomainAccessStatus { blockers: string[]; domainId: string; localWorkspaceAllowed: true; nodeId: string; nodeType: DomainNodeType; + runtimePolicy?: DomainRuntimePolicyProjection; runtimeReady: boolean; stage: 'login-required' | 'identity-verified' | 'runtime-ready'; } @@ -347,12 +358,24 @@ export function evaluateDomainAccess(evidence: DomainAccessEvidence, now = Date. blockers.push('matching_connection_receipt_missing'); } const runtimeReady = blockers.length === 0; + const runtimePolicy = runtimeReady && manifest + ? Object.freeze({ + allowedSessionScopes: Object.freeze([...manifest.runtimePolicy.allowedSessionScopes]), + forbiddenDataScopes: Object.freeze([...manifest.runtimePolicy.forbiddenDataScopes]), + manifestDigest: manifest.digest, + permissionPolicyRef: manifest.runtimePolicy.permissionPolicyRef, + routeRef: manifest.runtimePolicy.routeRef, + themeOwner: manifest.runtimePolicy.themeOwner, + themePackageRef: manifest.runtimePolicy.themePackageRef, + }) + : undefined; return { blockers, domainId: evidence.domainId, localWorkspaceAllowed: true, nodeId: evidence.nodeId, nodeType: evidence.nodeType, + ...(runtimePolicy ? { runtimePolicy } : {}), runtimeReady, stage: runtimeReady ? 'runtime-ready' diff --git a/product-source/guanghu-knowledge-base/src/App.tsx b/product-source/guanghu-knowledge-base/src/App.tsx index 98d0718..b6931ed 100644 --- a/product-source/guanghu-knowledge-base/src/App.tsx +++ b/product-source/guanghu-knowledge-base/src/App.tsx @@ -13,6 +13,7 @@ import { ModuleLibrarySheet } from './components/ModuleLibrarySheet'; import { cleanDisplayText } from './presentation'; import { WorldEntry } from './components/WorldEntry'; import { DomainConnectionSheet } from './components/DomainConnectionSheet'; +import type { DomainAccessProjection } from './domain-connection'; import { createDomainEntryTarget, type DomainEntryTarget, type DomainNodeType } from './domain-entry-state'; import type { DomainRouteId } from './public-domain-directory'; @@ -43,22 +44,6 @@ interface ServerProfile { channelSubtitle?: string; } -interface DomainAccessStatus { - blockers: string[]; - domainId?: string; - nodeId?: string; - nodeType?: DomainNodeType; - runtimeReady: boolean; - stage: 'checking' | 'login-required' | 'identity-verified' | 'runtime-ready'; - trustSource?: { - reason?: 'ANCHOR_INVALID' | 'REGISTRY_INVALID' | 'SOURCE_UNAVAILABLE'; - registryVersion: string | null; - signerCount: number; - sourceCommit: string | null; - status: 'CURRENT' | 'DEGRADED_LAST_KNOWN_GOOD' | 'UNAVAILABLE'; - }; -} - function findFirstDocument(nodes: DocTreeNode[]): string | null { for (const node of nodes) { if (node.type === 'document') return node.path; @@ -103,7 +88,7 @@ export default function App() { const [moduleMessage, setModuleMessage] = useState(''); const [lastChannelReceipt, setLastChannelReceipt] = useState(''); const [worldEntered, setWorldEntered] = useState(false); - const [domainAccess, setDomainAccess] = useState({ blockers: [], runtimeReady: false, stage: 'checking' }); + const [domainAccess, setDomainAccess] = useState({ blockers: [], runtimeReady: false, stage: 'checking' }); const domainAccessRequest = useRef(0); const storageMode = repositoryStatus?.remote ? 'server' : 'local'; diff --git a/product-source/guanghu-knowledge-base/src/components/DomainConnectionSheet.tsx b/product-source/guanghu-knowledge-base/src/components/DomainConnectionSheet.tsx index e3f7041..b152e62 100644 --- a/product-source/guanghu-knowledge-base/src/components/DomainConnectionSheet.tsx +++ b/product-source/guanghu-knowledge-base/src/components/DomainConnectionSheet.tsx @@ -1,5 +1,5 @@ import { Cloud, Laptop, ShieldCheck, X } from 'lucide-react'; -import { projectDomainConnectionSteps, projectDomainTrustSource, type DomainAccessProjection } from '../domain-connection'; +import { projectDomainConnectionSteps, projectDomainRuntimePolicyReceipt, projectDomainTrustSource, type DomainAccessProjection } from '../domain-connection'; import { canEnterSelectedDomainRuntime, projectDomainRuntimeBoundary, type DomainEntryTarget, type DomainNodeType } from '../domain-entry-state'; import { publicDomainDirectory, type DomainRouteId } from '../public-domain-directory'; @@ -17,6 +17,7 @@ interface Props { export function DomainConnectionSheet({ access, target, open, onClose, onSelectTarget, onSelectNodeType, onEnterRuntime, onOpenCodeChannel }: Props) { if (!open) return null; const steps = projectDomainConnectionSteps(access); + const policyReceipt = projectDomainRuntimePolicyReceipt(access); const canEnter = canEnterSelectedDomainRuntime(target, access); return ( @@ -54,6 +55,13 @@ export function DomainConnectionSheet({ access, target, open, onClose, onSelectT ))} + {policyReceipt.length > 0 &&
+

可信域运行策略

+
+ {policyReceipt.map(row =>
{row.label}
{row.value}
)} +
+
} +

{projectDomainRuntimeBoundary(target, access)} 代码频道账号只用于仓库与同步,不能单独签发域权限。

} diff --git a/product-source/guanghu-knowledge-base/src/domain-connection.test.ts b/product-source/guanghu-knowledge-base/src/domain-connection.test.ts index e123ec1..c9fc96e 100644 --- a/product-source/guanghu-knowledge-base/src/domain-connection.test.ts +++ b/product-source/guanghu-knowledge-base/src/domain-connection.test.ts @@ -1,6 +1,16 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { projectDomainConnectionSteps, projectDomainTrustSource } from './domain-connection.js'; +import { projectDomainConnectionSteps, projectDomainRuntimePolicyReceipt, projectDomainTrustSource } from './domain-connection.js'; + +const verifiedRuntimePolicy = { + allowedSessionScopes: ['domain:enter', 'knowledge:read'], + forbiddenDataScopes: ['private:relationship-core'], + manifestDigest: 'a'.repeat(64), + permissionPolicyRef: 'policy://origin-domain/default', + routeRef: 'domain-route://origin-domain/runtime', + themeOwner: 'fifth-domain' as const, + themePackageRef: 'theme://origin-domain/lake-reflects-stars', +}; test('code-channel account absence cannot be projected as a domain runtime login', () => { const steps = projectDomainConnectionSteps({ @@ -32,10 +42,29 @@ test('verified account and node remain identity-only without domain handoff evid }); test('runtime-ready requires all four verified steps', () => { - const steps = projectDomainConnectionSteps({ blockers: [], runtimeReady: true, stage: 'runtime-ready' }); + const steps = projectDomainConnectionSteps({ blockers: [], runtimePolicy: verifiedRuntimePolicy, runtimeReady: true, stage: 'runtime-ready' }); assert.ok(steps.every(step => step.state === 'verified')); }); +test('a runtime-ready access projects only a compact verified policy receipt', () => { + const rows = projectDomainRuntimePolicyReceipt({ + blockers: [], + runtimePolicy: verifiedRuntimePolicy, + runtimeReady: true, + stage: 'runtime-ready', + }); + assert.deepEqual(rows.map(row => row.label), ['主题包', '运行路线', '权限策略', '允许会话', '禁止数据', '清单摘要']); + assert.match(rows[0].value, /^theme:\/\/origin-domain\//); + assert.match(rows.at(-1)?.value ?? '', /^a{12}…a{8}$/); + assert.doesNotMatch(JSON.stringify(rows), /signature|signer|repository|publicKey/i); + assert.deepEqual(projectDomainRuntimePolicyReceipt({ + blockers: ['matching_connection_receipt_missing'], + runtimePolicy: verifiedRuntimePolicy, + runtimeReady: false, + stage: 'identity-verified', + }), []); +}); + test('a current empty signer registry is projected as a real manifest blocker', () => { const access = { blockers: ['verified_domain_manifest_missing'], diff --git a/product-source/guanghu-knowledge-base/src/domain-connection.ts b/product-source/guanghu-knowledge-base/src/domain-connection.ts index 780a44b..1a5b951 100644 --- a/product-source/guanghu-knowledge-base/src/domain-connection.ts +++ b/product-source/guanghu-knowledge-base/src/domain-connection.ts @@ -1,10 +1,21 @@ export type DomainAccessStage = 'checking' | 'login-required' | 'identity-verified' | 'runtime-ready'; +export interface VerifiedDomainRuntimePolicyProjection { + allowedSessionScopes: readonly string[]; + forbiddenDataScopes: readonly string[]; + manifestDigest: string; + permissionPolicyRef: string; + routeRef: string; + themeOwner: 'domain-team' | 'fifth-domain'; + themePackageRef: string; +} + export interface DomainAccessProjection { blockers: string[]; domainId?: string; nodeId?: string; nodeType?: 'local-terminal' | 'cloud-resident'; + runtimePolicy?: VerifiedDomainRuntimePolicyProjection; runtimeReady: boolean; stage: DomainAccessStage; trustSource?: { @@ -23,6 +34,11 @@ export interface DomainConnectionStep { detail: string; } +export interface DomainRuntimePolicyReceiptRow { + label: string; + value: string; +} + const blockerToStep: Record = { account_identity_missing: 'identity', verified_node_registration_missing: 'identity', @@ -90,3 +106,16 @@ export function projectDomainTrustSource(access: DomainAccessProjection): string const health = source.status === 'CURRENT' ? '当前' : '上次可信快照'; return `可信清单 ${health} · v${version} · ${commit} · 已登记签名人 ${source.signerCount}`; } + +export function projectDomainRuntimePolicyReceipt(access: DomainAccessProjection): DomainRuntimePolicyReceiptRow[] { + const policy = access.runtimeReady ? access.runtimePolicy : undefined; + if (!policy) return []; + return [ + { label: '主题包', value: policy.themePackageRef }, + { label: '运行路线', value: policy.routeRef }, + { label: '权限策略', value: policy.permissionPolicyRef }, + { label: '允许会话', value: policy.allowedSessionScopes.join(' · ') }, + { label: '禁止数据', value: policy.forbiddenDataScopes.join(' · ') }, + { label: '清单摘要', value: `${policy.manifestDigest.slice(0, 12)}…${policy.manifestDigest.slice(-8)}` }, + ]; +} diff --git a/product-source/guanghu-knowledge-base/src/domain-entry-state.test.ts b/product-source/guanghu-knowledge-base/src/domain-entry-state.test.ts index 6138c39..29ca4e9 100644 --- a/product-source/guanghu-knowledge-base/src/domain-entry-state.test.ts +++ b/product-source/guanghu-knowledge-base/src/domain-entry-state.test.ts @@ -2,7 +2,24 @@ import assert from 'node:assert/strict'; import test from 'node:test'; import { canEnterSelectedDomainRuntime, createDomainEntryTarget, projectDomainRuntimeBoundary } from './domain-entry-state.js'; -const ready = (domainId: string, nodeType: 'local-terminal' | 'cloud-resident' = 'local-terminal') => ({ blockers: [], domainId, nodeType, runtimeReady: true, stage: 'runtime-ready' as const }); +const validRuntimePolicy = { + allowedSessionScopes: ['domain:enter', 'knowledge:read'], + forbiddenDataScopes: ['private:relationship-core'], + manifestDigest: 'a'.repeat(64), + permissionPolicyRef: 'policy://origin-domain/default', + routeRef: 'domain-route://origin-domain/runtime', + themeOwner: 'fifth-domain' as const, + themePackageRef: 'theme://origin-domain/lake-reflects-stars', +}; + +const ready = (domainId: string, nodeType: 'local-terminal' | 'cloud-resident' = 'local-terminal') => ({ + blockers: [], + domainId, + nodeType, + runtimePolicy: validRuntimePolicy, + runtimeReady: true, + stage: 'runtime-ready' as const, +}); test('a generic login request does not silently target the Fifth Domain', () => { assert.equal(canEnterSelectedDomainRuntime(null, ready('DOM-FIFTH-0001')), false); @@ -30,3 +47,20 @@ test('the Fifth Domain opens only with matching runtime-ready evidence', () => { assert.match(projectDomainRuntimeBoundary(fifth, ready('DOM-FIFTH-0001', 'local-terminal')), /另一种节点类型/); assert.match(projectDomainRuntimeBoundary(fifth, ready('DOM-FIFTH-0001', 'cloud-resident')), /已经匹配/); }); + +test('the Fifth Domain stays closed without the exact verified runtime policy projection', () => { + const fifth = createDomainEntryTarget('fifth'); + const base = ready('DOM-FIFTH-0001'); + assert.equal(canEnterSelectedDomainRuntime(fifth, { ...base, runtimePolicy: undefined }), false); + assert.match(projectDomainRuntimeBoundary(fifth, { ...base, runtimePolicy: undefined }), /可信运行策略缺失或不匹配/); + + for (const runtimePolicy of [ + { ...validRuntimePolicy, manifestDigest: 'not-a-digest' }, + { ...validRuntimePolicy, themeOwner: 'domain-team' as const }, + { ...validRuntimePolicy, themePackageRef: 'theme://enterprise/fifth-look' }, + { ...validRuntimePolicy, routeRef: 'domain-route://enterprise/fifth' }, + { ...validRuntimePolicy, allowedSessionScopes: ['knowledge:read'] }, + ]) { + assert.equal(canEnterSelectedDomainRuntime(fifth, { ...base, runtimePolicy }), false); + } +}); diff --git a/product-source/guanghu-knowledge-base/src/domain-entry-state.ts b/product-source/guanghu-knowledge-base/src/domain-entry-state.ts index bfddb1a..1e77fff 100644 --- a/product-source/guanghu-knowledge-base/src/domain-entry-state.ts +++ b/product-source/guanghu-knowledge-base/src/domain-entry-state.ts @@ -20,7 +20,14 @@ export function canEnterSelectedDomainRuntime(target: DomainEntryTarget | null, if (access.nodeType !== target.nodeType) return false; // The present desktop bundle contains only the Fifth Domain renderer. The four // enterprise domains must provide their own signed runtime package and endpoint. - return target.domain.routeId === 'fifth'; + if (target.domain.routeId !== 'fifth') return false; + const policy = access.runtimePolicy; + return Boolean(policy + && /^[a-f0-9]{64}$/.test(policy.manifestDigest) + && policy.themeOwner === 'fifth-domain' + && policy.themePackageRef.startsWith('theme://origin-domain/') + && policy.routeRef.startsWith('domain-route://origin-domain/') + && policy.allowedSessionScopes.includes('domain:enter')); } export function projectDomainRuntimeBoundary(target: DomainEntryTarget | null, access: DomainAccessProjection): string { @@ -34,7 +41,8 @@ export function projectDomainRuntimeBoundary(target: DomainEntryTarget | null, a if (target.domain.routeId !== 'fifth') { return `${target.domain.displayName}的独立运行端点与主题包尚未登记;当前只能查看公开门厅。`; } - return access.runtimeReady - ? '第五域运行端点、签名清单、会话能力与在线回执已经匹配。' - : '第五域入口保持关闭,直到四项真实接入证据全部匹配。'; + if (!access.runtimeReady) return '第五域入口保持关闭,直到四项真实接入证据全部匹配。'; + return canEnterSelectedDomainRuntime(target, access) + ? '第五域运行端点、签名清单、主题策略、会话能力与在线回执已经匹配。' + : '域接入证据声称已就绪,但可信运行策略缺失或不匹配;第五域入口保持关闭。'; } diff --git a/product-source/guanghu-knowledge-base/src/styles/app.css b/product-source/guanghu-knowledge-base/src/styles/app.css index 441aa29..4d50c6a 100644 --- a/product-source/guanghu-knowledge-base/src/styles/app.css +++ b/product-source/guanghu-knowledge-base/src/styles/app.css @@ -3240,6 +3240,27 @@ select:focus-visible { .domain-connection-steps em { color: #d9ad5f; font-size: 9px; font-style: normal; } .domain-connection-steps li[data-state="verified"] em { color: var(--lake-success); } +.domain-policy-receipt { + margin: 12px 20px 0; + padding: 13px 14px; + border: 1px solid rgba(81, 200, 120, .2); + border-radius: 10px; + background: rgba(8, 26, 29, .58); +} + +.domain-policy-receipt h3 { + margin: 0 0 9px; + color: var(--lake-success); + font-size: 10px; + font-weight: 600; + letter-spacing: .08em; +} + +.domain-policy-receipt dl { display: grid; gap: 6px; margin: 0; } +.domain-policy-receipt dl > div { display: grid; grid-template-columns: 72px minmax(0, 1fr); gap: 10px; } +.domain-policy-receipt dt { color: var(--lake-muted); font-size: 9px; } +.domain-policy-receipt dd { margin: 0; overflow-wrap: anywhere; color: var(--lake-text-soft); font-size: 9px; line-height: 1.45; } + .domain-connection-boundary { margin-bottom: 18px; padding: 10px 12px; diff --git a/product-source/hololake-platform/architecture/HOLOLAKE-DESKTOP-VERIFIED-DOMAIN-POLICY-PROJECTION-20260810.md b/product-source/hololake-platform/architecture/HOLOLAKE-DESKTOP-VERIFIED-DOMAIN-POLICY-PROJECTION-20260810.md new file mode 100644 index 0000000..034e9ca --- /dev/null +++ b/product-source/hololake-platform/architecture/HOLOLAKE-DESKTOP-VERIFIED-DOMAIN-POLICY-PROJECTION-20260810.md @@ -0,0 +1,32 @@ +# HoloLake 桌面端可信域策略投影验收 + +日期:2026-08-10 +阶段:DEV-20260809-007 / Stage 008 +状态:实现前验收基线 + +## 目标 + +把服务端已经完成密码学核验的域运行策略,以只读、最小化的方式投影到真实 HoloLake 桌面入口。桌面端在载入第五域运行体前,除了核对域编号和节点类型,还必须核对签名清单绑定的运行路线、主题归属、主题包和会话权限。 + +这不是新增一套前端 manifest,也不是让 UI 自己判断签名;唯一权威仍是桌面进程内已经通过可信签名人快照、Ed25519 签名、清单摘要、会话能力和在线回执共同验证的服务端结果。 + +## 验收标准 + +1. 只有本进程内完成密码学核验、且四项域接入证据全部匹配时,服务端才返回 `runtimePolicy` 投影。 +2. 投影仅包含:manifest 摘要、运行路线、主题归属、主题包、权限策略、允许的会话范围和禁止的数据范围。 +3. 投影不得包含签名、签名人公钥、仓库地址、源提交、连接凭据或任何私人数据。 +4. 非 `runtime-ready` 状态不得携带策略投影;复制一份外观相同的 manifest 也不能越过进程内验证边界。 +5. 第五域最终入口必须同时满足:稳定域编号和节点类型匹配、摘要格式有效、主题归属为 `fifth-domain`、主题包属于 `theme://origin-domain/`、运行路线属于 `domain-route://origin-domain/`,并允许 `domain:enter`。 +6. 缺少或不匹配可信策略投影时,即使上层错误声称 `runtimeReady`,第五域渲染器也保持关闭,并向用户说明是策略回读不完整或不匹配。 +7. 四个企业域继续只有公开门厅;在各自独立运行端点和主题包真正登记、打包以前,不得复用第五域渲染器。 +8. 域接入面板以紧凑、可读的可信回执展示真实策略,不制造假状态,不暴露验证内部秘密。 +9. 公共灯塔和五域公开门厅的匿名可见边界不变;本阶段不改变已选定的公共主题或第五域主题。 +10. 本阶段只证明代码、测试、构建、安装和运行中实际完成的层级;真实生产 manifest、注册端点、handoff 端点或生产会话不存在时继续明确记为 `NOT_EXISTS_0`。 + +## 失败关闭边界 + +- 签名清单未验证:不投影策略,不进入域。 +- 策略投影缺失或被篡改:不进入域。 +- 域、节点、路线、主题归属、主题命名空间或权限任一不匹配:不进入域。 +- 代码频道登录、仓库同步或本地知识工作区可用:均不得被解释为已经取得域运行权限。 +