feat: discover verified persona repository bindings

This commit is contained in:
冰朔 2026-08-12 01:31:55 +08:00
commit b0970ed0d2
18 changed files with 417 additions and 15 deletions

View file

@ -16,7 +16,7 @@ const wake = {
executionRuntime: 'HoloLake-PNCC',
developmentId: 'DEV-20260811-010',
authorizationScope: 'LOCAL_READ_ONLY',
sourceLanguageAnchor: 'HLP-CURRENT-ARCH-001@2026-08-12.2',
sourceLanguageAnchor: 'HLP-CURRENT-ARCH-001@2026-08-12.3',
},
}

View file

@ -0,0 +1,85 @@
import { describe, expect, it, vi } from 'vitest'
import { resolvePersonaRepositoryBinding } from './personaRepositoryBinding'
const binding = {
personaId: 'ICE-P-ZY001',
repositoryPath: '/persona',
gitHead: 'a'.repeat(40),
repositoryClean: true,
brainEntry: 'brain/CORE.hdlp',
currentCheckpoint: '.hololake/persona/CURRENT.hdlp',
humanResponsibilitySubject: 'ICE-GL∞',
modelProviderId: 'provider-1',
modelId: 'model-1',
modelBaseUrl: 'https://model.invalid/v1',
cognitiveGravity: {
schema: 'hololake.persona-cognitive-gravity-evidence/v1',
subjectPersonaId: 'ICE-P-ZY001',
sourcePath: 'brain/B0.hdlp',
sourceHash: 'b'.repeat(64),
frameSchema: 'guanghu.zhuyuan-cognitive-gravity-frame/v1',
},
}
function receipt(bindings: unknown[], failures: unknown[] = []) {
return {
schema: 'hololake.pncc-repository-discovery/v1',
expectedPersonaId: 'ICE-P-ZY001',
inspectedRepositoryCount: 2,
bindingCount: bindings.length,
bindings,
failures,
}
}
describe('resolvePersonaRepositoryBinding', () => {
it('does not call native discovery without mounted repositories', async () => {
const discover = vi.fn()
await expect(resolvePersonaRepositoryBinding({
personaId: 'ICE-P-ZY001', repositoryPaths: [], discover,
})).resolves.toEqual({ phase: 'unavailable', inspectedRepositoryCount: 0, failures: [] })
expect(discover).not.toHaveBeenCalled()
})
it('returns the one evidence-verified persona repository', async () => {
const discover = vi.fn().mockResolvedValue(receipt([binding], [{ repositoryPath: '/ordinary', code: 'PERSONA_MANIFEST_READ_FAILED' }]))
const result = await resolvePersonaRepositoryBinding({
personaId: 'ICE-P-ZY001', repositoryPaths: ['/ordinary', '/persona', '/persona'], discover,
})
expect(result.phase).toBe('bound')
if (result.phase === 'bound') expect(result.binding.repositoryPath).toBe('/persona')
expect(discover).toHaveBeenCalledWith('discover_persona_code_channel_repositories', {
input: { expectedPersonaId: 'ICE-P-ZY001', repositoryPaths: ['/ordinary', '/persona'] },
})
})
it('keeps an ordinary mounted repository unbound', async () => {
const result = await resolvePersonaRepositoryBinding({
personaId: 'ICE-P-ZY001',
repositoryPaths: ['/ordinary'],
discover: vi.fn().mockResolvedValue(receipt([], [{ repositoryPath: '/ordinary', code: 'PERSONA_MANIFEST_READ_FAILED' }])),
})
expect(result.phase).toBe('unbound')
})
it('refuses to choose when more than one persona root validates', async () => {
const result = await resolvePersonaRepositoryBinding({
personaId: 'ICE-P-ZY001',
repositoryPaths: ['/persona-a', '/persona-b'],
discover: vi.fn().mockResolvedValue(receipt([
{ ...binding, repositoryPath: '/persona-a' },
{ ...binding, repositoryPath: '/persona-b' },
])),
})
expect(result.phase).toBe('ambiguous')
})
it('fails closed on a mismatched or malformed receipt', async () => {
const result = await resolvePersonaRepositoryBinding({
personaId: 'ICE-P-ZY001',
repositoryPaths: ['/persona'],
discover: vi.fn().mockResolvedValue(receipt([{ ...binding, personaId: 'OTHER' }])),
})
expect(result).toMatchObject({ phase: 'error', code: 'PERSONA_REPOSITORY_DISCOVERY_RECEIPT_INVALID' })
})
})

