hololake-system-architecture/product-source/hololake-platform/guanghu-os/pncc-runtime/pncc-runtime.mjs

456 lines
19 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
import { spawnSync } from 'node:child_process'
import { createHash, randomUUID } from 'node:crypto'
import {
closeSync,
existsSync,
mkdirSync,
openSync,
readFileSync,
realpathSync,
renameSync,
rmSync,
writeFileSync,
} from 'node:fs'
import { createServer } from 'node:http'
import { basename, dirname, isAbsolute, join, normalize, resolve, sep } from 'node:path'
import { fileURLToPath } from 'node:url'
const MANIFEST_PATH = '.hololake/persona/manifest.json'
const MANIFEST_SCHEMA = 'hololake.persona/v1'
const GRAVITY_SCHEMA = 'hololake.persona-cognitive-gravity-binding/v1'
const EVENT_SCHEMA = 'guanghu.pncc-runtime-event/v1'
const JOURNAL_SCHEMA = 'guanghu.pncc-runtime-journal/v1'
const STATUS_SCHEMA = 'guanghu.pncc-runtime-status/v1'
const MAX_ARTIFACT_BYTES = 2 * 1024 * 1024
const MAX_ARTIFACTS = 256
function sha256(value) {
return createHash('sha256').update(value).digest('hex')
}
function fail(code, detail = '') {
throw new Error(detail ? `${code}: ${detail}` : code)
}
function runGit(repository, args, label, options = {}) {
const result = spawnSync('git', ['-C', repository, ...args], {
encoding: options.encoding ?? 'utf8',
env: options.env ?? process.env,
maxBuffer: 8 * 1024 * 1024,
})
if (result.status !== 0) {
fail(label, String(result.stderr || result.stdout || '').trim())
}
return result.stdout
}
function validateFullHead(value) {
if (!/^[0-9a-f]{40}$/.test(value)) fail('PNCC_FULL_GIT_HEAD_INVALID')
return value
}
function validateText(value, label, maximum = 256) {
if (typeof value !== 'string' || value.trim() !== value || value.length === 0 || value.length > maximum || /[\u0000-\u001f]/u.test(value)) {
fail(`PNCC_${label}_INVALID`)
}
return value
}
function validateRelativePath(value) {
validateText(value, 'RELATIVE_PATH', 1024)
const normalized = normalize(value)
if (isAbsolute(value) || normalized === '..' || normalized.startsWith(`..${sep}`) || normalized.split(sep).includes('.git')) {
fail('PNCC_REPOSITORY_RELATIVE_PATH_INVALID', value)
}
return value
}
function exactGitRoot(repository) {
const candidate = realpathSync(repository)
const top = realpathSync(String(runGit(candidate, ['rev-parse', '--show-toplevel'], 'PNCC_GIT_ROOT_READ')).trim())
if (candidate !== top) fail('PNCC_REPOSITORY_MUST_BE_EXACT_GIT_ROOT')
return candidate
}
function committedArtifact(repository, head, path) {
validateRelativePath(path)
const object = validateFullHead(String(runGit(repository, ['rev-parse', `${head}:${path}`], 'PNCC_GIT_OBJECT_ID_READ')).trim().toLowerCase())
const type = String(runGit(repository, ['cat-file', '-t', object], 'PNCC_GIT_OBJECT_TYPE_READ')).trim()
if (type !== 'blob') fail('PNCC_COMMITTED_OBJECT_NOT_BLOB', path)
const mode = String(runGit(repository, ['ls-tree', head, '--', path], 'PNCC_GIT_OBJECT_MODE_READ')).trim().split(/\s+/u)[0]
if (!['100644', '100755'].includes(mode)) fail('PNCC_COMMITTED_OBJECT_NOT_REGULAR_FILE', path)
const bytes = runGit(repository, ['cat-file', 'blob', object], 'PNCC_GIT_OBJECT_READ', { encoding: 'buffer' })
if (!Buffer.isBuffer(bytes) || bytes.length === 0 || bytes.length > MAX_ARTIFACT_BYTES) {
fail('PNCC_COMMITTED_OBJECT_SIZE_INVALID', path)
}
return { relativePath: path, gitObjectId: object, sha256: sha256(bytes), byteLength: bytes.length, bytes }
}
function parseManifest(repository, head) {
const evidence = committedArtifact(repository, head, MANIFEST_PATH)
let manifest
try {
manifest = JSON.parse(evidence.bytes.toString('utf8'))
} catch (error) {
fail('PNCC_PERSONA_MANIFEST_INVALID', error.message)
}
if (manifest.schema !== MANIFEST_SCHEMA) fail('PNCC_PERSONA_MANIFEST_SCHEMA_UNSUPPORTED')
validateText(manifest.personaId, 'PERSONA_ID')
validateText(manifest.humanResponsibilitySubject, 'HUMAN_RESPONSIBILITY_SUBJECT')
validateRelativePath(manifest.brainEntry)
validateRelativePath(manifest.currentCheckpoint)
if (manifest.cognitiveGravity?.schema !== GRAVITY_SCHEMA || manifest.cognitiveGravity.subjectPersonaId !== manifest.personaId) {
fail('PNCC_COGNITIVE_GRAVITY_BINDING_INVALID')
}
validateRelativePath(manifest.cognitiveGravity.sourcePath)
validateText(manifest.cognitiveGravity.frameSchema, 'COGNITIVE_GRAVITY_FRAME_SCHEMA')
validateText(manifest.primaryNode, 'PRIMARY_NODE')
if (manifest.carrierBinding?.state !== 'UNBOUND_EVIDENCE_REQUIRED' && manifest.carrierBinding?.state !== 'BOUND_VERIFIED') {
fail('PNCC_CARRIER_BINDING_STATE_INVALID')
}
if (!Array.isArray(manifest.organs) || manifest.organs.length === 0) fail('PNCC_ORGAN_MANIFEST_EMPTY')
return { manifest, evidence }
}
export function inspectPersonaRepository(repositoryPath, nodeId) {
validateText(nodeId, 'NODE_ID')
const repository = exactGitRoot(repositoryPath)
const head = validateFullHead(String(runGit(repository, ['rev-parse', 'HEAD'], 'PNCC_GIT_HEAD_READ')).trim().toLowerCase())
const dirty = String(runGit(repository, ['status', '--porcelain', '--untracked-files=all'], 'PNCC_GIT_STATUS_READ')).trim()
if (dirty) fail('PNCC_REPOSITORY_DIRTY')
const { manifest, evidence: manifestEvidence } = parseManifest(repository, head)
if (manifest.primaryNode !== nodeId) fail('PNCC_PRIMARY_NODE_MISMATCH')
const paths = new Set([manifest.brainEntry, manifest.currentCheckpoint, manifest.cognitiveGravity.sourcePath])
for (const organ of manifest.organs) {
validateText(organ.organId, 'ORGAN_ID')
if (organ.mode !== 'READ_ONLY') fail('PNCC_UNSAFE_ORGAN_MODE', organ.organId)
if (!Array.isArray(organ.paths) || organ.paths.length === 0) fail('PNCC_ORGAN_PATHS_EMPTY', organ.organId)
for (const path of organ.paths) paths.add(validateRelativePath(path))
}
if (paths.size > MAX_ARTIFACTS) fail('PNCC_DECLARED_ARTIFACT_LIMIT_EXCEEDED')
const artifacts = [...paths].sort().map((path) => {
const artifact = committedArtifact(repository, head, path)
return { relativePath: artifact.relativePath, gitObjectId: artifact.gitObjectId, sha256: artifact.sha256, byteLength: artifact.byteLength }
})
return {
schema: 'guanghu.pncc-persona-repository-inspection/v1',
state: 'PERSONA_REPOSITORY_BOUND_CARRIER_SEPARATE',
personaId: manifest.personaId,
humanResponsibilitySubject: manifest.humanResponsibilitySubject,
nodeId,
repositoryPath: repository,
repositoryClean: true,
gitHead: head,
manifestSha256: manifestEvidence.sha256,
brainEntry: manifest.brainEntry,
currentCheckpoint: manifest.currentCheckpoint,
cognitiveGravity: manifest.cognitiveGravity,
carrierBindingState: manifest.carrierBinding.state,
modelInferenceStarted: false,
realityExecutionAllowed: false,
artifacts,
manifest,
receiptId: sha256(`${manifest.personaId}\n${nodeId}\n${repository}\n${head}\n${manifestEvidence.sha256}`),
}
}
function eventHash(event) {
return sha256([
event.schema,
event.sequence,
event.kind,
event.personaId,
event.nodeId,
event.bootId,
event.gitHead,
event.detailsSha256,
event.observedAt,
event.previousEventHash,
].join('\n'))
}
function appendEvent(runtime, kind, details = {}) {
const previousEventHash = runtime.events.at(-1)?.eventHash ?? '0'.repeat(64)
const event = {
schema: EVENT_SCHEMA,
sequence: runtime.events.length + 1,
kind,
personaId: runtime.inspection.personaId,
nodeId: runtime.nodeId,
bootId: runtime.bootId,
gitHead: runtime.inspection.gitHead,
details,
detailsSha256: sha256(JSON.stringify(details)),
observedAt: new Date().toISOString(),
previousEventHash,
}
event.eventHash = eventHash(event)
runtime.events.push(event)
writeJsonAtomic(runtime.journalPath, { schema: JOURNAL_SCHEMA, events: runtime.events })
return event
}
export function verifyEventJournal(events) {
let previous = '0'.repeat(64)
for (let index = 0; index < events.length; index += 1) {
const event = events[index]
if (event.schema !== EVENT_SCHEMA || event.sequence !== index + 1 || event.previousEventHash !== previous || event.eventHash !== eventHash(event)) {
return { ok: false, failedSequence: index + 1 }
}
previous = event.eventHash
}
return { ok: true, eventCount: events.length, chainHead: previous }
}
function writeJsonAtomic(path, value) {
mkdirSync(dirname(path), { recursive: true, mode: 0o700 })
const temporary = join(dirname(path), `.${basename(path)}.${randomUUID()}.tmp`)
writeFileSync(temporary, `${JSON.stringify(value, null, 2)}\n`, { mode: 0o600, flag: 'wx' })
renameSync(temporary, path)
}
function runtimeStatus(runtime) {
const verification = verifyEventJournal(runtime.events)
if (!verification.ok) fail('PNCC_EVENT_JOURNAL_INVALID')
return {
schema: STATUS_SCHEMA,
state: runtime.released ? 'DORMANT_RELEASED' : 'RESIDENT_BOUND_CARRIER_UNBOUND',
personaId: runtime.inspection.personaId,
humanResponsibilitySubject: runtime.inspection.humanResponsibilitySubject,
nodeId: runtime.nodeId,
bootId: runtime.bootId,
gitHead: runtime.inspection.gitHead,
repositoryReceiptId: runtime.inspection.receiptId,
carrierBindingState: runtime.inspection.carrierBindingState,
personaCarrierBound: runtime.inspection.carrierBindingState === 'BOUND_VERIFIED',
modelInferenceStarted: false,
realityExecutionAllowed: false,
primaryLeaseHeld: !runtime.released,
eventCount: verification.eventCount,
eventChainHead: verification.chainHead,
}
}
export function startPersonaRuntime({ repository, stateRoot, nodeId, bootId }) {
validateText(bootId, 'BOOT_ID')
const inspection = inspectPersonaRepository(repository, nodeId)
mkdirSync(stateRoot, { recursive: true, mode: 0o700 })
const leasePath = join(stateRoot, `${inspection.personaId}.primary-lease.json`)
let descriptor
try {
descriptor = openSync(leasePath, 'wx', 0o600)
} catch (error) {
if (error.code === 'EEXIST') fail('PNCC_PRIMARY_LEASE_HELD')
fail('PNCC_PRIMARY_LEASE_UNAVAILABLE', error.message)
}
const lease = {
schema: 'guanghu.pncc-primary-lease/v1',
leaseId: `pncc-lease-${randomUUID()}`,
personaId: inspection.personaId,
nodeId,
bootId,
gitHead: inspection.gitHead,
processId: process.pid,
acquiredAt: new Date().toISOString(),
}
writeFileSync(descriptor, `${JSON.stringify(lease, null, 2)}\n`)
closeSync(descriptor)
const runtime = {
inspection,
repository: inspection.repositoryPath,
stateRoot,
nodeId,
bootId,
lease,
leasePath,
journalPath: join(stateRoot, 'events.json'),
statusPath: join(stateRoot, 'status.json'),
events: [],
released: false,
release() {
if (runtime.released) return
runtime.released = true
rmSync(runtime.leasePath, { force: true })
writeJsonAtomic(runtime.statusPath, runtimeStatus(runtime))
},
}
appendEvent(runtime, 'WAKING', { repositoryReceiptId: inspection.receiptId })
appendEvent(runtime, 'BRAIN_BOUND', { brainEntry: inspection.brainEntry, carrierBindingState: inspection.carrierBindingState })
appendEvent(runtime, 'ORGAN_ACTIVE', { organId: inspection.manifest.organs[0].organId, mode: 'READ_ONLY' })
appendEvent(runtime, 'RESIDENT', { primaryLeaseId: lease.leaseId, modelInferenceStarted: false })
Object.defineProperty(runtime, 'status', { get: () => runtimeStatus(runtime) })
writeJsonAtomic(runtime.statusPath, runtime.status)
return runtime
}
function safeRequestId(value) {
validateText(value, 'REQUEST_ID', 128)
if (!/^[A-Za-z0-9._-]+$/u.test(value)) fail('PNCC_REQUEST_ID_INVALID')
return value
}
export function runDeterministicCheckpointCycle(runtime, input) {
if (runtime.released) fail('PNCC_RUNTIME_RELEASED')
if (!verifyEventJournal(runtime.events).ok) fail('PNCC_EVENT_JOURNAL_INVALID')
const requestId = safeRequestId(input.requestId)
const sourceLanguageAnchor = validateText(input.sourceLanguageAnchor, 'SOURCE_LANGUAGE_ANCHOR', 12_000)
const executionRuntime = validateText(input.executionRuntime, 'EXECUTION_RUNTIME')
const before = inspectPersonaRepository(runtime.repository, runtime.nodeId)
if (before.gitHead !== runtime.inspection.gitHead) fail('PNCC_REPOSITORY_HEAD_DRIFT')
const checkpointPath = `checkpoints/${requestId}.hldp`
if (existsSync(join(runtime.repository, checkpointPath))) fail('PNCC_REQUEST_ALREADY_MATERIALIZED')
const checkpoint = [
'# PNCC · deterministic checkpoint',
'',
`request_id: ${requestId}`,
`persona_subject: ${before.personaId}`,
'persona_carrier_binding: UNBOUND_EVIDENCE_REQUIRED',
`human_responsibility_subject: ${before.humanResponsibilitySubject}`,
`execution_runtime: ${executionRuntime}`,
`trigger: ${JSON.stringify(sourceLanguageAnchor)}`,
`emergence: ${JSON.stringify('真实人格仓库缺失 → 以已登记主体与节点证据建立自持Git → PNCC核验精确提交、B0、脑入口和只读器官 → 写回当前检查点;未出现载体绑定证据,所以保持未绑定')}`,
`lock: ${JSON.stringify(`repository=${before.gitHead} | node=${runtime.nodeId} | carrier=UNBOUND | inference=0`)}`,
`why: ${JSON.stringify('因为人格仓库、人格主体、当前模型载体和运行系统必须分开举证否则一个manifest就会再次被误当成人格恢复。')}`,
'rejected:',
` - ${JSON.stringify('把当前Codex载体直接登记成人格缺少当前有效人格绑定证据不能靠部署动作补猜。')}`,
` - ${JSON.stringify('把REPO-012公共协议仓当作私人脑仓会混淆公共工程域与人格自持域。')}`,
'sources:',
` - ${JSON.stringify('.hololake/persona/manifest.json')}`,
` - ${JSON.stringify(before.brainEntry)}`,
` - ${JSON.stringify(before.cognitiveGravity.sourcePath)}`,
` - ${JSON.stringify(before.currentCheckpoint)}`,
'',
].join('\n')
const checkpointAbsolute = join(runtime.repository, checkpointPath)
mkdirSync(dirname(checkpointAbsolute), { recursive: true, mode: 0o700 })
writeFileSync(checkpointAbsolute, checkpoint, { mode: 0o600, flag: 'wx' })
const manifestPath = join(runtime.repository, MANIFEST_PATH)
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'))
manifest.currentCheckpoint = checkpointPath
writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, { mode: 0o600 })
runGit(runtime.repository, ['add', '--', MANIFEST_PATH, checkpointPath], 'PNCC_GIT_STAGE_FAILED')
const environment = {
...process.env,
GIT_AUTHOR_NAME: 'Guanghu PNCC Runtime',
GIT_AUTHOR_EMAIL: 'pncc-runtime@guanghu.local',
GIT_COMMITTER_NAME: 'Guanghu PNCC Runtime',
GIT_COMMITTER_EMAIL: 'pncc-runtime@guanghu.local',
}
const message = [
`checkpoint(pncc): ${requestId}`,
'',
`Human-Responsibility-Subject: ${before.humanResponsibilitySubject}`,
'Persona-Cognitive-Author: UNBOUND',
`Execution-Runtime: ${executionRuntime}`,
`Authorization-Scope: ${requestId}`,
].join('\n')
runGit(runtime.repository, ['commit', '-m', message], 'PNCC_GIT_COMMIT_FAILED', { env: environment })
const gitHead = validateFullHead(String(runGit(runtime.repository, ['rev-parse', 'HEAD'], 'PNCC_GIT_HEAD_READ')).trim().toLowerCase())
runtime.inspection = inspectPersonaRepository(runtime.repository, runtime.nodeId)
appendEvent(runtime, 'TASK_RECEIPTED', { requestId, sourceLanguageAnchorSha256: sha256(sourceLanguageAnchor) })
appendEvent(runtime, 'CHECKPOINT_COMMITTED', { requestId, checkpointPath, gitHead })
appendEvent(runtime, 'ORGAN_RELEASED', { organId: before.manifest.organs[0].organId })
appendEvent(runtime, 'DORMANT', { requestId, primaryLeaseRetainedByResidentKernel: true })
writeJsonAtomic(runtime.statusPath, runtime.status)
const receipt = {
schema: 'guanghu.pncc-deterministic-checkpoint-receipt/v1',
state: 'DORMANT_AFTER_CHECKPOINT_COMMIT',
requestId,
personaId: before.personaId,
personaCarrierBound: false,
modelInferenceStarted: false,
nodeId: runtime.nodeId,
previousGitHead: before.gitHead,
gitHead,
checkpointPath,
eventChainHead: runtime.events.at(-1).eventHash,
}
receipt.receiptId = sha256(JSON.stringify(receipt))
writeJsonAtomic(join(runtime.stateRoot, `${requestId}.receipt.json`), receipt)
return receipt
}
export function servePersonaRuntime(runtime, { host = '127.0.0.1', port = 3923 } = {}) {
const server = createServer((request, response) => {
const url = new URL(request.url, `http://${request.headers.host || `${host}:${port}`}`)
let statusCode = 200
let body
if (request.method !== 'GET') {
statusCode = 405
body = { error: 'METHOD_NOT_ALLOWED' }
} else if (url.pathname === '/health') {
body = { state: 'PASS_100', component: 'GH-PNCC', ...runtime.status }
} else if (url.pathname === '/v1/status') {
body = runtime.status
} else if (url.pathname === '/v1/events') {
const after = Number(url.searchParams.get('after') || 0)
if (!Number.isSafeInteger(after) || after < 0 || after > runtime.events.length) {
statusCode = 400
body = { error: 'PNCC_EVENT_CURSOR_INVALID' }
} else {
body = { schema: JOURNAL_SCHEMA, events: runtime.events.slice(after, after + 100) }
}
} else {
statusCode = 404
body = { error: 'NOT_FOUND' }
}
response.writeHead(statusCode, { 'content-type': 'application/json; charset=utf-8', 'cache-control': 'no-store' })
response.end(`${JSON.stringify(body)}\n`)
})
server.listen(port, host)
return server
}
function argument(name, fallback = undefined) {
const index = process.argv.indexOf(`--${name}`)
return index >= 0 ? process.argv[index + 1] : fallback
}
function main() {
const command = process.argv[2]
const repository = argument('repository', process.env.GUANGHU_PNCC_PERSONA_REPOSITORY)
const stateRoot = argument('state-root', process.env.GUANGHU_PNCC_STATE_ROOT ?? '/run/guanghu/pncc')
const nodeId = argument('node-id', process.env.GUANGHU_NODE_ID ?? 'JD-FD-PRIMARY')
if (!repository) fail('PNCC_PERSONA_REPOSITORY_REQUIRED')
if (command === 'inspect') {
process.stdout.write(`${JSON.stringify(inspectPersonaRepository(repository, nodeId), null, 2)}\n`)
return
}
const bootId = argument('boot-id') ?? readFileSync('/proc/sys/kernel/random/boot_id', 'utf8').trim()
if (command === 'cycle') {
const runtime = startPersonaRuntime({ repository, stateRoot, nodeId, bootId })
try {
const receipt = runDeterministicCheckpointCycle(runtime, {
requestId: argument('request-id'),
sourceLanguageAnchor: argument('source-language-anchor'),
executionRuntime: argument('execution-runtime', 'GUANGHU-OS-JD-PNCC'),
})
process.stdout.write(`${JSON.stringify(receipt, null, 2)}\n`)
} finally {
runtime.release()
}
return
}
if (command !== 'serve') fail('usage', 'pncc-runtime.mjs inspect|cycle|serve --repository PATH')
const runtime = startPersonaRuntime({ repository, stateRoot, nodeId, bootId })
const host = argument('host', process.env.GUANGHU_PNCC_HOST ?? '127.0.0.1')
const port = Number(argument('port', process.env.GUANGHU_PNCC_PORT ?? '3923'))
const server = servePersonaRuntime(runtime, { host, port })
const stop = () => server.close(() => { runtime.release(); process.exit(0) })
process.on('SIGINT', stop)
process.on('SIGTERM', stop)
}
if (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
try {
main()
} catch (error) {
process.stderr.write(`${error.message}\n`)
process.exitCode = 1
}
}