From 46d19aeb459a9556f6478fe8353d19962833fdb0 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 08:25:34 +0800 Subject: [PATCH] Bind runtime handoff to node proof --- .../server/domain-access-orchestrator.ts | 10 +- .../domain-runtime-handoff-source.test.ts | 154 ++++++++++++++---- .../server/domain-runtime-handoff-source.ts | 78 +++++++-- .../server/node-possession-proof.test.ts | 5 +- .../server/node-possession-proof.ts | 35 +++- ...AKE-NODE-REGISTRATION-CONTRACT-20260810.md | 20 +++ .../hololake-platform/architecture/README.md | 2 +- 7 files changed, 249 insertions(+), 55 deletions(-) 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 ceeb2ae..53e21e8 100644 --- a/product-source/guanghu-knowledge-base/server/domain-access-orchestrator.ts +++ b/product-source/guanghu-knowledge-base/server/domain-access-orchestrator.ts @@ -23,6 +23,7 @@ import { createNodePossessionChallenge, verifyNodePossessionResponse, type NodePossessionProofSource, + type VerifiedNodePossession, } from './node-possession-proof.js'; const IDENTIFIER_PATTERN = /^[A-Z0-9][A-Z0-9._:-]{1,159}$/; @@ -46,7 +47,7 @@ export interface DomainRuntimeHandoffCandidate { } export interface DomainRuntimeHandoffSource { - read(domainId: string, nodeId: string, nodeType: DomainNodeType): Promise; + read(possession: VerifiedNodePossession): Promise; } export interface DomainAccessProjection { @@ -102,6 +103,7 @@ export class DomainAccessOrchestrator { ]); let nodeRegistrationVerified = false; let nodePossessionVerified = false; + let possession: VerifiedNodePossession | null = null; if (identity.accountVerified && nodeRegistrationSnapshot.receipt.status === 'CURRENT') { try { const loaded = assertLoadedNodeRegistrationSnapshot(nodeRegistrationSnapshot); @@ -126,7 +128,7 @@ export class DomainAccessOrchestrator { const response = await this.nodePossessions.prove(challenge); if (response) { if (at === undefined) now = this.clock(); - verifyNodePossessionResponse(response, challenge, registration, now); + possession = verifyNodePossessionResponse(response, challenge, registration, now); nodePossessionVerified = true; } } @@ -144,10 +146,10 @@ export class DomainAccessOrchestrator { nodeType, }; - if (identity.accountVerified && nodeRegistrationVerified && nodePossessionVerified) { + if (identity.accountVerified && nodeRegistrationVerified && nodePossessionVerified && possession) { let candidate: DomainRuntimeHandoffCandidate | null = null; try { - candidate = await this.handoffs.read(domainId, identity.nodeId, nodeType); + candidate = await this.handoffs.read(possession); } catch { candidate = null; } diff --git a/product-source/guanghu-knowledge-base/server/domain-runtime-handoff-source.test.ts b/product-source/guanghu-knowledge-base/server/domain-runtime-handoff-source.test.ts index bbf631e..ddd1503 100644 --- a/product-source/guanghu-knowledge-base/server/domain-runtime-handoff-source.test.ts +++ b/product-source/guanghu-knowledge-base/server/domain-runtime-handoff-source.test.ts @@ -1,75 +1,163 @@ import test from 'node:test'; import assert from 'node:assert/strict'; +import { createHash, generateKeyPairSync, sign } from 'node:crypto'; import { StrictDomainRuntimeHandoffSource } from './domain-runtime-handoff-source.js'; +import { + createNodePossessionChallenge, + nodePossessionChallengeSigningBytes, + verifyNodePossessionResponse, +} from './node-possession-proof.js'; +import { + nodeRegistrationClaimSigningBytes, + parseNodeRegistrationEndpointRegistry, + resolveNodeRegistrationEndpoint, + verifyNodeRegistrationClaim, +} from './node-registration.js'; +const NOW = 1_786_291_200_000; const DOMAIN_ID = 'DOM-FIFTH-0001'; const NODE_ID = 'JD-FD-PRIMARY'; const NODE_TYPE = 'cloud-resident' as const; +const registrationKeys = generateKeyPairSync('ed25519'); +const nodeKeys = generateKeyPairSync('ed25519'); +const publicKeyPem = nodeKeys.publicKey.export({ format: 'pem', type: 'spki' }).toString(); +const fingerprint = createHash('sha256') + .update(nodeKeys.publicKey.export({ format: 'der', type: 'spki' })) + .digest('hex'); -function response(overrides: Record = {}) { +function verifiedPossession() { + const registry = parseNodeRegistrationEndpointRegistry({ + endpoints: [{ + algorithm: 'Ed25519', + domainIds: [DOMAIN_ID], + endpointId: 'GH-NODE-REG-001', + nodeTypes: [NODE_TYPE], + publicKeyPem: registrationKeys.publicKey.export({ format: 'pem', type: 'spki' }).toString(), + signerId: 'GH-NODE-REG-SIGNER-001', + status: 'ACTIVE', + url: 'https://guanghulab.com/api/ai/v1/node-registrations/claims', + }], + registryId: 'GH-AIOS-NODE-REGISTRATION-ENDPOINTS-001', + schema: 'gh-aios.node-registration-endpoints/v1', + state: 'CURRENT', + version: '1.0.0', + }, { + repositoryId: 'REPO-012', + sourceCommit: 'a'.repeat(40), + sourceUrl: `https://guanghulab.com/code/bingshuo/guanghu-ice-heart/raw/commit/${'a'.repeat(40)}/routing/node-registration-endpoints.json`, + }); + const endpoint = resolveNodeRegistrationEndpoint(registry, { domainId: DOMAIN_ID, nodeType: NODE_TYPE }); + assert.ok(endpoint); + const payload = { + accountId: 'bingshuo', + claimId: 'NODE-CLAIM-001', + domainId: DOMAIN_ID, + endpointId: endpoint.endpointId, + expiresAt: NOW + 120_000, + issuedAt: NOW - 1_000, + nodeId: NODE_ID, + nodeKeyFingerprint: fingerprint, + nodeType: NODE_TYPE, + schema: 'gh-aios.node-registration-claim/v1' as const, + signerId: endpoint.signerId, + }; + const registration = verifyNodeRegistrationClaim({ + ...payload, + signature: sign(null, nodeRegistrationClaimSigningBytes(payload), registrationKeys.privateKey).toString('base64'), + }, { + accountId: payload.accountId, + domainId: DOMAIN_ID, + nodeId: NODE_ID, + nodeType: NODE_TYPE, + }, endpoint, NOW); + const challenge = createNodePossessionChallenge( + registration, + NOW, + 'NODE-CHALLENGE-001', + 'A'.repeat(43), + ); + const response = { + challengeId: challenge.challengeId, + publicKeyPem, + schema: 'gh-aios.node-possession-response/v1' as const, + signature: sign(null, nodePossessionChallengeSigningBytes(challenge), nodeKeys.privateKey).toString('base64'), + }; + return verifyNodePossessionResponse(response, challenge, registration, NOW + 1); +} + +function response(requestId: string, overrides: Record = {}) { return { schema: 'gh-aios.domain-runtime-handoff-response/v1', handoff: { manifest: { digest: 'untrusted-until-orchestrator-verifies' } }, + request_id: requestId, signer_lookup: { repository_id: 'REPO-014', signer_id: 'GH-LIGHTHOUSE-001', }, + status: 'ISSUED', ...overrides, }; } -test('adapts one exact endpoint-neutral response without interpreting signed evidence', async () => { +test('forwards one exact cryptographic authorization bundle without private material', async () => { const requests: unknown[] = []; const source = new StrictDomainRuntimeHandoffSource({ async request(input) { requests.push(input); - return response(); + return response(input.requestId); }, - }); + }, () => NOW + 2, () => 'HANDOFF-REQ-001'); - const candidate = await source.read(DOMAIN_ID, NODE_ID, NODE_TYPE); + const candidate = await source.read(verifiedPossession()); - assert.deepEqual(requests, [{ domainId: DOMAIN_ID, nodeId: NODE_ID, nodeType: NODE_TYPE }]); + assert.equal(requests.length, 1); + assert.deepEqual(Object.keys(requests[0] as object).sort(), [ + 'accountId', 'challenge', 'domainId', 'issuedAt', 'nodeId', 'nodeType', + 'registration', 'requestId', 'response', 'schema', + ]); + assert.equal(JSON.stringify(requests[0]).includes('PRIVATE KEY'), false); assert.deepEqual(candidate, { handoff: { manifest: { digest: 'untrusted-until-orchestrator-verifies' } }, signerLookup: { repositoryId: 'REPO-014', signerId: 'GH-LIGHTHOUSE-001' }, }); - assert.equal(Object.isFrozen(candidate), true); - assert.equal(Object.isFrozen(candidate?.signerLookup), true); }); -test('rejects malformed, extended and self-authorizing response envelopes', async () => { +test('binds the response to the generated request and rejects malformed envelopes', async () => { const samples = [ null, - response({ extra: true }), - response({ schema: 'other/v1' }), - response({ signer_lookup: { repository_id: 'REPO-014', signer_id: 'bad signer' } }), - response({ signer_lookup: { repository_id: 'REPO-014', signer_id: 'GH-LIGHTHOUSE-001', public_key: 'forbidden' } }), - response({ handoff: null }), + response('OTHER-REQ'), + response('HANDOFF-REQ-001', { extra: true }), + response('HANDOFF-REQ-001', { schema: 'other/v1' }), + response('HANDOFF-REQ-001', { signer_lookup: { repository_id: 'REPO-014', signer_id: 'bad signer' } }), + response('HANDOFF-REQ-001', { signer_lookup: { repository_id: 'REPO-014', signer_id: 'GH-LIGHTHOUSE-001', public_key: 'forbidden' } }), + response('HANDOFF-REQ-001', { handoff: null }), + response('HANDOFF-REQ-001', { handoff: null, signer_lookup: null, status: 'NOT_AUTHORIZED' }), ]; - let index = 0; - const source = new StrictDomainRuntimeHandoffSource({ - async request() { return samples[index++]; }, - }); - - for (const _sample of samples) { - assert.equal(await source.read(DOMAIN_ID, NODE_ID, NODE_TYPE), null); + for (const sample of samples) { + const source = new StrictDomainRuntimeHandoffSource({ async request() { return sample; } }, () => NOW + 2, () => 'HANDOFF-REQ-001'); + assert.equal(await source.read(verifiedPossession()), null); } }); -test('fails closed on invalid request identity and transport errors without leaking details', async () => { +test('rejects copied, expired and replayed possession authorizations before transport', async () => { let requests = 0; + const possession = verifiedPossession(); const source = new StrictDomainRuntimeHandoffSource({ - async request() { - requests += 1; - throw new Error('secret remote detail'); - }, - }); - - assert.equal(await source.read('bad domain', NODE_ID, NODE_TYPE), null); - assert.equal(requests, 0); - assert.equal(await source.read(DOMAIN_ID, NODE_ID, NODE_TYPE), null); - assert.equal(requests, 1); - assert.equal(await source.read(DOMAIN_ID, NODE_ID, 'invalid' as never), null); + async request(input) { requests += 1; return response(input.requestId); }, + }, () => NOW + 2, () => 'HANDOFF-REQ-001'); + assert.ok(await source.read(possession)); + assert.equal(await source.read(possession), null); + assert.equal(await source.read({ ...verifiedPossession() }), null); + const expired = new StrictDomainRuntimeHandoffSource({ + async request(input) { requests += 1; return response(input.requestId); }, + }, () => NOW + 60_000, () => 'HANDOFF-REQ-002'); + assert.equal(await expired.read(verifiedPossession()), null); assert.equal(requests, 1); }); + +test('fails closed on transport errors without exposing remote details', async () => { + const source = new StrictDomainRuntimeHandoffSource({ + async request() { throw new Error('secret remote detail'); }, + }, () => NOW + 2, () => 'HANDOFF-REQ-001'); + assert.equal(await source.read(verifiedPossession()), null); +}); diff --git a/product-source/guanghu-knowledge-base/server/domain-runtime-handoff-source.ts b/product-source/guanghu-knowledge-base/server/domain-runtime-handoff-source.ts index 30370c2..1d36698 100644 --- a/product-source/guanghu-knowledge-base/server/domain-runtime-handoff-source.ts +++ b/product-source/guanghu-knowledge-base/server/domain-runtime-handoff-source.ts @@ -2,14 +2,31 @@ import type { DomainRuntimeHandoffCandidate, DomainRuntimeHandoffSource, } from './domain-access-orchestrator.js'; -import type { DomainNodeType } from './domain-access.js'; +import { + assertVerifiedNodePossession, + type NodePossessionChallenge, + type NodePossessionResponse, + type VerifiedNodePossession, +} from './node-possession-proof.js'; +import type { VerifiedNodeRegistration } from './node-registration.js'; +import { randomUUID } from 'node:crypto'; const IDENTIFIER_PATTERN = /^[A-Z0-9][A-Z0-9._:-]{1,159}$/; +const REQUEST_SCHEMA = 'gh-aios.domain-runtime-handoff-request/v1' as const; +const RESPONSE_SCHEMA = 'gh-aios.domain-runtime-handoff-response/v1' as const; +const consumedPossessions = new WeakSet(); export interface DomainRuntimeHandoffRequest { + accountId: string; + challenge: Readonly; domainId: string; + issuedAt: number; nodeId: string; - nodeType: DomainNodeType; + nodeType: VerifiedNodeRegistration['nodeType']; + registration: Readonly; + requestId: string; + response: Readonly; + schema: typeof REQUEST_SCHEMA; } export interface DomainRuntimeHandoffTransport { @@ -26,19 +43,28 @@ function hasExactKeys(value: Record, expected: readonly string[ return actual.length === keys.length && actual.every((key, index) => key === keys[index]); } -function parseResponse(input: unknown): Readonly | null { +function parseResponse( + input: unknown, + request: DomainRuntimeHandoffRequest, +): Readonly | null { if (!isRecord(input) - || !hasExactKeys(input, ['handoff', 'schema', 'signer_lookup']) - || input.schema !== 'gh-aios.domain-runtime-handoff-response/v1' - || !isRecord(input.handoff) + || !hasExactKeys(input, ['handoff', 'request_id', 'schema', 'signer_lookup', 'status']) + || input.schema !== RESPONSE_SCHEMA + || input.request_id !== request.requestId + || (input.status !== 'ISSUED' && input.status !== 'NOT_AUTHORIZED')) { + return null; + } + if (input.status === 'NOT_AUTHORIZED') { + if (input.handoff !== null || input.signer_lookup !== null) return null; + return null; + } + if (!isRecord(input.handoff) || !isRecord(input.signer_lookup) || !hasExactKeys(input.signer_lookup, ['repository_id', 'signer_id']) || typeof input.signer_lookup.repository_id !== 'string' || !IDENTIFIER_PATTERN.test(input.signer_lookup.repository_id) || typeof input.signer_lookup.signer_id !== 'string' - || !IDENTIFIER_PATTERN.test(input.signer_lookup.signer_id)) { - return null; - } + || !IDENTIFIER_PATTERN.test(input.signer_lookup.signer_id)) return null; return Object.freeze({ handoff: input.handoff, signerLookup: Object.freeze({ @@ -49,13 +75,37 @@ function parseResponse(input: unknown): Readonly } export class StrictDomainRuntimeHandoffSource implements DomainRuntimeHandoffSource { - constructor(private readonly transport: DomainRuntimeHandoffTransport) {} + constructor( + private readonly transport: DomainRuntimeHandoffTransport, + private readonly clock: () => number = Date.now, + private readonly requestId: () => string = () => `HANDOFF-REQ-${randomUUID().toUpperCase()}`, + ) {} - async read(domainId: string, nodeId: string, nodeType: DomainNodeType): Promise | null> { - if (!IDENTIFIER_PATTERN.test(domainId) || !IDENTIFIER_PATTERN.test(nodeId)) return null; - if (nodeType !== 'local-terminal' && nodeType !== 'cloud-resident') return null; + async read(possession: VerifiedNodePossession): Promise | null> { try { - return parseResponse(await this.transport.request(Object.freeze({ domainId, nodeId, nodeType }))); + const verified = assertVerifiedNodePossession(possession); + if (consumedPossessions.has(verified)) return null; + const issuedAt = this.clock(); + const requestId = this.requestId(); + if (!Number.isSafeInteger(issuedAt) + || issuedAt < verified.verifiedAt + || issuedAt >= verified.challenge.expiresAt + || issuedAt >= verified.registration.expiresAt + || !IDENTIFIER_PATTERN.test(requestId)) return null; + const request = Object.freeze({ + accountId: verified.registration.accountId, + challenge: verified.challenge, + domainId: verified.registration.domainId, + issuedAt, + nodeId: verified.registration.nodeId, + nodeType: verified.registration.nodeType, + registration: verified.registration, + requestId, + response: verified.response, + schema: REQUEST_SCHEMA, + }); + consumedPossessions.add(verified); + return parseResponse(await this.transport.request(request), request); } catch { return null; } diff --git a/product-source/guanghu-knowledge-base/server/node-possession-proof.test.ts b/product-source/guanghu-knowledge-base/server/node-possession-proof.test.ts index 58b5618..f5dd8e2 100644 --- a/product-source/guanghu-knowledge-base/server/node-possession-proof.test.ts +++ b/product-source/guanghu-knowledge-base/server/node-possession-proof.test.ts @@ -91,7 +91,10 @@ test('verifies a fresh proof from the key fingerprint bound into the signed regi 'A'.repeat(43), ); const response = responseFor(challenge); - assert.equal(verifyNodePossessionResponse(response, challenge, registration, NOW + 1), true); + const possession = verifyNodePossessionResponse(response, challenge, registration, NOW + 1); + assert.equal(possession.registration, registration); + assert.equal(possession.challenge, challenge); + assert.deepEqual(possession.response, response); assert.throws(() => verifyNodePossessionResponse(response, challenge, registration, NOW + 2), /proof_invalid/); }); diff --git a/product-source/guanghu-knowledge-base/server/node-possession-proof.ts b/product-source/guanghu-knowledge-base/server/node-possession-proof.ts index 2cd5682..3315a67 100644 --- a/product-source/guanghu-knowledge-base/server/node-possession-proof.ts +++ b/product-source/guanghu-knowledge-base/server/node-possession-proof.ts @@ -17,6 +17,7 @@ const IDENTIFIER_PATTERN = /^[A-Z0-9][A-Z0-9._:-]{1,159}$/; const NONCE_PATTERN = /^[A-Za-z0-9_-]{43}$/; const issuedChallenges = new WeakSet(); const consumedChallenges = new WeakSet(); +const verifiedPossessions = new WeakSet(); export interface NodePossessionChallenge { accountId: string; @@ -43,6 +44,13 @@ export interface NodePossessionProofSource { prove(challenge: Readonly): Promise; } +export interface VerifiedNodePossession { + challenge: Readonly; + registration: Readonly; + response: Readonly; + verifiedAt: number; +} + function invalidProof(): never { throw new Error('node_possession_proof_invalid'); } @@ -113,7 +121,7 @@ export function verifyNodePossessionResponse( challenge: NodePossessionChallenge, registration: VerifiedNodeRegistration, now = Date.now(), -): true { +): Readonly { try { assertVerifiedNodeRegistration(registration); } catch { @@ -140,7 +148,11 @@ export function verifyNodePossessionResponse( || input.publicKeyPem.includes('PRIVATE KEY') || typeof input.signature !== 'string') invalidProof(); + let publicKeyPem: string; + let signatureText: string; try { + publicKeyPem = input.publicKeyPem as string; + signatureText = input.signature as string; const publicKey = createPublicKey({ key: input.publicKeyPem, format: 'pem' }); if (publicKey.asymmetricKeyType !== 'ed25519') invalidProof(); const fingerprint = createHash('sha256') @@ -154,5 +166,24 @@ export function verifyNodePossessionResponse( invalidProof(); } consumedChallenges.add(challenge); - return true; + const verified = Object.freeze({ + challenge, + registration, + response: Object.freeze({ + challengeId: challenge.challengeId, + publicKeyPem: publicKeyPem!, + schema: RESPONSE_SCHEMA, + signature: signatureText!, + }), + verifiedAt: now, + }); + verifiedPossessions.add(verified); + return verified; +} + +export function assertVerifiedNodePossession( + possession: VerifiedNodePossession, +): VerifiedNodePossession { + if (!verifiedPossessions.has(possession)) invalidProof(); + return possession; } diff --git a/product-source/hololake-platform/architecture/HOLOLAKE-NODE-REGISTRATION-CONTRACT-20260810.md b/product-source/hololake-platform/architecture/HOLOLAKE-NODE-REGISTRATION-CONTRACT-20260810.md index ab72b59..0a660c3 100644 --- a/product-source/hololake-platform/architecture/HOLOLAKE-NODE-REGISTRATION-CONTRACT-20260810.md +++ b/product-source/hololake-platform/architecture/HOLOLAKE-NODE-REGISTRATION-CONTRACT-20260810.md @@ -79,3 +79,23 @@ 运行体交接。当前桌面尚无生产节点密钥库桥,正式运行源固定返回无证明,因此即使未来出现一份 有效登记声明,也不能越过 `verified_node_possession_missing`。代码验证器存在不等于节点密钥、 生产密钥库桥、灯塔会话签发或域连接已经存在。 + +## 私钥证明到域交接的证据链 · 阶段 004 + +本地布尔值 `nodePossessionVerified=true` 不能作为灯塔签发域会话的请求证据。节点证明验证器 +现在生成进程内不可伪造的 `VerifiedNodePossession`:包含已验证登记声明、一次性挑战、节点 +签名响应和验证时间,并通过内部来源集合阻止调用方复制字段冒充验证结果。 + +域运行体交接源只接受这个验证对象,并构造固定 +`gh-aios.domain-runtime-handoff-request/v1` 请求包:账号、域、节点编号、节点类型、完整签名 +登记声明、挑战、节点响应、一次性请求编号和请求时间。它不包含账号密码、访问令牌、验证码 +或节点私钥。每份节点证明最多发起一次交接请求;失败重试必须重新完成新挑战,不能重放旧证明。 + +响应固定为 `gh-aios.domain-runtime-handoff-response/v1`,并必须回绑请求编号。只允许 +`ISSUED + handoff + signer_lookup` 或 `NOT_AUTHORIZED + null + null`。客户端仍须使用当前 +REPO-012 信任快照独立验证 handoff 中的域清单签名、短期会话能力和在线连接回执;服务端 +返回的 signer 名称、公钥字段或自授权布尔值都不能成为信任来源。 + +本阶段闭合的是“证明能够被带到交接边界”的客户端证据结构,不是生产 HTTP 端点。当前公共 +锚点没有域交接端点注册表,桌面运行源仍返回空结果,因此生产会话签发、域运行体连接与在线 +回执继续为 `NOT_EXISTS_0`。 diff --git a/product-source/hololake-platform/architecture/README.md b/product-source/hololake-platform/architecture/README.md index 37241d6..b59f51e 100644 --- a/product-source/hololake-platform/architecture/README.md +++ b/product-source/hololake-platform/architecture/README.md @@ -8,7 +8,7 @@ - [`HOLOLAKE-INTENT-REASONING-MAP-20260809.md`](HOLOLAKE-INTENT-REASONING-MAP-20260809.md):当前产品意图、纠正、思维推理与因果链。 - [`HOLOLAKE-SYSTEM-ARCHITECTURE-20260809.md`](HOLOLAKE-SYSTEM-ARCHITECTURE-20260809.md):`HLP-CURRENT-ARCH-001` 当前完整系统蓝图,覆盖 GH-AIOS 灯塔、五域独立入口、光湖本源域、节点登录与光湖桥。 - [`HOLOLAKE-DESKTOP-0.8.0-CURRENT-CAPABILITY-GAP-20260809.md`](HOLOLAKE-DESKTOP-0.8.0-CURRENT-CAPABILITY-GAP-20260809.md):桌面 0.8.0 已观察能力与最终规划的逐项差距;同时登记线上产品源码仍为 0.4.6 的分叉事实。 -- [`HOLOLAKE-NODE-REGISTRATION-CONTRACT-20260810.md`](HOLOLAKE-NODE-REGISTRATION-CONTRACT-20260810.md):账号、签名节点登记与当前节点私钥持有证明分离后的端点注册表、无凭据声明读取、60 秒一次性 Ed25519 挑战、失败关闭和当前生产缺口验收基线。 +- [`HOLOLAKE-NODE-REGISTRATION-CONTRACT-20260810.md`](HOLOLAKE-NODE-REGISTRATION-CONTRACT-20260810.md):账号、签名节点登记与当前节点私钥持有证明分离后的端点注册表、无凭据声明读取、60 秒一次性 Ed25519 挑战、不可伪造交接证据包、失败关闭和当前生产缺口验收基线。 - [`HOLOLAKE-LANGUAGE-PERSONA-OS.md`](HOLOLAKE-LANGUAGE-PERSONA-OS.md):HoloLake 作为 AI 语言人格驱动操作系统的当前正式产品定位、操作系统映射、原生应用边界与实现缺口。 - [`HOLOLAKE-INTENT-REASONING-MAP-20260807.md`](HOLOLAKE-INTENT-REASONING-MAP-20260807.md):2026-08-07 历史意图层,继续保存形成过程;不再作为当前默认入口。