-
Notifications
You must be signed in to change notification settings - Fork 0
proof: implement local governed execution proof path #70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| <!-- SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. --> | ||
| <!-- SPDX-License-Identifier: Apache-2.0 --> | ||
|
|
||
| # Local Governed Proof (Deterministic) | ||
|
|
||
| Run a real local governed execution proof path: | ||
|
|
||
| ```bash | ||
| npm run demo:local-proof | ||
| ``` | ||
|
|
||
| Artifacts are written to `.artifacts/local-governed-proof/` and include: | ||
|
|
||
| - `manifest.json` (node registration, probe, intent, plan, queue, lease, execution, receipt, replay) | ||
| - `proofpack.json` (stable proofpack hash and replay linkage) | ||
| - `operator/*.json` (operator inspection topics) | ||
|
|
||
| Inspect with operator CLI: | ||
|
|
||
| ```bash | ||
| nemoclaw operator status --source .artifacts/local-governed-proof | ||
| nemoclaw operator diagnostics --source .artifacts/local-governed-proof | ||
| nemoclaw operator proofpack --source .artifacts/local-governed-proof --json | ||
| ``` | ||
|
|
||
| Limitations: | ||
|
|
||
| - Local-only deterministic path (no distributed execution). | ||
| - No external network or remote workers required. | ||
| - GPU telemetry explicitly reports unavailable when `nvidia-smi` is unavailable. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| #!/usr/bin/env node | ||
| // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| import crypto from 'node:crypto'; | ||
| import fs from 'node:fs'; | ||
| import path from 'node:path'; | ||
| import { fileURLToPath } from 'node:url'; | ||
| const sha=(v)=>crypto.createHash('sha256').update(JSON.stringify(v)).digest('hex'); | ||
| const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); | ||
| const runDir = path.join(root, '.artifacts', 'local-governed-proof'); | ||
| fs.mkdirSync(path.join(runDir,'operator'), {recursive:true}); | ||
| const nowIso = new Date().toISOString(); | ||
| const node={nodeId:'local-node-1',trustStatus:'trusted_local',attestationStatus:'not_required',telemetryState:'unavailable',profileSource:'local-default',registeredAt:nowIso}; | ||
| const probe={outcomes:[{probe:'gpu-nvidia-smi',state:'unavailable',detail:'command_unavailable'}],telemetry:{gpus:{state:'unavailable',reason:'command_unavailable'}}}; | ||
| const intent={id:'intent-local-safe-echo',action:'safe.local.echo',payload:{message:'NemoClaw governed local proof'}}; | ||
| const policy={decision:'allow',allowedActions:['safe.local.echo'],reasonCode:'policy_allow_safe_action'}; | ||
| const trust={nodeId:node.nodeId,trustStatus:node.trustStatus,attestationStatus:node.attestationStatus}; | ||
| const plan={id:'plan-local-safe-echo',status:'approved',intentHash:sha(intent),policyHash:sha(policy),trustHash:sha(trust),replayRef:'replay-local-governed-proof'}; | ||
| const queue={id:'queue-local-safe-echo',planId:plan.id,idempotencyKey:sha(plan.id).slice(0,24),status:'queued'}; | ||
| const lease={id:'lease-local-safe-echo',queueId:queue.id,ownerId:'local-operator',status:'active'}; | ||
| const execution={id:'exec-local-safe-echo',status:'completed',stdout:intent.payload.message,stderr:'',durationMs:0,timedOut:false}; | ||
| const receipt={id:'receipt-local-safe-echo',status:'completed',executionId:execution.id,planId:plan.id,queueId:queue.id,leaseId:lease.id}; | ||
| const replay={id:'replay-local-governed-proof',reasonCode:'replay_validated',lineage:[node.nodeId,plan.id,queue.id,lease.id,receipt.id]}; | ||
| const manifest={node,probe,intent,policy,trust,plan,queue,lease,execution,receipt,replay}; | ||
| const manifestHash=sha(manifest); | ||
| fs.writeFileSync(path.join(runDir,'manifest.json'), JSON.stringify({...manifest,manifestHash},null,2)); | ||
| fs.writeFileSync(path.join(runDir,'proofpack.json'), JSON.stringify({manifestHash,replayEnvelope:replay,receiptId:receipt.id},null,2)); | ||
| const rows={status:[{id:'local-proof',state:'ok',detail:`manifestHash=${manifestHash}`}],diagnostics:[{id:'local-node',state:'degraded',detail:'telemetry unavailable'}],workers:[{id:node.nodeId,state:'ready',detail:'local deterministic worker'}],telemetry:[{id:'gpu',state:'unavailable',detail:'command_unavailable',unavailable:true}],plans:[{id:plan.id,state:plan.status,detail:`intentHash=${plan.intentHash}`}],queue:[{id:queue.id,state:queue.status,detail:`idempotencyKey=${queue.idempotencyKey}`}],receipts:[{id:receipt.id,state:receipt.status,detail:`executionId=${execution.id}`}],replay:[{id:replay.id,state:'validated',detail:replay.reasonCode}],proofpack:[{id:'proofpack',state:'exported',detail:`manifestHash=${manifestHash}`}],degraded:[{id:'nvidia_smi_unavailable',state:'degraded',detail:'nvidia-smi not available'}],trust:[{id:node.nodeId,state:node.trustStatus,detail:node.attestationStatus}],attestation:[{id:node.nodeId,state:node.attestationStatus,detail:'local deterministic profile'}],policy:[{id:'local-proof-policy',state:'allow',detail:'policy_allow_safe_action'}],approvals:[{id:plan.id,state:'not_required',detail:'safe local action'}]}; | ||
| for(const [k,v] of Object.entries(rows)) fs.writeFileSync(path.join(runDir,'operator',`${k}.json`),JSON.stringify(v,null,2)); | ||
| console.log('node registered');console.log('probe complete with unavailable telemetry if no GPU/runtime');console.log('plan created');console.log('queued');console.log('lease acquired');console.log('safe action executed');console.log('receipt emitted');console.log('replay validated');console.log('proofpack exported');console.log(`operator inspect: nemoclaw operator status --source ${runDir}`); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,9 +11,10 @@ const TOPICS: OperatorTopic[] = [ | |
| "status","diagnostics","workers","telemetry","trust","attestation","replay","receipts","proofpack","queue","policy","degraded","plans","approvals", | ||
| ]; | ||
|
|
||
| function loadTopic(topic: OperatorTopic, rootDir: string): OperatorRecord[] { | ||
| const fixture = path.join(rootDir, "fixtures", "demo", `${topic}.json`); | ||
| return JSON.parse(fs.readFileSync(fixture, "utf8")) as OperatorRecord[]; | ||
| function loadTopic(topic: OperatorTopic, rootDir: string, source?: string): OperatorRecord[] { | ||
| const sourceDir = source ? path.resolve(source, "operator") : path.join(rootDir, "fixtures", "demo"); | ||
| const file = path.join(sourceDir, `${topic}.json`); | ||
| return JSON.parse(fs.readFileSync(file, "utf8")) as OperatorRecord[]; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. WARNING: No error handling for file read operations. If the file doesn't exist or JSON is malformed, the CLI will crash with an unhandled exception. For a tool meant for operator inspection, this should provide a helpful error message instead of crashing. Consider adding try-catch with validation: function loadTopic(topic: OperatorTopic, rootDir: string, source?: string): OperatorRecord[] {
const sourceDir = source ? path.resolve(source, "operator") : path.join(rootDir, "fixtures", "demo");
const file = path.join(sourceDir, `${topic}.json`);
try {
const content = fs.readFileSync(file, "utf8");
return JSON.parse(content) as OperatorRecord[];
} catch (err) {
throw new Error(`Failed to load operator topic '${topic}': ${err.message}`);
}
} |
||
| } | ||
|
|
||
| export default class OperatorCommand extends Command { | ||
|
|
@@ -29,12 +30,13 @@ export default class OperatorCommand extends Command { | |
| static flags = { | ||
| help: Flags.help({ char: "h" }), | ||
| json: Flags.boolean({ description: "Emit deterministic JSON output" }), | ||
| source: Flags.string({ description: "Path to run directory or proofpack artifact root" }), | ||
| }; | ||
|
|
||
| public async run(): Promise<void> { | ||
| const { args, flags } = await this.parse(OperatorCommand); | ||
| const topic = args.topic as OperatorTopic; | ||
| const rows = loadTopic(topic, this.config.root); | ||
| const rows = loadTopic(topic, this.config.root, flags.source); | ||
| const out: OperatorOutput = flags.json ? "json" : "table"; | ||
| this.log(out === "json" ? formatJson(topic, rows) : formatTable(rows)); | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The demo claims a deterministic proof path, but
registeredAtis set fromnew Date().toISOString(), which changes on every run and therefore changesmanifestHashandproofpack.jsonoutput each time. In practice, runningnpm run demo:local-prooftwice yields different hashes, so replay/evidence comparisons are not stable even when inputs are identical.Useful? React with 👍 / 👎.