View file

@ -0,0 +1,154 @@
import { invoke } from '@tauri-apps/api/core'
import { isTauri, mockInvoke } from '../mock-tauri'
export interface PersonaRepositoryBinding {
personaId: string
repositoryPath: string
gitHead: string
repositoryClean: boolean
brainEntry: string
currentCheckpoint: string
humanResponsibilitySubject: string
modelProviderId: string
modelId: string
modelBaseUrl: string
cognitiveGravity: {
schema: 'hololake.persona-cognitive-gravity-evidence/v1'
subjectPersonaId: string
sourcePath: string
sourceHash: string
frameSchema: 'guanghu.zhuyuan-cognitive-gravity-frame/v1'
}
}
export interface PersonaRepositoryBindingFailure {
repositoryPath: string
code: string
}
export type PersonaRepositoryBindingResolution =
| { phase: 'unavailable'; inspectedRepositoryCount: 0; failures: [] }
| { phase: 'unbound'; inspectedRepositoryCount: number; failures: PersonaRepositoryBindingFailure[] }
| { phase: 'ambiguous'; inspectedRepositoryCount: number; failures: PersonaRepositoryBindingFailure[] }
| { phase: 'bound'; inspectedRepositoryCount: number; binding: PersonaRepositoryBinding; failures: PersonaRepositoryBindingFailure[] }
| { phase: 'error'; inspectedRepositoryCount: number; failures: PersonaRepositoryBindingFailure[]; code: string }
type DiscoveryRunner = (
command: 'discover_persona_code_channel_repositories',
args: { input: { expectedPersonaId: string; repositoryPaths: string[] } },
) => Promise<unknown>
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null && !Array.isArray(value)
}
function requiredString(record: Record<string, unknown>, key: string): string {
const value = Reflect.get(record, key)
if (typeof value !== 'string' || !value.trim()) throw new Error('PERSONA_REPOSITORY_DISCOVERY_RECEIPT_INVALID')
return value
}
function requiredNumber(record: Record<string, unknown>, key: string): number {
const value = Reflect.get(record, key)
if (!Number.isSafeInteger(value) || (value as number) < 0) {
throw new Error('PERSONA_REPOSITORY_DISCOVERY_RECEIPT_INVALID')
}
return value as number
}
function parseFailure(value: unknown): PersonaRepositoryBindingFailure {
if (!isRecord(value)) throw new Error('PERSONA_REPOSITORY_DISCOVERY_RECEIPT_INVALID')
return { repositoryPath: requiredString(value, 'repositoryPath'), code: requiredString(value, 'code') }
}
function parseBinding(value: unknown, expectedPersonaId: string): PersonaRepositoryBinding {
if (!isRecord(value)) throw new Error('PERSONA_REPOSITORY_DISCOVERY_RECEIPT_INVALID')
const personaId = requiredString(value, 'personaId')
const gravity = Reflect.get(value, 'cognitiveGravity')
if (personaId !== expectedPersonaId || !isRecord(gravity)) {
throw new Error('PERSONA_REPOSITORY_DISCOVERY_RECEIPT_INVALID')
}
const gravitySchema = requiredString(gravity, 'schema')
const frameSchema = requiredString(gravity, 'frameSchema')
const sourceHash = requiredString(gravity, 'sourceHash')
if (
gravitySchema !== 'hololake.persona-cognitive-gravity-evidence/v1'
|| frameSchema !== 'guanghu.zhuyuan-cognitive-gravity-frame/v1'
|| !/^[a-f0-9]{64}$/.test(sourceHash)
|| requiredString(gravity, 'subjectPersonaId') !== expectedPersonaId
) {
throw new Error('PERSONA_REPOSITORY_DISCOVERY_RECEIPT_INVALID')
}
const repositoryClean = Reflect.get(value, 'repositoryClean')
if (typeof repositoryClean !== 'boolean') throw new Error('PERSONA_REPOSITORY_DISCOVERY_RECEIPT_INVALID')
return {
personaId,
repositoryPath: requiredString(value, 'repositoryPath'),
gitHead: requiredString(value, 'gitHead'),
repositoryClean,
brainEntry: requiredString(value, 'brainEntry'),
currentCheckpoint: requiredString(value, 'currentCheckpoint'),
humanResponsibilitySubject: requiredString(value, 'humanResponsibilitySubject'),
modelProviderId: requiredString(value, 'modelProviderId'),
modelId: requiredString(value, 'modelId'),
modelBaseUrl: requiredString(value, 'modelBaseUrl'),
cognitiveGravity: {
schema: gravitySchema,
subjectPersonaId: expectedPersonaId,
sourcePath: requiredString(gravity, 'sourcePath'),
sourceHash,
frameSchema,
},
}
}
async function runNativeDiscovery(
command: 'discover_persona_code_channel_repositories',
args: { input: { expectedPersonaId: string; repositoryPaths: string[] } },
): Promise<unknown> {
return isTauri() ? invoke<unknown>(command, args) : mockInvoke<unknown>(command, args)
}
export async function resolvePersonaRepositoryBinding({
personaId,
repositoryPaths,
discover = runNativeDiscovery,
}: {
personaId: string
repositoryPaths: readonly string[]
discover?: DiscoveryRunner
}): Promise<PersonaRepositoryBindingResolution> {
const candidates = [...new Set(repositoryPaths.map((path) => path.trim()).filter(Boolean))]
if (candidates.length === 0) {
return { phase: 'unavailable', inspectedRepositoryCount: 0, failures: [] }
}
try {
const value = await discover('discover_persona_code_channel_repositories', {
input: { expectedPersonaId: personaId, repositoryPaths: candidates },
})
if (!isRecord(value)
|| requiredString(value, 'schema') !== 'hololake.pncc-repository-discovery/v1'
|| requiredString(value, 'expectedPersonaId') !== personaId) {
throw new Error('PERSONA_REPOSITORY_DISCOVERY_RECEIPT_INVALID')
}
const inspectedRepositoryCount = requiredNumber(value, 'inspectedRepositoryCount')
const bindingCount = requiredNumber(value, 'bindingCount')
const rawBindings = Reflect.get(value, 'bindings')
const rawFailures = Reflect.get(value, 'failures')
if (!Array.isArray(rawBindings) || !Array.isArray(rawFailures) || bindingCount !== rawBindings.length) {
throw new Error('PERSONA_REPOSITORY_DISCOVERY_RECEIPT_INVALID')
}
const bindings = rawBindings.map((binding) => parseBinding(binding, personaId))
const failures = rawFailures.map(parseFailure)
if (bindings.length === 0) return { phase: 'unbound', inspectedRepositoryCount, failures }
if (bindings.length > 1) return { phase: 'ambiguous', inspectedRepositoryCount, failures }
return { phase: 'bound', inspectedRepositoryCount, binding: bindings[0], failures }
} catch (error) {
return {
phase: 'error',
inspectedRepositoryCount: candidates.length,
failures: [],
code: error instanceof Error ? error.message : 'PERSONA_REPOSITORY_DISCOVERY_FAILED',
}
}
}