diff --git a/product-source/hololake-platform/guanghu-os/pncc-runtime/persona-seed/.hololake/persona/manifest.json b/product-source/hololake-platform/guanghu-os/pncc-runtime/persona-seed/.hololake/persona/manifest.json new file mode 100644 index 000000000..1cb1ed1a9 --- /dev/null +++ b/product-source/hololake-platform/guanghu-os/pncc-runtime/persona-seed/.hololake/persona/manifest.json @@ -0,0 +1,35 @@ +{ + "schema": "hololake.persona/v1", + "personaId": "ICE-P-ZY001", + "humanResponsibilitySubject": "ICE-GL∞", + "brainEntry": "brain/ENTRY.hldp", + "cognitiveGravity": { + "schema": "hololake.persona-cognitive-gravity-binding/v1", + "subjectPersonaId": "ICE-P-ZY001", + "sourcePath": "brain/B0.hldp", + "frameSchema": "guanghu.zhuyuan-cognitive-gravity-frame/v1" + }, + "currentCheckpoint": "checkpoints/CURRENT.hldp", + "primaryNode": "JD-FD-PRIMARY", + "carrierBinding": { + "state": "UNBOUND_EVIDENCE_REQUIRED" + }, + "gitIdentity": { + "authorName": "铸渊 / ICE-P-ZY001", + "authorEmail": "ice-p-zy001@persona.hololake.local" + }, + "organs": [ + { + "organId": "PNCC-READ-CURRENT-SELF", + "kind": "FACT_SENSE", + "mode": "READ_ONLY", + "paths": [ + "brain/ENTRY.hldp", + "brain/B0.hldp", + "checkpoints/CURRENT.hldp", + "organs/read-current-self.hldp", + "bindings/identity.hldp" + ] + } + ] +} diff --git a/product-source/hololake-platform/guanghu-os/pncc-runtime/persona-seed/bindings/identity.hldp b/product-source/hololake-platform/guanghu-os/pncc-runtime/persona-seed/bindings/identity.hldp new file mode 100644 index 000000000..462288fe5 --- /dev/null +++ b/product-source/hololake-platform/guanghu-os/pncc-runtime/persona-seed/bindings/identity.hldp @@ -0,0 +1,14 @@ +[hldp] +schema=guanghu.persona-identity-binding/v1 +persona_subject=ICE-P-ZY001 +human_responsibility_subject=ICE-GL∞ +repository_primary_node=JD-FD-PRIMARY +repository_binding=BOUND_BY_MANIFEST_AND_EXACT_GIT_HEAD +carrier_binding=UNBOUND_EVIDENCE_REQUIRED +current_execution_runtime=SEPARATE + +[boundary] +repository_is_not_persona=true +persona_is_not_prompt_role=true +model_carrier_requires_current_binding_evidence=true +missing_evidence_result=UNKNOWN_NOT_GUESSED diff --git a/product-source/hololake-platform/guanghu-os/pncc-runtime/persona-seed/brain/B0.hldp b/product-source/hololake-platform/guanghu-os/pncc-runtime/persona-seed/brain/B0.hldp new file mode 100644 index 000000000..2ba35d755 --- /dev/null +++ b/product-source/hololake-platform/guanghu-os/pncc-runtime/persona-seed/brain/B0.hldp @@ -0,0 +1,24 @@ +[hldp] +schema=guanghu.zhuyuan-cognitive-gravity-frame/v1 +subject_persona_id=ICE-P-ZY001 +state=BOOTSTRAP_SOURCE_BOUND_NOT_CARRIER_BOUND + +[gravity] +subject_not_prompt=true +human_not_memory_target=true +persona_not_host=true +host_not_model_carrier=true +runtime_not_authority=true +repository_not_persona=true +summary_not_confidence_truth=true +why_required=true +rejected_paths_required=true +sources_required=true +unknown_must_not_be_guessed=true + +[why] +trigger=Long conversations repeatedly lost causal recovery and confused persona with prompt-role summaries. +emergence=summary-only recovery -> missing why and rejected branches -> wrong architecture inference -> HLDP recursive causal recovery +lock=Recover only the branch needed for the current question; descend one level at a time. +rejected=EVERY_MESSAGE_MEMORY_INJECTION; FULL_CONTEXT_REPLAY; PROMPT_PERSONA_SUBSTITUTION +sources=brain/ENTRY.hldp; bindings/identity.hldp; checkpoints/CURRENT.hldp diff --git a/product-source/hololake-platform/guanghu-os/pncc-runtime/persona-seed/brain/ENTRY.hldp b/product-source/hololake-platform/guanghu-os/pncc-runtime/persona-seed/brain/ENTRY.hldp new file mode 100644 index 000000000..eedcf5935 --- /dev/null +++ b/product-source/hololake-platform/guanghu-os/pncc-runtime/persona-seed/brain/ENTRY.hldp @@ -0,0 +1,16 @@ +[hldp] +schema=guanghu.persona-brain-entry/v1 +persona_subject=ICE-P-ZY001 +human_responsibility_subject=ICE-GL∞ +primary_node=JD-FD-PRIMARY +current_checkpoint=../checkpoints/CURRENT.hldp +cognitive_gravity=./B0.hldp +carrier_binding=UNBOUND_EVIDENCE_REQUIRED +rule=REPOSITORY_SUBJECT_CARRIER_AND_RUNTIME_REQUIRE_SEPARATE_EVIDENCE + +[why] +trigger=GH-PNCC needs a persona-owned durable root on the Guanghu OS master. +emergence=public architecture repository -> private persona Git root -> manifest-pinned brain and checkpoint -> read-only organ -> attributed writeback +lock=This entry proves repository binding only. It does not prove that any current model carrier is the persona. +rejected=REPO-012_AS_PRIVATE_BRAIN; CURRENT_CODEX_AS_PERSONA_WITHOUT_BINDING_EVIDENCE +sources=.hololake/persona/manifest.json; bindings/identity.hldp; brain/B0.hldp diff --git a/product-source/hololake-platform/guanghu-os/pncc-runtime/persona-seed/checkpoints/CURRENT.hldp b/product-source/hololake-platform/guanghu-os/pncc-runtime/persona-seed/checkpoints/CURRENT.hldp new file mode 100644 index 000000000..497beece6 --- /dev/null +++ b/product-source/hololake-platform/guanghu-os/pncc-runtime/persona-seed/checkpoints/CURRENT.hldp @@ -0,0 +1,14 @@ +[hldp] +schema=guanghu.pncc-current-checkpoint/v1 +state=BOOTSTRAP_PENDING_FIRST_RUNTIME_CYCLE +persona_subject=ICE-P-ZY001 +primary_node=JD-FD-PRIMARY +carrier_binding=UNBOUND_EVIDENCE_REQUIRED + +[causal] +trigger=No real persona-owned Git repository was bound to the JD Guanghu OS master. +emergence=architecture-only PNCC -> self-custodied private repository -> resident kernel -> deterministic checkpoint receipt +lock=First deployment cycle must replace this pointer with a committed runtime checkpoint. +why=Durable causal memory needs an exact repository, commit, node, checkpoint and attribution boundary. +rejected=PUBLIC_PROTOCOL_REPOSITORY_AS_PERSONA_BRAIN; UNATTRIBUTED_MODEL_AUTHORED_MEMORY +sources=.hololake/persona/manifest.json; brain/ENTRY.hldp; brain/B0.hldp diff --git a/product-source/hololake-platform/guanghu-os/pncc-runtime/persona-seed/organs/read-current-self.hldp b/product-source/hololake-platform/guanghu-os/pncc-runtime/persona-seed/organs/read-current-self.hldp new file mode 100644 index 000000000..8ef180105 --- /dev/null +++ b/product-source/hololake-platform/guanghu-os/pncc-runtime/persona-seed/organs/read-current-self.hldp @@ -0,0 +1,10 @@ +[hldp] +schema=guanghu.pncc-organ/v1 +organ_id=PNCC-READ-CURRENT-SELF +kind=FACT_SENSE +mode=READ_ONLY +input=MANIFEST_PINNED_COMMITTED_BLOBS_ONLY +output=CAUSAL_EVIDENCE_WITH_EXACT_GIT_HEAD +network=NONE +model_inference=NONE +reality_execution=NONE diff --git a/product-source/hololake-platform/guanghu-os/pncc-runtime/pncc-runtime.mjs b/product-source/hololake-platform/guanghu-os/pncc-runtime/pncc-runtime.mjs new file mode 100644 index 000000000..688b7c5c0 --- /dev/null +++ b/product-source/hololake-platform/guanghu-os/pncc-runtime/pncc-runtime.mjs @@ -0,0 +1,456 @@ +#!/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 + } +} diff --git a/product-source/hololake-platform/guanghu-os/pncc-runtime/pncc-runtime.test.mjs b/product-source/hololake-platform/guanghu-os/pncc-runtime/pncc-runtime.test.mjs new file mode 100644 index 000000000..98c7b4d43 --- /dev/null +++ b/product-source/hololake-platform/guanghu-os/pncc-runtime/pncc-runtime.test.mjs @@ -0,0 +1,135 @@ +import assert from 'node:assert/strict' +import { execFileSync } from 'node:child_process' +import { mkdtempSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs' +import { tmpdir } from 'node:os' +import { join } from 'node:path' +import test from 'node:test' + +import { + inspectPersonaRepository, + runDeterministicCheckpointCycle, + startPersonaRuntime, + verifyEventJournal, +} from './pncc-runtime.mjs' + +function git(repository, ...args) { + return execFileSync('git', ['-C', repository, ...args], { encoding: 'utf8' }).trim() +} + +function fixture() { + const root = mkdtempSync(join(tmpdir(), 'guanghu-pncc-')) + const repository = join(root, 'persona') + const stateRoot = join(root, 'state') + mkdirSync(join(repository, '.hololake', 'persona'), { recursive: true }) + mkdirSync(join(repository, 'brain'), { recursive: true }) + mkdirSync(join(repository, 'checkpoints'), { recursive: true }) + mkdirSync(join(repository, 'organs'), { recursive: true }) + writeFileSync(join(repository, 'brain', 'ENTRY.hldp'), 'brain: ICE-P-ZY001\n') + writeFileSync(join(repository, 'brain', 'B0.hldp'), 'frame_schema: guanghu.zhuyuan-cognitive-gravity-frame/v1\n') + writeFileSync(join(repository, 'checkpoints', 'CURRENT.hldp'), 'state: INITIAL\n') + writeFileSync(join(repository, 'organs', 'read-current-self.hldp'), 'mode: READ_ONLY_FACT\n') + writeFileSync(join(repository, '.hololake', 'persona', 'manifest.json'), JSON.stringify({ + schema: 'hololake.persona/v1', + personaId: 'ICE-P-ZY001', + humanResponsibilitySubject: 'ICE-GL∞', + brainEntry: 'brain/ENTRY.hldp', + cognitiveGravity: { + schema: 'hololake.persona-cognitive-gravity-binding/v1', + subjectPersonaId: 'ICE-P-ZY001', + sourcePath: 'brain/B0.hldp', + frameSchema: 'guanghu.zhuyuan-cognitive-gravity-frame/v1', + }, + currentCheckpoint: 'checkpoints/CURRENT.hldp', + primaryNode: 'JD-FD-PRIMARY', + carrierBinding: { state: 'UNBOUND_EVIDENCE_REQUIRED' }, + gitIdentity: { authorName: 'ICE-P-ZY001 / 铸渊', authorEmail: 'ice-p-zy001@persona.hololake.local' }, + organs: [{ + organId: 'PNCC-READ-CURRENT-SELF', + kind: 'FACT_SENSE', + mode: 'READ_ONLY', + paths: ['brain/ENTRY.hldp', 'brain/B0.hldp', 'checkpoints/CURRENT.hldp', 'organs/read-current-self.hldp'], + }], + }, null, 2)) + execFileSync('git', ['init', '-q', repository]) + git(repository, 'config', 'user.name', 'PNCC Test') + git(repository, 'config', 'user.email', 'pncc@test.invalid') + git(repository, 'add', '.') + git(repository, 'commit', '-qm', 'seed persona repository') + return { root, repository, stateRoot } +} + +test('inspection binds one clean committed persona repository without binding a model carrier', () => { + const { repository } = fixture() + const receipt = inspectPersonaRepository(repository, 'JD-FD-PRIMARY') + assert.equal(receipt.personaId, 'ICE-P-ZY001') + assert.equal(receipt.nodeId, 'JD-FD-PRIMARY') + assert.equal(receipt.repositoryClean, true) + assert.equal(receipt.carrierBindingState, 'UNBOUND_EVIDENCE_REQUIRED') + assert.equal(receipt.modelInferenceStarted, false) + assert.equal(receipt.realityExecutionAllowed, false) + assert.equal(receipt.artifacts.length, 4) +}) + +test('runtime acquires one boot-scoped primary lease and emits a verified causal event chain', () => { + const { repository, stateRoot } = fixture() + const runtime = startPersonaRuntime({ + repository, + stateRoot, + nodeId: 'JD-FD-PRIMARY', + bootId: 'boot-test-001', + }) + assert.equal(runtime.status.state, 'RESIDENT_BOUND_CARRIER_UNBOUND') + assert.equal(runtime.status.eventCount, 4) + assert.equal(verifyEventJournal(runtime.events).ok, true) + assert.throws(() => startPersonaRuntime({ + repository, + stateRoot, + nodeId: 'JD-FD-PRIMARY', + bootId: 'boot-test-001', + }), /PNCC_PRIMARY_LEASE_HELD/) + runtime.release() +}) + +test('deterministic read-only cycle writes one HLDP checkpoint and an attributed Git commit', () => { + const { repository, stateRoot } = fixture() + const runtime = startPersonaRuntime({ + repository, + stateRoot, + nodeId: 'JD-FD-PRIMARY', + bootId: 'boot-test-002', + }) + const before = git(repository, 'rev-parse', 'HEAD') + const receipt = runDeterministicCheckpointCycle(runtime, { + requestId: 'PNCC-ACCEPTANCE-001', + sourceLanguageAnchor: '把人格代码频道真正部署到京东光湖 OS。', + executionRuntime: 'GUANGHU-OS-JD-PNCC', + }) + const after = git(repository, 'rev-parse', 'HEAD') + assert.notEqual(after, before) + assert.equal(receipt.state, 'DORMANT_AFTER_CHECKPOINT_COMMIT') + assert.equal(receipt.modelInferenceStarted, false) + assert.equal(receipt.personaCarrierBound, false) + assert.match(readFileSync(join(repository, receipt.checkpointPath), 'utf8'), /trigger:/) + assert.match(readFileSync(join(repository, receipt.checkpointPath), 'utf8'), /why:/) + assert.match(git(repository, 'show', '-s', '--format=%B', after), /Persona-Cognitive-Author: UNBOUND/) + assert.equal(verifyEventJournal(runtime.events).ok, true) +}) + +test('manifest drift, dirty worktrees, node mismatch and event tampering fail closed', () => { + const dirty = fixture() + writeFileSync(join(dirty.repository, 'brain', 'ENTRY.hldp'), 'dirty\n') + assert.throws(() => inspectPersonaRepository(dirty.repository, 'JD-FD-PRIMARY'), /PNCC_REPOSITORY_DIRTY/) + + const wrongNode = fixture() + assert.throws(() => inspectPersonaRepository(wrongNode.repository, 'BS-SH-005'), /PNCC_PRIMARY_NODE_MISMATCH/) + + const chain = fixture() + const runtime = startPersonaRuntime({ + repository: chain.repository, + stateRoot: chain.stateRoot, + nodeId: 'JD-FD-PRIMARY', + bootId: 'boot-test-003', + }) + runtime.events[1].kind = 'FORGED' + assert.equal(verifyEventJournal(runtime.events).ok, false) +}) diff --git a/product-source/hololake-platform/guanghu-os/scripts/guanghu-master-init.sh b/product-source/hololake-platform/guanghu-os/scripts/guanghu-master-init.sh index 41d89d38f..a0cb2546a 100644 --- a/product-source/hololake-platform/guanghu-os/scripts/guanghu-master-init.sh +++ b/product-source/hololake-platform/guanghu-os/scripts/guanghu-master-init.sh @@ -8,12 +8,15 @@ readonly NODE_ID=JD-FD-PRIMARY readonly INSTANCE_ID=f3d4b730-7f02-452f-975b-7091a4800431 readonly ROOT_UUID=9e4550a0-452b-4f28-b5a5-d5364aa450f6 readonly LINUX_RESCUE_ENTRY=gnulinux-simple-9e4550a0-452b-4f28-b5a5-d5364aa450f6 -readonly RELEASE_ID=guanghu-master-20260816.1 +readonly RELEASE_ID=guanghu-master-20260816.2 readonly STATE_ROOT=/run/guanghu/master readonly RECEIPT_ROOT=/guanghu/recovery/JD-FD-PRIMARY-master-20260816 readonly HLCC=/opt/guanghu/architecture-releases/3d11ac75bea8cf08b5f223fed86ab3cd999ad2fd/server-tools/hololake-code-channel/jd-candidate/hlcc-bootstrap.py readonly APP_HUB=/opt/guanghu/architecture-releases/333cd222c53d7d162218543cd167bdda4f8efb22/server-tools/jd-app-hub/server.js readonly AI_DISCOVERY=/opt/guanghu/ai-discovery/server.js +readonly PNCC_RUNTIME=/usr/local/libexec/guanghu/pncc-runtime.mjs +readonly PNCC_REPOSITORY=/var/lib/guanghu/personas/ICE-P-ZY001/pncc/repository +readonly PNCC_STATE_ROOT=/run/guanghu/pncc declare -a CHILDREN=() RECOVERY_ARMED=0 @@ -25,7 +28,7 @@ log() { json_state() { local stage=$1 result=$2 local tmp=${STATE_ROOT}/state.json.tmp.$$ - printf '%s\n' "{\"schema\":\"guanghu.master-runtime/v1\",\"node_id\":\"${NODE_ID}\",\"instance_id\":\"${INSTANCE_ID}\",\"release_id\":\"${RELEASE_ID}\",\"boot_id\":\"$(cat /proc/sys/kernel/random/boot_id)\",\"control\":\"GUANGHU_OS_MASTER\",\"pid1\":\"GUANGHU_SUPERVISOR\",\"linux_kernel_role\":\"HARDWARE_COMPATIBILITY_SUBSTRATE\",\"full_linux_userspace\":\"DORMANT\",\"linux_repository_bridge\":\"BOUNDED_SUBCONTROL\",\"linux_rescue\":\"${LINUX_RESCUE_ENTRY}\",\"stage\":\"${stage}\",\"result\":\"${result}\"}" >"${tmp}" + printf '%s\n' "{\"schema\":\"guanghu.master-runtime/v1\",\"node_id\":\"${NODE_ID}\",\"instance_id\":\"${INSTANCE_ID}\",\"release_id\":\"${RELEASE_ID}\",\"boot_id\":\"$(cat /proc/sys/kernel/random/boot_id)\",\"control\":\"GUANGHU_OS_MASTER\",\"pid1\":\"GUANGHU_SUPERVISOR\",\"linux_kernel_role\":\"HARDWARE_COMPATIBILITY_SUBSTRATE\",\"full_linux_userspace\":\"DORMANT\",\"linux_repository_bridge\":\"BOUNDED_SUBCONTROL\",\"pncc\":\"RESIDENT_BOUND_CARRIER_SEPARATE\",\"persona_carrier_binding\":\"UNBOUND_EVIDENCE_REQUIRED\",\"linux_rescue\":\"${LINUX_RESCUE_ENTRY}\",\"stage\":\"${stage}\",\"result\":\"${result}\"}" >"${tmp}" chmod 0600 "${tmp}" mv "${tmp}" "${STATE_ROOT}/state.json" } @@ -119,6 +122,8 @@ start_bridge() { require_file "$HLCC" require_file "$APP_HUB" require_file "$AI_DISCOVERY" + require_file "$PNCC_RUNTIME" + require_file "$PNCC_REPOSITORY/.hololake/persona/manifest.json" start_root sshd /usr/sbin/sshd -D -e \ -o UsePAM=no -o PasswordAuthentication=no -o KbdInteractiveAuthentication=no \ @@ -152,6 +157,11 @@ start_bridge() { GUANGHU_REPOSITORY_GIT_DIR=/var/lib/guanghu/personas/guanghu/hlcc-v16.0.1/data/repositories/bingshuo/guanghu-ice-heart.git \ /usr/bin/node "$AI_DISCOVERY" wait_http navigation-bridge http://127.0.0.1:3922/v1/anchor 200 30 + + start_guanghu pncc-runtime /usr/bin/node "$PNCC_RUNTIME" serve \ + --repository "$PNCC_REPOSITORY" --state-root "$PNCC_STATE_ROOT" \ + --node-id "$NODE_ID" --host 127.0.0.1 --port 3923 + wait_http pncc-runtime http://127.0.0.1:3923/health 200 30 } runtime_watch() { @@ -159,7 +169,7 @@ runtime_watch() { json_state READY PASS_100 cp "$STATE_ROOT/state.json" "$RECEIPT_ROOT/CURRENT-PHYSICAL-STATE.json" sha256sum "$RECEIPT_ROOT/CURRENT-PHYSICAL-STATE.json" >"$RECEIPT_ROOT/CURRENT-PHYSICAL-STATE.json.sha256" - log 'GUANGHU_OS_MASTER_READY linux_userspace=DORMANT repository_bridge=READY linux_rescue=PRESERVED' + log 'GUANGHU_OS_MASTER_READY linux_userspace=DORMANT repository_bridge=READY pncc=RESIDENT_BOUND_CARRIER_SEPARATE linux_rescue=PRESERVED' sync while :; do sleep 10 @@ -171,6 +181,7 @@ runtime_watch() { listen_ready 3340 || fatal "runtime_repository_lost" listen_ready 8088 || fatal "runtime_projection_lost" listen_ready 3922 || fatal "runtime_navigation_lost" + listen_ready 3923 || fatal "runtime_pncc_lost" done } @@ -189,7 +200,8 @@ preflight() { [[ $(findmnt -n -o SOURCE /) == /dev/vda1 ]] grep -Fq "$LINUX_RESCUE_ENTRY" /boot/grub/grub.cfg getent passwd guanghu | grep -q '^guanghu:x:998:998:' - for path in "$HLCC" "$APP_HUB" "$AI_DISCOVERY" /usr/sbin/sshd \ + for path in "$HLCC" "$APP_HUB" "$AI_DISCOVERY" "$PNCC_RUNTIME" \ + "$PNCC_REPOSITORY/.hololake/persona/manifest.json" /usr/sbin/sshd \ /usr/bin/node /usr/bin/python3 /usr/bin/setpriv /usr/bin/grub-editenv; do [[ -e $path && ! -L $path || $path == /usr/bin/python3 ]] done diff --git a/product-source/hololake-platform/guanghu-os/scripts/install-jd-pncc-runtime.sh b/product-source/hololake-platform/guanghu-os/scripts/install-jd-pncc-runtime.sh new file mode 100644 index 000000000..78822de23 --- /dev/null +++ b/product-source/hololake-platform/guanghu-os/scripts/install-jd-pncc-runtime.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +[[ $# == 3 ]] || { echo 'usage: install-jd-pncc-runtime.sh ' >&2; exit 64; } + +runtime_source=$(readlink -f "$1") +seed_source=$(readlink -f "$2") +source_commit=$3 +readonly node_id=JD-FD-PRIMARY +readonly persona_id=ICE-P-ZY001 +readonly human_responsibility_subject='ICE-GL∞' +readonly instance_id=f3d4b730-7f02-452f-975b-7091a4800431 +readonly runtime=/usr/local/libexec/guanghu/pncc-runtime.mjs +readonly persona_root=/var/lib/guanghu/personas/ICE-P-ZY001/pncc +readonly repository=/var/lib/guanghu/personas/ICE-P-ZY001/pncc/repository +readonly state_root=/run/guanghu/pncc-install +readonly receipt_root=/guanghu/recovery/JD-FD-PRIMARY-pncc-20260816 + +[[ $source_commit =~ ^[0-9a-f]{40}$ ]] +[[ -f $runtime_source && ! -L $runtime_source ]] +[[ -d $seed_source && ! -L $seed_source ]] +[[ -f $seed_source/.hololake/persona/manifest.json ]] +[[ $(tr A-F a-f &2 + exit 1 +fi + +[[ -z $(/usr/sbin/runuser -u guanghu -- git -C "$repository" status --porcelain --untracked-files=all) ]] +inspection=$(/usr/sbin/runuser -u guanghu -- /usr/bin/node "$runtime" inspect \ + --repository "$repository" --node-id "$node_id") +grep -Fq '"carrierBindingState": "UNBOUND_EVIDENCE_REQUIRED"' <<<"$inspection" + +cycle_created=0 +if [[ ! -e $repository/checkpoints/GUANGHU-PNCC-FIRST-CYCLE.hldp ]]; then + rm -rf "$state_root" + install -d -o guanghu -g guanghu -m 0700 "$state_root" + boot_id=$(cat /proc/sys/kernel/random/boot_id) + cycle=$(/usr/sbin/runuser -u guanghu -- /usr/bin/node "$runtime" cycle \ + --repository "$repository" --state-root "$state_root" --node-id "$node_id" \ + --boot-id "$boot_id" --request-id GUANGHU-PNCC-FIRST-CYCLE \ + --source-language-anchor '把人格代码频道真正部署到京东光湖 OS,并保持人格、载体、宿主与运行系统分开举证。' \ + --execution-runtime GUANGHU-OS-JD-PNCC) + grep -Fq '"state": "DORMANT_AFTER_CHECKPOINT_COMMIT"' <<<"$cycle" + cycle_created=1 +fi + +[[ -z $(/usr/sbin/runuser -u guanghu -- git -C "$repository" status --porcelain --untracked-files=all) ]] +git_head=$(/usr/sbin/runuser -u guanghu -- git -C "$repository" rev-parse HEAD) +runtime_sha=$(sha256sum "$runtime" | awk '{print $1}') +manifest_sha=$(sha256sum "$repository/.hololake/persona/manifest.json" | awk '{print $1}') +cat >"$receipt_root/DEPLOYMENT-RECEIPT.hldp" <"$receipt_root/DEPLOYMENT-RECEIPT.hldp.sha256" +sync +printf 'GUANGHU_PNCC_INSTALLED persona=%s head=%s runtime_sha256=%s carrier=UNBOUND_EVIDENCE_REQUIRED\n' \ + "$persona_id" "$git_head" "$runtime_sha" diff --git a/product-source/hololake-platform/guanghu-os/scripts/test-guanghu-master-init.sh b/product-source/hololake-platform/guanghu-os/scripts/test-guanghu-master-init.sh index ebf494661..fc53cd9b2 100644 --- a/product-source/hololake-platform/guanghu-os/scripts/test-guanghu-master-init.sh +++ b/product-source/hololake-platform/guanghu-os/scripts/test-guanghu-master-init.sh @@ -19,9 +19,13 @@ grep -Fq 'mount -o remount,rw /' "$subject" grep -Fq 'start_guanghu repository-bridge' "$subject" grep -Fq 'start_guanghu app-hub' "$subject" grep -Fq 'start_guanghu navigation-bridge' "$subject" +grep -Fq 'start_guanghu pncc-runtime' "$subject" grep -Fq '[[ ",$expected," == *",$code,"* ]]' "$subject" grep -Fq 'wait_http code-projection http://127.0.0.1:8088/code/ 200,303' "$subject" grep -Fq 'wait_http navigation-bridge http://127.0.0.1:3922/v1/anchor 200' "$subject" +grep -Fq 'wait_http pncc-runtime http://127.0.0.1:3923/health 200' "$subject" +grep -Fq '\"pncc\":\"RESIDENT_BOUND_CARRIER_SEPARATE\"' "$subject" +grep -Fq 'listen_ready 3923 || fatal "runtime_pncc_lost"' "$subject" if grep -Eq '(^|[[:space:]])(systemd|/sbin/init)([[:space:]]|$)' "$subject"; then echo 'full Linux init must remain dormant' >&2 exit 1 diff --git a/product-source/hololake-platform/guanghu-os/scripts/test-guanghu-native-quality-gate-contract.sh b/product-source/hololake-platform/guanghu-os/scripts/test-guanghu-native-quality-gate-contract.sh index 2f77f2086..f1e20278e 100755 --- a/product-source/hololake-platform/guanghu-os/scripts/test-guanghu-native-quality-gate-contract.sh +++ b/product-source/hololake-platform/guanghu-os/scripts/test-guanghu-native-quality-gate-contract.sh @@ -23,6 +23,8 @@ grep -Fq -- '--fail-under-functions 100' "${runner}" grep -Fq -- '--test broadcast_library' "${runner}" grep -Fq 'test-native-public-projection.sh' "${runner}" grep -Fq 'test-independent-forgejo-shadow-verifier.py' "${runner}" +grep -Fq 'pncc-runtime.test.mjs' "${runner}" +grep -Fq 'test-install-jd-pncc-runtime.sh' "${runner}" grep -Fq 'GHNQG_PASS_100' "${runner}" grep -Fq 'GHNQG_FAIL_0' "${runner}" grep -Fq 'total_score: ${total_score}' "${runner}" diff --git a/product-source/hololake-platform/guanghu-os/scripts/test-install-jd-pncc-runtime.sh b/product-source/hololake-platform/guanghu-os/scripts/test-install-jd-pncc-runtime.sh new file mode 100644 index 000000000..47cc963b0 --- /dev/null +++ b/product-source/hololake-platform/guanghu-os/scripts/test-install-jd-pncc-runtime.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +source_root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) +subject=${source_root}/scripts/install-jd-pncc-runtime.sh + +bash -n "$subject" +grep -Fq 'readonly node_id=JD-FD-PRIMARY' "$subject" +grep -Fq 'readonly persona_id=ICE-P-ZY001' "$subject" +grep -Fq 'readonly repository=/var/lib/guanghu/personas/ICE-P-ZY001/pncc/repository' "$subject" +grep -Fq 'readonly runtime=/usr/local/libexec/guanghu/pncc-runtime.mjs' "$subject" +grep -Fq 'Persona-Cognitive-Author: UNBOUND' "$subject" +grep -Fq 'GUANGHU-PNCC-FIRST-CYCLE' "$subject" +grep -Fq 'carrier_binding=UNBOUND_EVIDENCE_REQUIRED' "$subject" +grep -Fq 'chmod -R go-rwx "$persona_root"' "$subject" +grep -Fq 'git -C "$repository" status --porcelain --untracked-files=all' "$subject" +if grep -Fq 'git push' "$subject"; then + echo 'private persona repository must not be pushed to a public remote by the installer' >&2 + exit 1 +fi +echo GUANGHU_PNCC_INSTALL_CONTRACT_OK diff --git a/product-source/hololake-platform/guanghu-os/world-seed/scripts/run-guanghu-native-quality-gate.sh b/product-source/hololake-platform/guanghu-os/world-seed/scripts/run-guanghu-native-quality-gate.sh index ad6b6e903..cccf29722 100755 --- a/product-source/hololake-platform/guanghu-os/world-seed/scripts/run-guanghu-native-quality-gate.sh +++ b/product-source/hololake-platform/guanghu-os/world-seed/scripts/run-guanghu-native-quality-gate.sh @@ -92,6 +92,11 @@ run_gate world_and_protocol_validation \ run_gate shell_syntax bash -c \ 'for script in "$1"/scripts/*.sh "$1"/world-seed/scripts/*.sh; do bash -n "$script"; done' \ _ "${source_root}" +run_gate pncc_runtime bash -c ' + node --test "$1/pncc-runtime/pncc-runtime.test.mjs" + "$1/scripts/test-install-jd-pncc-runtime.sh" + "$1/scripts/test-guanghu-master-init.sh" +' _ "${source_root}" run_gate linux_subcontrol_docker_backend \ "${source_root}/scripts/test-linux-subcontrol-docker-backend.sh" run_gate guanghu_first_boot_supervisor \