diff --git a/deployment/receipts/GH-HOLOLAKE-DOMAIN-LOGIN-GATE-20260810-001.json b/deployment/receipts/GH-HOLOLAKE-DOMAIN-LOGIN-GATE-20260810-001.json deleted file mode 100644 index 938e5c3fd..000000000 --- a/deployment/receipts/GH-HOLOLAKE-DOMAIN-LOGIN-GATE-20260810-001.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "schema": "gh.hololake.desktop-stage-receipt/v1", - "receiptId": "GH-HOLOLAKE-DOMAIN-LOGIN-GATE-20260810-001", - "developmentId": "DEV-20260809-007", - "recordedAt": "2026-08-09T22:04:11Z", - "source": { - "repositoryId": "REPO-014", - "commit": "b24d5b54525fd06678c10322c4870b374f2c3c91", - "tree": "5d16121d6d247886d50b93950f26b426803a444f", - "baselineRemoteMain": "2c50b285572516c6228abd5e8e97f2babbfe259c", - "lighthouseSourceCommit": "34e1949a113be8d4871e61c094f2ae06e0bc5a45" - }, - "acceptance": { - "genericLoginRequiresExplicitDomainSelection": true, - "stableDomainIdPropagatedToProbe": true, - "nodeTypeSelectionExplicit": true, - "enterpriseDomainsCannotReuseFifthRenderer": true, - "fifthRuntimeRequiresMatchingReadyEvidence": true, - "staleProbeResponsesIgnored": true, - "privateResourcesProjectedBeforeRuntimeReady": false - }, - "verification": { - "desktopTests": "59/59", - "frontendTests": "4993/4993", - "rustTests": "1142/1142", - "nativeQualityState": "GHNQG_PASS_100", - "nativeQualityReceiptSha256": "42581166b0c39054d8902d6ae3942264188301fbce4d1be64066627aa4dcfcdb", - "codesign": "PASS_DEEP_STRICT", - "notarization": "NOT_RUN", - "desktopAppAsarSha256": "7f1ccffd98102f723515d3b50a8a0f8814d63bc812871ffa27d31700e09af09c", - "desktopExecutableSha256": "ed01ffa1fb86f5491fd390aa3b621a394a5aa946c59c1e033c140ac9c41250be", - "currentUiEvidenceSha256": "6b11eecb64f6ef56acc1a58cc2a082e49744eb24dab4e02401db489f0cd6510b" - }, - "runtimeReality": { - "installedDesktopPath": "/Users/bingshuolingdianyuanhe/Desktop/HoloLake Era.app", - "applicationLaunch": "PASS", - "currentTrustedSignerCount": 0, - "domainRuntimeEntry": "FAIL_CLOSED", - "reason": "No trusted target-domain signer, scoped capability, and matching online receipt are currently available." - } -} diff --git a/product-source/guanghu-knowledge-base/src/App.tsx b/product-source/guanghu-knowledge-base/src/App.tsx index 6315b6fd5..f13e55170 100644 --- a/product-source/guanghu-knowledge-base/src/App.tsx +++ b/product-source/guanghu-knowledge-base/src/App.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useMemo, useRef, useState, type CSSProperties, type PointerEvent as ReactPointerEvent } from 'react'; +import { useCallback, useEffect, useMemo, useState, type CSSProperties, type PointerEvent as ReactPointerEvent } from 'react'; import { api, DocTreeNode, DocContent, type ChannelState, type ModuleManifest } from './api'; import { DocTree } from './components/DocTree'; import { Editor } from './components/Editor'; @@ -13,7 +13,6 @@ import { ModuleLibrarySheet } from './components/ModuleLibrarySheet'; import { cleanDisplayText } from './presentation'; import { WorldEntry } from './components/WorldEntry'; import { DomainConnectionSheet } from './components/DomainConnectionSheet'; -import { createDomainEntryTarget, type DomainEntryTarget, type DomainNodeType } from './domain-entry-state'; import type { DomainRouteId } from './public-domain-directory'; type View = 'editor' | 'history'; @@ -85,7 +84,6 @@ export default function App() { const [activeModule, setActiveModule] = useState('knowledge'); const [storageSheetOpen, setStorageSheetOpen] = useState(false); const [domainConnectionOpen, setDomainConnectionOpen] = useState(false); - const [domainEntryTarget, setDomainEntryTarget] = useState(null); const [storageSheetInitialMode, setStorageSheetInitialMode] = useState<'local' | 'server' | undefined>(); const [serverSession, setServerSession] = useState({ authenticated: false, nodeId: '' }); const [serverProfiles, setServerProfiles] = useState([]); @@ -103,7 +101,6 @@ export default function App() { const [lastChannelReceipt, setLastChannelReceipt] = useState(''); const [worldEntered, setWorldEntered] = useState(false); const [domainAccess, setDomainAccess] = useState({ blockers: [], runtimeReady: false, stage: 'checking' }); - const domainAccessRequest = useRef(0); const storageMode = repositoryStatus?.remote ? 'server' : 'local'; const storageLabel = storageMode === 'server' ? '服务器已托管' : '仅本机'; @@ -179,35 +176,19 @@ export default function App() { } }, []); - const refreshDomainAccess = useCallback(async (domainId = 'DOM-FIFTH-0001') => { - const request = ++domainAccessRequest.current; + const refreshDomainAccess = useCallback(async () => { const server = (window as any).hololake?.server; if (!server?.domainAccess) { - if (request === domainAccessRequest.current) setDomainAccess({ blockers: ['desktop_runtime_required'], domainId, runtimeReady: false, stage: 'login-required' }); + setDomainAccess({ blockers: ['desktop_runtime_required'], runtimeReady: false, stage: 'login-required' }); return; } try { - const result = await server.domainAccess(domainId); - if (request === domainAccessRequest.current) setDomainAccess(result); + setDomainAccess(await server.domainAccess('DOM-FIFTH-0001')); } catch { - if (request === domainAccessRequest.current) setDomainAccess({ blockers: ['domain_access_probe_failed'], domainId, runtimeReady: false, stage: 'login-required' }); + setDomainAccess({ blockers: ['domain_access_probe_failed'], runtimeReady: false, stage: 'login-required' }); } }, []); - const openDomainConnection = useCallback((routeId: DomainRouteId | null) => { - const target = routeId ? createDomainEntryTarget(routeId) : null; - setDomainEntryTarget(target); - setDomainConnectionOpen(true); - if (target) { - setDomainAccess({ blockers: [], domainId: target.domain.stableDomainId, runtimeReady: false, stage: 'checking' }); - void refreshDomainAccess(target.domain.stableDomainId); - } - }, [refreshDomainAccess]); - - const selectDomainNodeType = useCallback((nodeType: DomainNodeType) => { - setDomainEntryTarget(current => current ? createDomainEntryTarget(current.domain.routeId, nodeType) : null); - }, []); - const refreshChannel = useCallback(async () => { try { const [channel, registry] = await Promise.all([api.getChannel(), api.getModules()]); @@ -412,7 +393,9 @@ export default function App() { setActiveModule('knowledge'); setWorldEntered(true); }} - onOpenConnection={openDomainConnection} + onOpenConnection={() => { + setDomainConnectionOpen(true); + }} /> )}
setDomainConnectionOpen(false)} - onSelectTarget={routeId => openDomainConnection(routeId)} - onSelectNodeType={selectDomainNodeType} onEnterRuntime={() => { - if (!domainEntryTarget || domainEntryTarget.domain.routeId !== 'fifth' || !domainAccess.runtimeReady || domainAccess.domainId !== domainEntryTarget.domain.stableDomainId) return; + if (!domainAccess.runtimeReady) return; setActiveRoute('fifth'); setActiveModule('knowledge'); setWorldEntered(true); diff --git a/product-source/guanghu-knowledge-base/src/components/DomainConnectionSheet.tsx b/product-source/guanghu-knowledge-base/src/components/DomainConnectionSheet.tsx index e3f704162..f8b417ffb 100644 --- a/product-source/guanghu-knowledge-base/src/components/DomainConnectionSheet.tsx +++ b/product-source/guanghu-knowledge-base/src/components/DomainConnectionSheet.tsx @@ -1,23 +1,17 @@ import { Cloud, Laptop, ShieldCheck, X } from 'lucide-react'; import { projectDomainConnectionSteps, 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'; interface Props { access: DomainAccessProjection; - target: DomainEntryTarget | null; open: boolean; onClose: () => void; - onSelectTarget: (routeId: DomainRouteId) => void; - onSelectNodeType: (nodeType: DomainNodeType) => void; onEnterRuntime: () => void; onOpenCodeChannel: () => void; } -export function DomainConnectionSheet({ access, target, open, onClose, onSelectTarget, onSelectNodeType, onEnterRuntime, onOpenCodeChannel }: Props) { +export function DomainConnectionSheet({ access, open, onClose, onEnterRuntime, onOpenCodeChannel }: Props) { if (!open) return null; const steps = projectDomainConnectionSteps(access); - const canEnter = canEnterSelectedDomainRuntime(target, access); return (
{ @@ -26,22 +20,18 @@ export function DomainConnectionSheet({ access, target, open, onClose, onSelectT
- {target?.domain.stableDomainId ?? 'SELECT-DOMAIN'} -

{target ? `接入${target.domain.displayName}` : '选择要接入的域'}

+ DOM-FIFTH-0001 +

接入第五域 · 光湖本源域

进入域不是切换页面。系统必须验证账户、登记节点、目标域授权、会话能力和在线回执。

-
- {publicDomainDirectory.map(domain => )} -
- {!target ?

{projectDomainRuntimeBoundary(target, access)}

: <>

{projectDomainTrustSource(access)}

- - +
+
    @@ -54,15 +44,14 @@ export function DomainConnectionSheet({ access, target, open, onClose, onSelectT ))}
-

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

- } +

代码频道账号只用于仓库与同步,是节点身份的辅助证明之一,不能单独签发第五域权限。

- + -
diff --git a/product-source/guanghu-knowledge-base/src/components/WorldEntry.tsx b/product-source/guanghu-knowledge-base/src/components/WorldEntry.tsx index 147a75aeb..a564bc529 100644 --- a/product-source/guanghu-knowledge-base/src/components/WorldEntry.tsx +++ b/product-source/guanghu-knowledge-base/src/components/WorldEntry.tsx @@ -6,7 +6,7 @@ interface Props { access: { blockers: string[]; runtimeReady: boolean; stage: 'checking' | 'login-required' | 'identity-verified' | 'runtime-ready' }; onEnterFifthRuntime: () => void; onEnterLocalWorkspace: () => void; - onOpenConnection: (routeId: DomainRouteId | null) => void; + onOpenConnection: () => void; } export function WorldEntry({ access, onEnterFifthRuntime, onEnterLocalWorkspace, onOpenConnection }: Props) { @@ -55,7 +55,7 @@ export function WorldEntry({ access, onEnterFifthRuntime, onEnterLocalWorkspace,
{access.stage === 'runtime-ready' ? '节点、域清单、会话能力与连接回执已验证' : access.stage === 'identity-verified' ? '账户与节点已验证 · 尚缺域清单、会话能力和连接回执' : access.stage === 'checking' ? '正在核对真实接入证据' : '公开门厅可查看 · 尚未登录或接入节点'}
- +
@@ -82,7 +82,7 @@ export function WorldEntry({ access, onEnterFifthRuntime, onEnterLocalWorkspace, - +
@@ -106,7 +106,6 @@ export function WorldEntry({ access, onEnterFifthRuntime, onEnterLocalWorkspace, {selectedVestibule.stableDomainId} {selectedVestibule.themeLabel} 仅公开门厅资料 · 私有资源未装载 - )} 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 deleted file mode 100644 index 2901e4768..000000000 --- a/product-source/guanghu-knowledge-base/src/domain-entry-state.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -import assert from 'node:assert/strict'; -import test from 'node:test'; -import { canEnterSelectedDomainRuntime, createDomainEntryTarget, projectDomainRuntimeBoundary } from './domain-entry-state.js'; - -const ready = (domainId: string) => ({ blockers: [], domainId, 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); - assert.match(projectDomainRuntimeBoundary(null, ready('DOM-FIFTH-0001')), /先选择目标域/); -}); - -test('the selected stable domain id must match the returned access evidence', () => { - const fifth = createDomainEntryTarget('fifth', 'cloud-resident'); - assert.equal(canEnterSelectedDomainRuntime(fifth, ready('DOMAIN-MAIN')), false); - assert.match(projectDomainRuntimeBoundary(fifth, ready('DOMAIN-MAIN')), /另一个域/); -}); - -test('enterprise vestibules cannot reuse the Fifth Domain renderer', () => { - const main = createDomainEntryTarget('main'); - assert.equal(main.domain.stableDomainId, 'DOMAIN-MAIN'); - assert.equal(main.nodeType, 'local-terminal'); - assert.equal(canEnterSelectedDomainRuntime(main, ready('DOMAIN-MAIN')), false); - assert.match(projectDomainRuntimeBoundary(main, ready('DOMAIN-MAIN')), /独立运行端点与主题包尚未登记/); -}); - -test('the Fifth Domain opens only with matching runtime-ready evidence', () => { - const fifth = createDomainEntryTarget('fifth', 'cloud-resident'); - assert.equal(canEnterSelectedDomainRuntime(fifth, ready('DOM-FIFTH-0001')), true); - assert.match(projectDomainRuntimeBoundary(fifth, ready('DOM-FIFTH-0001')), /已经匹配/); -}); diff --git a/product-source/guanghu-knowledge-base/src/domain-entry-state.ts b/product-source/guanghu-knowledge-base/src/domain-entry-state.ts deleted file mode 100644 index 70c649553..000000000 --- a/product-source/guanghu-knowledge-base/src/domain-entry-state.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { getPublicDomainVestibule, type DomainRouteId, type PublicDomainVestibule } from './public-domain-directory.js'; -import type { DomainAccessProjection } from './domain-connection.js'; - -export type DomainNodeType = 'local-terminal' | 'cloud-resident'; - -export interface DomainEntryTarget { - domain: PublicDomainVestibule; - nodeType: DomainNodeType; -} - -export function createDomainEntryTarget(routeId: DomainRouteId, nodeType: DomainNodeType = 'local-terminal'): DomainEntryTarget { - const domain = getPublicDomainVestibule(routeId); - if (!domain.supportedNodeTypes.includes(nodeType)) throw new Error('DOMAIN_NODE_TYPE_NOT_SUPPORTED'); - return Object.freeze({ domain, nodeType }); -} - -export function canEnterSelectedDomainRuntime(target: DomainEntryTarget | null, access: DomainAccessProjection): boolean { - if (!target || !access.runtimeReady) return false; - if (access.domainId !== target.domain.stableDomainId) 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'; -} - -export function projectDomainRuntimeBoundary(target: DomainEntryTarget | null, access: DomainAccessProjection): string { - if (!target) return '请先选择目标域;系统不会把通用登录请求默认路由到第五域。'; - if (access.domainId && access.domainId !== target.domain.stableDomainId) { - return '回读证据属于另一个域;当前入口保持关闭。'; - } - if (target.domain.routeId !== 'fifth') { - return `${target.domain.displayName}的独立运行端点与主题包尚未登记;当前只能查看公开门厅。`; - } - return access.runtimeReady - ? '第五域运行端点、签名清单、会话能力与在线回执已经匹配。' - : '第五域入口保持关闭,直到四项真实接入证据全部匹配。'; -} diff --git a/product-source/guanghu-knowledge-base/src/styles/app.css b/product-source/guanghu-knowledge-base/src/styles/app.css index 441aa298c..3798a7cfa 100644 --- a/product-source/guanghu-knowledge-base/src/styles/app.css +++ b/product-source/guanghu-knowledge-base/src/styles/app.css @@ -3142,28 +3142,6 @@ select:focus-visible { line-height: 1.65; } -.domain-target-picker { - display: grid; - grid-template-columns: repeat(5, minmax(0, 1fr)); - gap: 6px; - padding: 14px 20px 0; -} - -.domain-target-picker button { - display: grid; - gap: 4px; - min-height: 52px; - padding: 8px 6px; - border: 1px solid var(--lake-border-soft); - border-radius: 9px; - background: rgba(7, 17, 29, .62); - color: var(--lake-text-soft); - font-size: 9px; -} - -.domain-target-picker button span { color: var(--lake-muted); } -.domain-target-picker button[data-selected="true"] { border-color: var(--lake-accent); background: var(--lake-accent-soft); color: var(--lake-text); } - .domain-node-modes { display: grid; grid-template-columns: 1fr 1fr; @@ -3171,19 +3149,15 @@ select:focus-visible { padding: 16px 20px; } -.domain-node-modes button { +.domain-node-modes article { display: flex; gap: 11px; padding: 13px; border: 1px solid var(--lake-border-soft); border-radius: 11px; background: rgba(7, 17, 29, .62); - color: var(--lake-text); - text-align: left; } -.domain-node-modes button[data-selected="true"] { border-color: var(--lake-accent); background: var(--lake-accent-soft); } - .domain-node-modes svg { width: 19px; color: var(--lake-accent); @@ -3250,7 +3224,6 @@ select:focus-visible { } @media (max-width: 660px) { - .domain-target-picker { grid-template-columns: 1fr 1fr; } .domain-node-modes { grid-template-columns: 1fr; } .domain-connection-sheet .storage-sheet-footer { flex-wrap: wrap; } }