deadbyte-mcp 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MANIFEST.SHA256 +134 -92
- package/README.txt +19 -15
- package/bench/fixtures/corpus.json +32 -13
- package/bench/fixtures/r36/case-map.json +8 -0
- package/bin/WORKER-REGISTRY.txt +3 -3
- package/bin/appcontainer-stage.exe +0 -0
- package/bin/appcontainer-stage.obj +0 -0
- package/bin/bootstrap-advapi32.exe +0 -0
- package/bin/bootstrap-advapi32.obj +0 -0
- package/bin/bootstrap-exitcode.exe +0 -0
- package/bin/bootstrap-exitcode.obj +0 -0
- package/bin/bootstrap-kernel32.exe +0 -0
- package/bin/bootstrap-kernel32.obj +0 -0
- package/bin/child-control-probe.exe +0 -0
- package/bin/child-control-probe.obj +0 -0
- package/bin/child-control-stage.exe +0 -0
- package/bin/child-control-stage.obj +0 -0
- package/bin/contained-reverse-worker.exe +0 -0
- package/bin/contained-reverse-worker.obj +0 -0
- package/bin/contained-transform-worker.exe +0 -0
- package/bin/contained-transform-worker.obj +0 -0
- package/bin/containment-probe.exe +0 -0
- package/bin/containment-probe.obj +0 -0
- package/bin/deadbyte-contain.exe +0 -0
- package/bin/deadbyte-contain.obj +0 -0
- package/bin/deadbyte-exec.exe +0 -0
- package/bin/deadbyte-exec.obj +0 -0
- package/bin/deadbyte-process-host.exe +0 -0
- package/bin/deadbyte-process-host.obj +0 -0
- package/bin/deadbyte-tunnel-host.exe +0 -0
- package/bin/deadbyte-tunnel-host.obj +0 -0
- package/controller/README.TXT +8 -6
- package/controller/deadbyte-controller.ps1 +48 -2
- package/controller/deadbyte-process-policy.json +5 -5
- package/docs/ARCHITECTURE.md +1 -1
- package/docs/R36-CAPABILITY-EVIDENCE.md +43 -0
- package/docs/superpowers/plans/2026-09-18-r36-zero-loss-autonomy.md +739 -0
- package/docs/superpowers/specs/2026-09-18-r36-zero-loss-autonomy-design.md +640 -0
- package/package.json +1 -1
- package/proof/CONTAINMENT-BUILD.txt +6 -6
- package/scripts/deferred-slot-operation.mjs +53 -15
- package/scripts/final-closure-r36.mjs +113 -0
- package/scripts/final-closure-verify-r36.mjs +208 -0
- package/scripts/final-closure-verify.mjs +88 -39
- package/scripts/final-closure.mjs +63 -56
- package/scripts/gate-windows-r36.ps1 +42 -0
- package/scripts/gate-windows.ps1 +3 -3
- package/scripts/release-parity-r36.mjs +200 -0
- package/scripts/release-parity-tests.ps1 +9 -0
- package/scripts/release-parity.mjs +149 -139
- package/scripts/windows-gate-evidence-r36.mjs +52 -0
- package/scripts/windows-gate-evidence.mjs +5 -5
- package/src/agent-memory-plane.mjs +98 -0
- package/src/autonomous-context-engine.mjs +2 -1
- package/src/autonomous-mcp-tools.mjs +5 -1
- package/src/autonomous-output-contracts.mjs +9 -6
- package/src/autonomous-planner-contracts.mjs +36 -1
- package/src/autonomous-planner.mjs +25 -3
- package/src/autonomous-runtime.mjs +337 -43
- package/src/autonomous-timeout-recovery.mjs +27 -0
- package/src/capability-benchmark-runner.mjs +86 -1
- package/src/capability-benchmark.mjs +45 -0
- package/src/capability-ledger.mjs +158 -0
- package/src/coding-mcp-tools.mjs +31 -17
- package/src/coding-output-contracts.mjs +48 -10
- package/src/coding-plane.mjs +45 -9
- package/src/coding-search.mjs +130 -47
- package/src/compact-gateway-mcp-tools.mjs +128 -0
- package/src/compact-gateway-output-contracts.mjs +16 -0
- package/src/deadbyte-cli.mjs +62 -78
- package/src/effect-ledger.mjs +47 -0
- package/src/machine-fs-smoke-client.mjs +1 -1
- package/src/machine-fs.mjs +51 -8
- package/src/mcp-server.mjs +32 -9
- package/src/native-diff-v2.mjs +337 -0
- package/src/native-diff.mjs +50 -2
- package/src/observation-lease.mjs +32 -0
- package/src/observation-smoke-client.mjs +1 -1
- package/src/operator-surface.mjs +7 -1
- package/src/process-runtime.mjs +98 -11
- package/src/process-smoke-client.mjs +11 -3
- package/src/r36-compact-disarmed-probe.mjs +50 -0
- package/src/r36-full-surface-probe.mjs +56 -0
- package/src/remote-live-log.mjs +135 -0
- package/src/remote-mcp-autonomous-smoke-client.mjs +22 -12
- package/src/remote-mcp-coding-smoke-client.mjs +1 -1
- package/src/remote-mcp-r36-parity-client.mjs +175 -0
- package/src/remote-mcp-smoke-client.mjs +112 -56
- package/src/runtime-update.mjs +51 -1
- package/src/search-cursor.mjs +45 -0
- package/src/semantic-code.mjs +72 -5
- package/src/semantic-lsp-backend.mjs +39 -3
- package/src/version.mjs +1 -1
- package/src/worker-scheduler.mjs +53 -0
- package/test/autonomous-capability-r36.test.mjs +151 -0
- package/test/autonomous-output-contract.test.mjs +1 -1
- package/test/autonomous-runtime.test.mjs +2 -2
- package/test/capability-benchmark-r36.test.mjs +107 -0
- package/test/capability-benchmark-semantic-r36.test.mjs +52 -0
- package/test/capability-claims-r36.test.mjs +23 -0
- package/test/capability-ledger-r36.test.mjs +102 -0
- package/test/coding-catalog-consistency.test.mjs +2 -2
- package/test/coding-plane.test.mjs +2 -2
- package/test/coding-runtime.test.mjs +16 -0
- package/test/coding-search-r36.test.mjs +90 -0
- package/test/compact-catalog-r36.test.mjs +37 -0
- package/test/compact-gateway-r36.test.mjs +66 -0
- package/test/contained.test.mjs +1 -1
- package/test/core.test.mjs +1 -1
- package/test/deferred-slot-operation.test.mjs +9 -0
- package/test/fixtures/lsp-framed-server.mjs +2 -0
- package/test/helpers/autonomous-r34-fixture.mjs +5 -3
- package/test/multi-file-read.test.mjs +3 -0
- package/test/native-diff-topology-r36.test.mjs +105 -0
- package/test/package-boundary.test.mjs +6 -0
- package/test/process-longrun-r36.test.mjs +82 -0
- package/test/process-release-gate.test.mjs +9 -0
- package/test/production-docs.test.mjs +5 -5
- package/test/prompts-resources.test.mjs +7 -1
- package/test/r33-closeout-regression.test.mjs +4 -3
- package/test/r33-finalization.test.mjs +14 -9
- package/test/r36-finalization.test.mjs +104 -0
- package/test/r36-release-identity.test.mjs +45 -0
- package/test/r37-agent-fabric.test.mjs +92 -0
- package/test/r37-autonomous-timeout-recovery.test.mjs +60 -0
- package/test/r37-finalization.test.mjs +74 -0
- package/test/release-version.test.mjs +42 -33
- package/test/remote-live-log-r36.test.mjs +37 -0
- package/test/remote-live-log-r37.test.mjs +47 -0
- package/test/remote-live-log-recovery-r36.test.mjs +41 -0
- package/test/remote-r24-catalog.test.mjs +13 -0
- package/test/remote-session-cli.test.mjs +53 -66
- package/test/runtime-self-update.test.mjs +58 -1
- package/test/semantic-lsp-backend.test.mjs +9 -0
- package/test/semantic-r36-rename.test.mjs +82 -0
- package/deadbyte-mcp-0.8.9.tgz +0 -0
|
@@ -11,6 +11,11 @@ import { deriveLoopState, repairFingerprint } from './autonomous-loop-state.mjs'
|
|
|
11
11
|
import { judgeProgress, stallDisposition } from './autonomous-progress.mjs';
|
|
12
12
|
import { classifyProviderFailure, deriveCircuit, providerCallDisposition, providerCircuitId } from './provider-circuit.mjs';
|
|
13
13
|
import { verifyObservationReceiptFile } from './observation-runtime.mjs';
|
|
14
|
+
import { R36_CAPABILITY_LEDGER } from './capability-ledger.mjs';
|
|
15
|
+
import { deriveAgentMemory } from './agent-memory-plane.mjs';
|
|
16
|
+
import { effectIdentity, loopGuardDisposition, bindEffectCompletion } from './effect-ledger.mjs';
|
|
17
|
+
import { createWorkerScheduler } from './worker-scheduler.mjs';
|
|
18
|
+
import { issueObservationLease, verifyObservationLease } from './observation-lease.mjs';
|
|
14
19
|
|
|
15
20
|
export const AUTONOMOUS_GOAL_SCHEMA = 'deadbyte.autonomous-goal.v1';
|
|
16
21
|
export const AUTONOMOUS_EVENT_SCHEMA = 'deadbyte.autonomous-event.v1';
|
|
@@ -163,6 +168,22 @@ async function acquireLock(ctx) {
|
|
|
163
168
|
throw new Error('autonomous lock acquisition failed');
|
|
164
169
|
}
|
|
165
170
|
async function releaseLock(ctx) { await rm(ctx.lockPath,{force:true}); }
|
|
171
|
+
async function runLockStatus(ctx) {
|
|
172
|
+
let parsed;
|
|
173
|
+
try { parsed = JSON.parse(await readFile(ctx.lockPath,'utf8')); }
|
|
174
|
+
catch (error) {
|
|
175
|
+
if (error?.code === 'ENOENT') return { run_busy:false, run_owner_pid:null, run_lock_created_at_utc:null };
|
|
176
|
+
throw new Error('autonomous lock malformed');
|
|
177
|
+
}
|
|
178
|
+
if (parsed?.schema !== 'deadbyte.autonomous-lock.v1' || parsed?.goal_id !== path.basename(ctx.dir) ||
|
|
179
|
+
!Number.isInteger(parsed?.pid) || parsed.pid < 1 || typeof parsed?.created_at_utc !== 'string' || !parsed.created_at_utc) {
|
|
180
|
+
throw new Error('autonomous lock malformed');
|
|
181
|
+
}
|
|
182
|
+
const alive=await processExists(parsed.pid);
|
|
183
|
+
return alive
|
|
184
|
+
? { run_busy:true, run_owner_pid:parsed.pid, run_lock_created_at_utc:parsed.created_at_utc }
|
|
185
|
+
: { run_busy:false, run_owner_pid:null, run_lock_created_at_utc:null };
|
|
186
|
+
}
|
|
166
187
|
async function readCancel(ctx, verifyKeyPath) {
|
|
167
188
|
if (!await exists(ctx.cancelPath)) return null;
|
|
168
189
|
const parsed = JSON.parse(await readFile(ctx.cancelPath,'utf8'));
|
|
@@ -318,17 +339,39 @@ function normalizeGoal(policy, { submissionId, rootId, title = '', goal, accepta
|
|
|
318
339
|
return Object.freeze({ ...body, goal_sha256:sha256Object(body) });
|
|
319
340
|
}
|
|
320
341
|
|
|
321
|
-
|
|
342
|
+
function configuredCapabilityManifest({machineFsRuntime,observationRuntime,processRuntime,semanticRuntime}) {
|
|
343
|
+
const plannerReachable=id => id === 'coding.stat' || id === 'coding.search' || id === 'coding.files_read' ||
|
|
344
|
+
id.startsWith('semantic.') || id.startsWith('native_diff.') || id.startsWith('process.') ||
|
|
345
|
+
id.startsWith('machine_fs.') || id.startsWith('observation.') || id === 'autonomous.release_gate';
|
|
346
|
+
const runtimeEnabled=entry => {
|
|
347
|
+
if (entry.runtime_flag === 'DEADBYTE_CODING_RUNTIME' || entry.runtime_flag === 'DEADBYTE_AUTONOMOUS_RUNTIME') return true;
|
|
348
|
+
if (entry.runtime_flag === 'DEADBYTE_MACHINE_FS_RUNTIME') return Boolean(machineFsRuntime);
|
|
349
|
+
if (entry.runtime_flag === 'DEADBYTE_PROCESS_RUNTIME') return Boolean(processRuntime);
|
|
350
|
+
if (entry.runtime_flag === 'DEADBYTE_OBSERVATION_RUNTIME') return Boolean(observationRuntime);
|
|
351
|
+
return entry.runtime_flag === null;
|
|
352
|
+
};
|
|
353
|
+
const entries=R36_CAPABILITY_LEDGER.entries
|
|
354
|
+
.filter(entry=>entry.production && !entry.host_only && plannerReachable(entry.id) && runtimeEnabled(entry))
|
|
355
|
+
.filter(entry=>!entry.id.startsWith('semantic.') || Boolean(semanticRuntime))
|
|
356
|
+
.map(entry=>({id:entry.id,authority:entry.authority,mutating:entry.mutating,full_tool:entry.full_tool,
|
|
357
|
+
compact_tool:entry.compact_tool,compact_op:entry.compact_op}));
|
|
358
|
+
return Object.freeze({schema:'deadbyte.capability-manifest.v1',ledger_sha256:R36_CAPABILITY_LEDGER.ledger_sha256,
|
|
359
|
+
entries:Object.freeze(entries)});
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
async function plannerView(goal, state, events, codingRuntime, capabilityManifest) {
|
|
322
363
|
const tree = await codingRuntime.tree({ rootId:goal.root_id, path:'.', maxDepth:4, maxEntries:600 });
|
|
364
|
+
const memory=deriveAgentMemory(events,{maxArchival:24});
|
|
323
365
|
return { mutation_epoch:state.mutation_epoch, planner_round:state.planner_round, tree:tree.entries,
|
|
324
366
|
contexts:state.contexts.slice(-16), observations:state.observations.slice(-24), active_plan:state.active_plan,
|
|
367
|
+
capabilities:capabilityManifest, project_memory:memory,
|
|
325
368
|
recent_decisions:state.decisions.slice(-8).map(item => ({ planner_round:item.planner_round,
|
|
326
369
|
action:item.decision?.action, summary:item.decision?.summary })) };
|
|
327
370
|
}
|
|
328
371
|
function requestIdFor(goalId, plannerRound, journalHead) {
|
|
329
372
|
return sha256Object({ schema:'deadbyte.autonomous-planner-request.v1', goal_id:goalId, planner_round:plannerRound, journal_head_sha256:journalHead });
|
|
330
373
|
}
|
|
331
|
-
async function requestPlanner(ctx, goal, events, state, policy, codingRuntime, signingKeyPath) {
|
|
374
|
+
async function requestPlanner(ctx, goal, events, state, policy, codingRuntime, capabilityManifest, signingKeyPath) {
|
|
332
375
|
if (state.pending_request) return state.pending_request;
|
|
333
376
|
const round = state.planner_round + 1;
|
|
334
377
|
if (round > goal.max_iterations) {
|
|
@@ -339,7 +382,7 @@ async function requestPlanner(ctx, goal, events, state, policy, codingRuntime, s
|
|
|
339
382
|
await appendEvent(ctx,events,signingKeyPath,'goal_paused',{ reason:'wall_time_limit', max_wall_ms:policy.limits.max_wall_ms });
|
|
340
383
|
return null;
|
|
341
384
|
}
|
|
342
|
-
const view = await plannerView(goal,state,codingRuntime);
|
|
385
|
+
const view = await plannerView(goal,state,events,codingRuntime,capabilityManifest);
|
|
343
386
|
let prompt = buildPlannerPrompt({ goal:{ title:goal.title, goal:goal.goal, acceptance:goal.acceptance }, policy, view });
|
|
344
387
|
const repair = [...(state.planner_rejections ?? [])].reverse().find(item => item.planner_round === round) ?? null;
|
|
345
388
|
if (repair) {
|
|
@@ -476,9 +519,9 @@ async function requestProviderWithCircuit({ctx,events,goal,policy,pending,signin
|
|
|
476
519
|
throw error;
|
|
477
520
|
}
|
|
478
521
|
}
|
|
479
|
-
async function acceptPlannerDecision({ ctx, events, goal, state, policy, codingRuntime, signingKeyPath, plannerResponse }) {
|
|
522
|
+
async function acceptPlannerDecision({ ctx, events, goal, state, policy, codingRuntime, capabilityManifest, signingKeyPath, plannerResponse }) {
|
|
480
523
|
let currentState = state;
|
|
481
|
-
let pending = currentState.pending_request ?? await requestPlanner(ctx,goal,events,currentState,policy,codingRuntime,signingKeyPath);
|
|
524
|
+
let pending = currentState.pending_request ?? await requestPlanner(ctx,goal,events,currentState,policy,codingRuntime,capabilityManifest,signingKeyPath);
|
|
482
525
|
if (!pending) return null;
|
|
483
526
|
let suppliedResponse = plannerResponse;
|
|
484
527
|
while (pending) {
|
|
@@ -517,7 +560,7 @@ async function acceptPlannerDecision({ ctx, events, goal, state, policy, codingR
|
|
|
517
560
|
return { needs_planner:false, rejected:true, paused:true };
|
|
518
561
|
}
|
|
519
562
|
currentState = deriveState(goal,events);
|
|
520
|
-
pending = await requestPlanner(ctx,goal,events,currentState,policy,codingRuntime,signingKeyPath);
|
|
563
|
+
pending = await requestPlanner(ctx,goal,events,currentState,policy,codingRuntime,capabilityManifest,signingKeyPath);
|
|
521
564
|
if (!pending) return null;
|
|
522
565
|
if (policy.planner.backend === 'client_sampling') return { needs_planner:true, request:pending };
|
|
523
566
|
continue;
|
|
@@ -557,6 +600,18 @@ async function executeInspect({ ctx, events, goal, decisionEvent, decision, codi
|
|
|
557
600
|
}
|
|
558
601
|
|
|
559
602
|
const DELEGATED_MUTATIONS = new Set(['process_start','process_action','process_terminate','observation_search_cancel']);
|
|
603
|
+
const CAPABILITY_BY_ACTION=Object.freeze({
|
|
604
|
+
search:'coding.search',stat:'coding.stat',multi_read:'coding.files_read',
|
|
605
|
+
semantic_outline:'semantic.outline',semantic_definition:'semantic.definition',semantic_references:'semantic.references',
|
|
606
|
+
semantic_diagnostics:'semantic.diagnostics',semantic_implementations:'semantic.implementations',semantic_rename_preview:'semantic.rename_preview',
|
|
607
|
+
native_diff_apply:'native_diff.apply',native_diff_verify:'native_diff.verify',
|
|
608
|
+
process_start:'process.start',process_read:'process.read',process_status:'process.status',process_list:'process.list',process_action:'process.action',process_terminate:'process.terminate',
|
|
609
|
+
machine_fs_stat:'machine_fs.stat',machine_fs_list:'machine_fs.list',machine_fs_read:'machine_fs.read',machine_fs_mkdir:'machine_fs.mkdir',machine_fs_move:'machine_fs.move',machine_fs_delete:'machine_fs.delete',
|
|
610
|
+
machine_stat:'machine_fs.stat',machine_list:'machine_fs.list',machine_read:'machine_fs.read',
|
|
611
|
+
observation_search_start:'observation.search_start',observation_search_status:'observation.search_status',observation_search_page:'observation.search_page',observation_search_cancel:'observation.search_cancel',
|
|
612
|
+
observation_process_list:'observation.process_list',observation_system_status:'observation.system_status'
|
|
613
|
+
});
|
|
614
|
+
function capabilityIdForOperation(operation){return CAPABILITY_BY_ACTION[operation?.kind]??null;}
|
|
560
615
|
function assertDelegatedIdentity(events, operation) {
|
|
561
616
|
if (['observation_search_status','observation_search_page','observation_search_cancel'].includes(operation.kind)) {
|
|
562
617
|
const owned = events.some(event => event.type === 'delegated_action_completed' &&
|
|
@@ -570,8 +625,45 @@ function assertDelegatedIdentity(events, operation) {
|
|
|
570
625
|
}
|
|
571
626
|
}
|
|
572
627
|
async function invokeDelegatedOperation(goal, operation, runtimes) {
|
|
573
|
-
const { machineFsRuntime, observationRuntime, processRuntime } = runtimes;
|
|
628
|
+
const { codingRuntime, semanticRuntime, nativeDiffRuntime, machineFsRuntime, observationRuntime, processRuntime } = runtimes;
|
|
574
629
|
switch (operation.kind) {
|
|
630
|
+
case 'stat':
|
|
631
|
+
return codingRuntime.stat({rootId:goal.root_id,relativePath:operation.path,hash:operation.hash});
|
|
632
|
+
case 'search':
|
|
633
|
+
return codingRuntime.search({rootId:goal.root_id,path:operation.path,pattern:operation.pattern,target:operation.target,mode:operation.mode,
|
|
634
|
+
caseSensitive:operation.case_sensitive,maxResults:operation.max_results,maxFileBytes:operation.max_file_bytes,
|
|
635
|
+
maxScanBytes:operation.max_scan_bytes,pageSize:operation.page_size,cursor:operation.cursor});
|
|
636
|
+
case 'multi_read':
|
|
637
|
+
return codingRuntime.filesRead({rootId:goal.root_id,files:operation.files,maxTotalBytes:operation.max_total_bytes});
|
|
638
|
+
case 'semantic_outline':
|
|
639
|
+
if (!semanticRuntime) throw new Error('semantic runtime unavailable');
|
|
640
|
+
return semanticRuntime.outline({rootId:goal.root_id,relativePath:operation.path,maxSymbols:operation.max_symbols});
|
|
641
|
+
case 'semantic_definition':
|
|
642
|
+
if (!semanticRuntime) throw new Error('semantic runtime unavailable');
|
|
643
|
+
return semanticRuntime.definition({rootId:goal.root_id,relativePath:operation.path,line:operation.line,column:operation.column,maxResults:operation.max_results});
|
|
644
|
+
case 'semantic_references':
|
|
645
|
+
if (!semanticRuntime) throw new Error('semantic runtime unavailable');
|
|
646
|
+
return semanticRuntime.references({rootId:goal.root_id,relativePath:operation.path,line:operation.line,column:operation.column,maxResults:operation.max_results});
|
|
647
|
+
case 'semantic_diagnostics':
|
|
648
|
+
if (!semanticRuntime) throw new Error('semantic runtime unavailable');
|
|
649
|
+
return semanticRuntime.diagnostics({rootId:goal.root_id,relativePath:operation.path,maxResults:operation.max_results});
|
|
650
|
+
case 'semantic_implementations':
|
|
651
|
+
if (!semanticRuntime) throw new Error('semantic runtime unavailable');
|
|
652
|
+
return semanticRuntime.implementations({rootId:goal.root_id,relativePath:operation.path,line:operation.line,column:operation.column,maxResults:operation.max_results});
|
|
653
|
+
case 'semantic_rename_preview':
|
|
654
|
+
if (!semanticRuntime) throw new Error('semantic runtime unavailable');
|
|
655
|
+
return semanticRuntime.renamePreview({rootId:goal.root_id,relativePath:operation.path,line:operation.line,column:operation.column,newName:operation.new_name});
|
|
656
|
+
case 'native_diff_verify':
|
|
657
|
+
return nativeDiffRuntime.verify({diffId:operation.diff_id});
|
|
658
|
+
case 'machine_fs_stat':
|
|
659
|
+
if (!machineFsRuntime) throw new Error('machine filesystem runtime unavailable');
|
|
660
|
+
return machineFsRuntime.stat({rootId:goal.root_id,relativePath:operation.path,hash:operation.hash});
|
|
661
|
+
case 'machine_fs_list':
|
|
662
|
+
if (!machineFsRuntime) throw new Error('machine filesystem runtime unavailable');
|
|
663
|
+
return machineFsRuntime.list({rootId:goal.root_id,relativePath:operation.path,cursor:operation.cursor,limit:operation.limit,hashFiles:operation.hash_files});
|
|
664
|
+
case 'machine_fs_read':
|
|
665
|
+
if (!machineFsRuntime) throw new Error('machine filesystem runtime unavailable');
|
|
666
|
+
return machineFsRuntime.read({rootId:goal.root_id,relativePath:operation.path,offset:operation.offset,maxBytes:operation.max_bytes,hashFile:operation.hash_file});
|
|
575
667
|
case 'machine_stat':
|
|
576
668
|
if (!machineFsRuntime) throw new Error('machine filesystem runtime unavailable');
|
|
577
669
|
return machineFsRuntime.stat({ rootId:goal.root_id, relativePath:operation.path, hash:operation.hash });
|
|
@@ -605,7 +697,7 @@ async function invokeDelegatedOperation(goal, operation, runtimes) {
|
|
|
605
697
|
return observationRuntime.systemStatus();
|
|
606
698
|
case 'process_start':
|
|
607
699
|
if (!processRuntime) throw new Error('process runtime unavailable');
|
|
608
|
-
return processRuntime.start({ profileId:operation.profile_id, rootId:goal.root_id, cwd:operation.cwd, args:[] });
|
|
700
|
+
return processRuntime.start({ profileId:operation.profile_id, rootId:goal.root_id, cwd:operation.cwd, args:operation.args??[] });
|
|
609
701
|
case 'process_read':
|
|
610
702
|
if (!processRuntime) throw new Error('process runtime unavailable');
|
|
611
703
|
return processRuntime.read({ sessionId:operation.session_id, offset:operation.offset, maxBytes:operation.max_bytes });
|
|
@@ -647,7 +739,9 @@ async function verifyDelegatedEvidence(operation, result, runtimes, verifyKeyPat
|
|
|
647
739
|
}
|
|
648
740
|
async function executeDelegate({ ctx, events, goal, decisionEvent, decision, policy, runtimes, assertRunAuthority,
|
|
649
741
|
signingKeyPath, verifyKeyPath }) {
|
|
650
|
-
const
|
|
742
|
+
const capabilityId=capabilityIdForOperation(decision.operation);
|
|
743
|
+
if(!capabilityId) throw new Error(`unsupported typed capability action '${String(decision.operation?.kind)}'`);
|
|
744
|
+
const actionKey = `capability-${decisionEvent.event_sha256}`;
|
|
651
745
|
const prior = [...events].reverse().find(event => event.type === 'delegated_action_completed' && event.payload?.action_key === actionKey);
|
|
652
746
|
if (prior) return { status:'completed', result:prior.payload.result, existing:true };
|
|
653
747
|
const started = [...events].reverse().find(event => event.type === 'delegated_action_started' && event.payload?.action_key === actionKey);
|
|
@@ -656,7 +750,7 @@ async function executeDelegate({ ctx, events, goal, decisionEvent, decision, pol
|
|
|
656
750
|
operation_kind:decision.operation.kind });
|
|
657
751
|
return { status:'paused' };
|
|
658
752
|
}
|
|
659
|
-
await appendEvent(ctx,events,signingKeyPath,'delegated_action_started',{ action_key:actionKey,
|
|
753
|
+
await appendEvent(ctx,events,signingKeyPath,'delegated_action_started',{ action_key:actionKey, capability_id:capabilityId,
|
|
660
754
|
decision_event_sha256:decisionEvent.event_sha256, operation:decision.operation });
|
|
661
755
|
try {
|
|
662
756
|
assertDelegatedIdentity(events,decision.operation);
|
|
@@ -666,7 +760,7 @@ async function executeDelegate({ ctx, events, goal, decisionEvent, decision, pol
|
|
|
666
760
|
throw new Error('delegated result exceeds autonomous context bound');
|
|
667
761
|
}
|
|
668
762
|
const evidence = await verifyDelegatedEvidence(decision.operation,result,runtimes,verifyKeyPath);
|
|
669
|
-
await appendEvent(ctx,events,signingKeyPath,'delegated_action_completed',{ action_key:actionKey,
|
|
763
|
+
await appendEvent(ctx,events,signingKeyPath,'delegated_action_completed',{ action_key:actionKey, capability_id:capabilityId,
|
|
670
764
|
decision_event_sha256:decisionEvent.event_sha256, operation:decision.operation, result, evidence });
|
|
671
765
|
return { status:'completed', result, evidence };
|
|
672
766
|
} catch (error) {
|
|
@@ -676,14 +770,36 @@ async function executeDelegate({ ctx, events, goal, decisionEvent, decision, pol
|
|
|
676
770
|
}
|
|
677
771
|
}
|
|
678
772
|
|
|
679
|
-
async function
|
|
773
|
+
async function executeProfileWithLease({workerScheduler,ctx,events,goal,epoch,actionKey,profileId,policy,codingRuntime,signingKeyPath,r34ResumePhase=null}) {
|
|
774
|
+
if(!workerScheduler) throw new Error('R37 worker scheduler unavailable');
|
|
775
|
+
const taskId=`${goal.goal_id}:${actionKey}:${profileId}`;
|
|
776
|
+
const lease=workerScheduler.acquire({taskId,workerClass:'profile',cpuUnits:1,memoryMb:256});
|
|
777
|
+
await appendEvent(ctx,events,signingKeyPath,'worker_lease_acquired',{
|
|
778
|
+
lease_id:lease.lease_id,task_id:lease.task_id,worker_class:lease.worker_class,profile_id:profileId,
|
|
779
|
+
attempt:lease.attempt,cpu_units:lease.cpu_units,memory_mb:lease.memory_mb,expires_at_ms:lease.expires_at_ms
|
|
780
|
+
});
|
|
781
|
+
let outcomeStatus='failed';
|
|
782
|
+
try {
|
|
783
|
+
const result=await executeProfile({ctx,events,goalId:goal.goal_id,actionKey,profileId,epoch,policy,codingRuntime,signingKeyPath,r34ResumePhase});
|
|
784
|
+
outcomeStatus=result.status;
|
|
785
|
+
return result;
|
|
786
|
+
} finally {
|
|
787
|
+
const released=workerScheduler.release(lease.lease_id,{status:outcomeStatus});
|
|
788
|
+
await appendEvent(ctx,events,signingKeyPath,'worker_lease_released',{
|
|
789
|
+
lease_id:lease.lease_id,task_id:lease.task_id,worker_class:lease.worker_class,profile_id:profileId,
|
|
790
|
+
status:released.lease.status,released_at_ms:released.lease.released_at_ms
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
async function runMutationProfiles({ ctx, events, goal, epoch, actionKey, policy, codingRuntime, signingKeyPath, workerScheduler }) {
|
|
680
796
|
const profileIds = Object.entries(policy.profiles)
|
|
681
797
|
.filter(([,profile]) => profile.run_after_mutation)
|
|
682
798
|
.map(([id]) => id);
|
|
683
799
|
const results = [];
|
|
684
800
|
for (const profileId of profileIds) {
|
|
685
|
-
const result = await
|
|
686
|
-
profileId,
|
|
801
|
+
const result = await executeProfileWithLease({workerScheduler,ctx,events,goal,epoch,
|
|
802
|
+
actionKey:`${actionKey}:${profileId}`,profileId,policy,codingRuntime,signingKeyPath});
|
|
687
803
|
results.push({ profile_id:profileId, status:result.status, observation:result.observation });
|
|
688
804
|
if (result.status === 'paused') break;
|
|
689
805
|
}
|
|
@@ -729,16 +845,22 @@ async function appendPatchCommit({ctx,events,signingKeyPath,started,decisionEven
|
|
|
729
845
|
const prior = patchCommitForAction(events,actionId);
|
|
730
846
|
if (prior) return prior;
|
|
731
847
|
const action = started.payload.action;
|
|
848
|
+
const verifiedPaths=[...new Set((verified.final_states??[]).flatMap(item=>[
|
|
849
|
+
typeof item?.path==='string'?item.path:null,
|
|
850
|
+
typeof item?.source_path==='string'?item.source_path:null,
|
|
851
|
+
typeof item?.destination_path==='string'?item.destination_path:null
|
|
852
|
+
].filter(Boolean)))].sort((a,b)=>a.localeCompare(b,'en'));
|
|
732
853
|
return appendEvent(ctx,events,signingKeyPath,'native_diff_committed',{
|
|
733
854
|
action_id:actionId, decision_event_sha256:decisionEvent.event_sha256, diff_id:action.diff_id,
|
|
734
855
|
diff_receipt_sha256:verified.receipt_sha256, mutation_epoch:started.payload.target_mutation_epoch,
|
|
735
856
|
mutation_count:started.payload.mutation_count, operation_count:action.operation_count,
|
|
736
|
-
paths:action.paths
|
|
857
|
+
paths:Array.isArray(action.paths)&&action.paths.length>0?action.paths:verifiedPaths,
|
|
858
|
+
coding_receipts_verified:verified.coding_receipts_verified,
|
|
737
859
|
...(recovered ? { recovered:true } : {})
|
|
738
860
|
});
|
|
739
861
|
}
|
|
740
862
|
async function executePatch({ ctx, events, goal, state, decisionEvent, decision, nativeDiffRuntime,
|
|
741
|
-
policy, codingRuntime, signingKeyPath, actionCoordinatesOverride = null }) {
|
|
863
|
+
policy, codingRuntime, signingKeyPath, workerScheduler, actionCoordinatesOverride = null }) {
|
|
742
864
|
let started = patchStartedForDecision(events,decisionEvent.event_sha256);
|
|
743
865
|
if (!started && state.mutation_count + decision.operations.length > policy.limits.max_mutations) {
|
|
744
866
|
await appendEvent(ctx,events,signingKeyPath,'goal_paused',{
|
|
@@ -774,7 +896,7 @@ async function executePatch({ ctx, events, goal, state, decisionEvent, decision,
|
|
|
774
896
|
if (!committed) throw new Error('completed patch action missing native diff commit');
|
|
775
897
|
const epoch = committed.payload.mutation_epoch;
|
|
776
898
|
const profiles = await runMutationProfiles({ ctx,events,goal,epoch,
|
|
777
|
-
actionKey:`mutation-${epoch}`,policy,codingRuntime,signingKeyPath });
|
|
899
|
+
actionKey:`mutation-${epoch}`,policy,codingRuntime,signingKeyPath,workerScheduler });
|
|
778
900
|
return { status:profiles.some(item => item.status === 'paused') ? 'paused' : 'completed',
|
|
779
901
|
diff_id:diffId, mutation_epoch:epoch, profiles, recovered:true };
|
|
780
902
|
}
|
|
@@ -822,11 +944,72 @@ async function executePatch({ ctx, events, goal, state, decisionEvent, decision,
|
|
|
822
944
|
}
|
|
823
945
|
const epoch = committed.payload.mutation_epoch;
|
|
824
946
|
const profiles = await runMutationProfiles({ ctx,events,goal,epoch,
|
|
825
|
-
actionKey:`mutation-${epoch}`,policy,codingRuntime,signingKeyPath });
|
|
947
|
+
actionKey:`mutation-${epoch}`,policy,codingRuntime,signingKeyPath,workerScheduler });
|
|
826
948
|
return { status:profiles.some(item => item.status === 'paused') ? 'paused' : 'completed',
|
|
827
949
|
diff_id:diffId, mutation_epoch:epoch, profiles, recovered };
|
|
828
950
|
}
|
|
829
|
-
async function
|
|
951
|
+
async function executePreparedDiff({ctx,events,goal,state,decisionEvent,diffId,expectedOperationCount,
|
|
952
|
+
policy,codingRuntime,nativeDiffRuntime,signingKeyPath,workerScheduler}) {
|
|
953
|
+
let started=patchStartedForDecision(events,decisionEvent.event_sha256);
|
|
954
|
+
if(!started&&state.mutation_count+expectedOperationCount>policy.limits.max_mutations){
|
|
955
|
+
await appendEvent(ctx,events,signingKeyPath,'goal_paused',{reason:'mutation_limit',max_mutations:policy.limits.max_mutations});
|
|
956
|
+
return {status:'paused'};
|
|
957
|
+
}
|
|
958
|
+
if(!started){
|
|
959
|
+
const coordinates=patchActionCoordinates(state);
|
|
960
|
+
const action={kind:'patch',diff_id:diffId,operation_count:expectedOperationCount,paths:[]};
|
|
961
|
+
const identity=actionIdentity({goalId:goal.goal_id,planId:coordinates.planId,planVersion:coordinates.planVersion,
|
|
962
|
+
stepId:coordinates.stepId,mutationEpoch:state.mutation_epoch,decisionEventSha:decisionEvent.event_sha256,action});
|
|
963
|
+
started=await appendEvent(ctx,events,signingKeyPath,'action_started',{
|
|
964
|
+
...identity,decision_event_sha256:decisionEvent.event_sha256,plan_id:coordinates.planId,
|
|
965
|
+
plan_version:coordinates.planVersion,step_id:coordinates.stepId,mutation_epoch:state.mutation_epoch,
|
|
966
|
+
target_mutation_epoch:state.mutation_epoch+1,mutation_count:expectedOperationCount,action
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
const actionId=started.payload.action_id;
|
|
970
|
+
const existingCompletion=patchCompletionForAction(events,actionId);
|
|
971
|
+
if(existingCompletion){
|
|
972
|
+
const committed=patchCommitForAction(events,actionId);
|
|
973
|
+
if(!committed) throw new Error('completed prepared diff action missing native diff commit');
|
|
974
|
+
const epoch=committed.payload.mutation_epoch;
|
|
975
|
+
const profiles=await runMutationProfiles({ctx,events,goal,epoch,actionKey:`mutation-${epoch}`,policy,codingRuntime,signingKeyPath,workerScheduler});
|
|
976
|
+
return {status:profiles.some(item=>item.status==='paused')?'paused':'completed',diff_id:diffId,mutation_epoch:epoch,profiles,recovered:true};
|
|
977
|
+
}
|
|
978
|
+
const reconciliation=await reconcileStartedAction({startedEvent:started,journal:events,runtimes:{nativeDiffRuntime,codingRuntime}});
|
|
979
|
+
if(reconciliation.classification==='ambiguous'){
|
|
980
|
+
if(!events.some(event=>event.type==='waiting_entered'&&event.payload?.action_id===actionId)){
|
|
981
|
+
await appendEvent(ctx,events,signingKeyPath,'waiting_entered',{reason:'ambiguous_interrupted_action',action_id:actionId,
|
|
982
|
+
decision_event_sha256:decisionEvent.event_sha256,detail:truncated(reconciliation.reason,512)});
|
|
983
|
+
}
|
|
984
|
+
await appendEvent(ctx,events,signingKeyPath,'goal_paused',{reason:'ambiguous_interrupted_action',action_id:actionId,
|
|
985
|
+
decision_event_sha256:decisionEvent.event_sha256});
|
|
986
|
+
return {status:'paused',reason:'ambiguous_interrupted_action'};
|
|
987
|
+
}
|
|
988
|
+
let verified; let recovered=false;
|
|
989
|
+
if(reconciliation.classification==='executed_verified'){
|
|
990
|
+
recovered=true;
|
|
991
|
+
verified=await verifyPatchDiff(nativeDiffRuntime,diffId);
|
|
992
|
+
if(verified.operation_count!==expectedOperationCount) throw new Error(`prepared native diff operation count mismatch: expected ${expectedOperationCount}, verified ${verified.operation_count}`);
|
|
993
|
+
if(!events.some(event=>event.type==='action_reconciled'&&event.payload?.action_id===actionId)){
|
|
994
|
+
await appendEvent(ctx,events,signingKeyPath,'action_reconciled',{action_id:actionId,request_sha256:started.payload.request_sha256,
|
|
995
|
+
decision_event_sha256:decisionEvent.event_sha256,classification:reconciliation.classification,evidence:reconciliation.evidence});
|
|
996
|
+
}
|
|
997
|
+
}else{
|
|
998
|
+
await nativeDiffRuntime.apply({diffId,expectedOperationCount});
|
|
999
|
+
verified=await verifyPatchDiff(nativeDiffRuntime,diffId);
|
|
1000
|
+
if(verified.operation_count!==expectedOperationCount) throw new Error(`prepared native diff operation count mismatch: expected ${expectedOperationCount}, verified ${verified.operation_count}`);
|
|
1001
|
+
}
|
|
1002
|
+
const committed=await appendPatchCommit({ctx,events,signingKeyPath,started,decisionEvent,verified,recovered});
|
|
1003
|
+
if(!patchCompletionForAction(events,actionId)){
|
|
1004
|
+
await appendEvent(ctx,events,signingKeyPath,'action_completed',{action_id:actionId,request_sha256:started.payload.request_sha256,
|
|
1005
|
+
decision_event_sha256:decisionEvent.event_sha256,classification:'executed_verified',diff_id:diffId,
|
|
1006
|
+
receipt_sha256:verified.receipt_sha256,recovered});
|
|
1007
|
+
}
|
|
1008
|
+
const epoch=committed.payload.mutation_epoch;
|
|
1009
|
+
const profiles=await runMutationProfiles({ctx,events,goal,epoch,actionKey:`mutation-${epoch}`,policy,codingRuntime,signingKeyPath,workerScheduler});
|
|
1010
|
+
return {status:profiles.some(item=>item.status==='paused')?'paused':'completed',diff_id:diffId,mutation_epoch:epoch,profiles,recovered};
|
|
1011
|
+
}
|
|
1012
|
+
async function runRequiredReleaseProfiles({ ctx, events, goal, state, policy, codingRuntime, signingKeyPath, workerScheduler }) {
|
|
830
1013
|
const requiredIds = Object.entries(policy.profiles)
|
|
831
1014
|
.filter(([,profile]) => profile.required_for_release)
|
|
832
1015
|
.map(([id]) => id);
|
|
@@ -837,9 +1020,9 @@ async function runRequiredReleaseProfiles({ ctx, events, goal, state, policy, co
|
|
|
837
1020
|
results.push({ profile_id:profileId, status:'passed', observation:existing, existing:true });
|
|
838
1021
|
continue;
|
|
839
1022
|
}
|
|
840
|
-
const result = await
|
|
841
|
-
actionKey:`release-${state.mutation_epoch}:${profileId}`,
|
|
842
|
-
epoch:state.mutation_epoch,policy,codingRuntime,signingKeyPath
|
|
1023
|
+
const result = await executeProfileWithLease({workerScheduler,ctx,events,goal,
|
|
1024
|
+
actionKey:`release-${state.mutation_epoch}:${profileId}`,profileId,
|
|
1025
|
+
epoch:state.mutation_epoch,policy,codingRuntime,signingKeyPath});
|
|
843
1026
|
results.push({ profile_id:profileId, ...result });
|
|
844
1027
|
if (result.status === 'paused') break;
|
|
845
1028
|
}
|
|
@@ -1012,8 +1195,8 @@ function r34ReasonHash(goal,decisionEvent,reason) {
|
|
|
1012
1195
|
decision_event_sha256:decisionEvent.event_sha256,reason:String(reason ?? '')});
|
|
1013
1196
|
}
|
|
1014
1197
|
async function executeR34Decision({ctx,events,goal,state,decisionEvent,decision,policy,codingRuntime,
|
|
1015
|
-
nativeDiffRuntime,machineFsRuntime,observationRuntime,processRuntime,assertRunAuthority,
|
|
1016
|
-
signingKeyPath,verifyKeyPath}) {
|
|
1198
|
+
nativeDiffRuntime,machineFsRuntime,observationRuntime,processRuntime,semanticRuntime,assertRunAuthority,
|
|
1199
|
+
signingKeyPath,verifyKeyPath,workerScheduler}) {
|
|
1017
1200
|
let loop=deriveLoopState(goal,events);
|
|
1018
1201
|
if (decision.kind === 'plan_create') {
|
|
1019
1202
|
if (loop.phase !== 'PLAN' || loop.plan) throw new Error('R34 plan_create requires empty PLANNING state');
|
|
@@ -1056,7 +1239,7 @@ async function executeR34Decision({ctx,events,goal,state,decisionEvent,decision,
|
|
|
1056
1239
|
try {
|
|
1057
1240
|
outcome=await executePatch({ctx,events,goal,state,decisionEvent,
|
|
1058
1241
|
decision:{operations:decision.action.operations,summary:`R34 ${currentStep.step_id}`},nativeDiffRuntime,
|
|
1059
|
-
policy,codingRuntime,signingKeyPath,actionCoordinatesOverride:{planId:loop.plan_id,
|
|
1242
|
+
policy,codingRuntime,signingKeyPath,workerScheduler,actionCoordinatesOverride:{planId:loop.plan_id,
|
|
1060
1243
|
planVersion:loop.plan_version,stepId:currentStep.step_id}});
|
|
1061
1244
|
} catch (error) {
|
|
1062
1245
|
const detail=truncated(error,512);
|
|
@@ -1069,13 +1252,42 @@ async function executeR34Decision({ctx,events,goal,state,decisionEvent,decision,
|
|
|
1069
1252
|
}
|
|
1070
1253
|
} else if (decision.action.kind === 'run_profile') {
|
|
1071
1254
|
await assertRunAuthority(goal.root_id);
|
|
1072
|
-
outcome=await
|
|
1255
|
+
outcome=await executeProfileWithLease({workerScheduler,ctx,events,goal,
|
|
1073
1256
|
actionKey:`r34-${decisionEvent.event_sha256}`,profileId:decision.action.profile_id,
|
|
1074
1257
|
epoch:state.mutation_epoch,policy,codingRuntime,signingKeyPath,r34ResumePhase:loop.phase});
|
|
1075
1258
|
} else if (decision.action.kind === 'delegate') {
|
|
1076
1259
|
outcome=await executeDelegate({ctx,events,goal,decisionEvent,
|
|
1077
1260
|
decision:{operation:decision.action.operation},policy,
|
|
1078
|
-
runtimes:{machineFsRuntime,observationRuntime,processRuntime},assertRunAuthority,signingKeyPath,verifyKeyPath});
|
|
1261
|
+
runtimes:{codingRuntime,semanticRuntime,nativeDiffRuntime,machineFsRuntime,observationRuntime,processRuntime},assertRunAuthority,signingKeyPath,verifyKeyPath});
|
|
1262
|
+
} else if (decision.action.kind === 'native_diff_apply') {
|
|
1263
|
+
await assertRunAuthority(goal.root_id);
|
|
1264
|
+
outcome=await executePreparedDiff({ctx,events,goal,state,decisionEvent,diffId:decision.action.diff_id,
|
|
1265
|
+
expectedOperationCount:decision.action.expected_operation_count,policy,codingRuntime,nativeDiffRuntime,signingKeyPath,workerScheduler});
|
|
1266
|
+
} else if (['machine_fs_mkdir','machine_fs_move','machine_fs_delete'].includes(decision.action.kind)) {
|
|
1267
|
+
await assertRunAuthority(goal.root_id);
|
|
1268
|
+
if(!machineFsRuntime) throw new Error('machine filesystem runtime unavailable');
|
|
1269
|
+
let operations;
|
|
1270
|
+
if(decision.action.kind==='machine_fs_mkdir') {
|
|
1271
|
+
operations=[{kind:'mkdir',path:decision.action.path}];
|
|
1272
|
+
} else if(decision.action.kind==='machine_fs_move') {
|
|
1273
|
+
operations=[{kind:'move',source_path:decision.action.source_path,destination_path:decision.action.destination_path,
|
|
1274
|
+
expected_source_identity:decision.action.expected_source_identity}];
|
|
1275
|
+
} else {
|
|
1276
|
+
const topology=await machineFsRuntime.state({rootId:goal.root_id,relativePath:decision.action.path});
|
|
1277
|
+
if(!topology.exists||topology.identity_sha256!==decision.action.expected_source_identity) throw new Error(`machine fs delete identity precondition mismatch '${decision.action.path}'`);
|
|
1278
|
+
if(topology.kind==='directory') operations=[{kind:'rmdir',path:decision.action.path,expected_source_identity:decision.action.expected_source_identity}];
|
|
1279
|
+
else {
|
|
1280
|
+
const file=await codingRuntime.fileState({rootId:goal.root_id,relativePath:decision.action.path});
|
|
1281
|
+
if(!file.exists||!SHA256_RE.test(file.sha256??'')) throw new Error(`machine fs delete file precondition unavailable '${decision.action.path}'`);
|
|
1282
|
+
operations=[{kind:'delete',path:decision.action.path,expected_sha256:file.sha256}];
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
outcome=await executePatch({ctx,events,goal,state,decisionEvent,decision:{operations,summary:`R36 ${decision.action.kind}`},
|
|
1286
|
+
nativeDiffRuntime,policy,codingRuntime,signingKeyPath,workerScheduler});
|
|
1287
|
+
} else if (capabilityIdForOperation(decision.action)) {
|
|
1288
|
+
outcome=await executeDelegate({ctx,events,goal,decisionEvent,
|
|
1289
|
+
decision:{operation:decision.action},policy,
|
|
1290
|
+
runtimes:{codingRuntime,semanticRuntime,nativeDiffRuntime,machineFsRuntime,observationRuntime,processRuntime},assertRunAuthority,signingKeyPath,verifyKeyPath});
|
|
1079
1291
|
} else {
|
|
1080
1292
|
throw new Error(`unsupported R34 action '${String(decision.action.kind)}'`);
|
|
1081
1293
|
}
|
|
@@ -1087,10 +1299,10 @@ async function executeR34Decision({ctx,events,goal,state,decisionEvent,decision,
|
|
|
1087
1299
|
evidence_head:loop.evidence_head_sha256,release_ready:false,
|
|
1088
1300
|
acceptance_failures:afterState.observations.filter(item=>item?.passed===false).length};
|
|
1089
1301
|
const evidence={
|
|
1090
|
-
native_diff_verified:decision.action.kind
|
|
1302
|
+
native_diff_verified:['patch','native_diff_apply','machine_fs_mkdir','machine_fs_move','machine_fs_delete'].includes(decision.action.kind) && afterState.mutation_epoch > state.mutation_epoch,
|
|
1091
1303
|
new_profile_evidence:decision.action.kind === 'run_profile' && outcome.status === 'passed' &&
|
|
1092
1304
|
afterState.observations.length > state.observations.length,
|
|
1093
|
-
diagnostic_narrowed:decision.action.kind === 'delegate' && afterState.observations.length > state.observations.length,
|
|
1305
|
+
diagnostic_narrowed:(decision.action.kind === 'delegate' || capabilityIdForOperation(decision.action)) && afterState.observations.length > state.observations.length,
|
|
1094
1306
|
interrupted_action_recovered:outcome.recovered === true
|
|
1095
1307
|
};
|
|
1096
1308
|
const progress=judgeProgress({before,after,decision,evidence});
|
|
@@ -1178,14 +1390,14 @@ async function executeR34Decision({ctx,events,goal,state,decisionEvent,decision,
|
|
|
1178
1390
|
throw new Error(`unsupported R34 decision '${String(decision.kind)}'`);
|
|
1179
1391
|
}
|
|
1180
1392
|
|
|
1181
|
-
async function
|
|
1182
|
-
nativeDiffRuntime, machineFsRuntime, observationRuntime, processRuntime, assertRunAuthority,
|
|
1183
|
-
signingKeyPath, verifyKeyPath }) {
|
|
1393
|
+
async function executeDecisionCore({ ctx, events, goal, state, decisionEvent, policy, codingRuntime,
|
|
1394
|
+
nativeDiffRuntime, machineFsRuntime, observationRuntime, processRuntime, semanticRuntime, assertRunAuthority,
|
|
1395
|
+
signingKeyPath, verifyKeyPath, workerScheduler }) {
|
|
1184
1396
|
const decision = decisionEvent.decision;
|
|
1185
1397
|
if (decision?.schema === 'deadbyte.autonomous-decision.v2') {
|
|
1186
1398
|
const outcome=await executeR34Decision({ctx,events,goal,state,decisionEvent,decision,policy,codingRuntime,
|
|
1187
|
-
nativeDiffRuntime,machineFsRuntime,observationRuntime,processRuntime,assertRunAuthority,
|
|
1188
|
-
signingKeyPath,verifyKeyPath});
|
|
1399
|
+
nativeDiffRuntime,machineFsRuntime,observationRuntime,processRuntime,semanticRuntime,assertRunAuthority,
|
|
1400
|
+
signingKeyPath,verifyKeyPath,workerScheduler});
|
|
1189
1401
|
await appendEvent(ctx,events,signingKeyPath,'decision_completed',{
|
|
1190
1402
|
decision_event_sha256:decisionEvent.event_sha256,action:decision.kind,
|
|
1191
1403
|
outcome_status:outcome.status ?? 'completed'
|
|
@@ -1215,15 +1427,15 @@ async function executeDecision({ ctx, events, goal, state, decisionEvent, policy
|
|
|
1215
1427
|
} else if (decision.action === 'patch') {
|
|
1216
1428
|
await assertRunAuthority(goal.root_id);
|
|
1217
1429
|
outcome = await executePatch({ ctx,events,goal,state,decisionEvent,decision,nativeDiffRuntime,
|
|
1218
|
-
policy,codingRuntime,signingKeyPath });
|
|
1430
|
+
policy,codingRuntime,signingKeyPath,workerScheduler });
|
|
1219
1431
|
} else if (decision.action === 'delegate') {
|
|
1220
1432
|
outcome = await executeDelegate({ ctx,events,goal,decisionEvent,decision,policy,
|
|
1221
1433
|
runtimes:{ machineFsRuntime,observationRuntime,processRuntime },assertRunAuthority,signingKeyPath,verifyKeyPath });
|
|
1222
1434
|
} else if (decision.action === 'run_profile') {
|
|
1223
1435
|
await assertRunAuthority(goal.root_id);
|
|
1224
|
-
outcome = await
|
|
1225
|
-
actionKey:`planner-${decisionEvent.event_sha256}`,
|
|
1226
|
-
epoch:state.mutation_epoch,policy,codingRuntime,signingKeyPath
|
|
1436
|
+
outcome = await executeProfileWithLease({workerScheduler,ctx,events,goal,
|
|
1437
|
+
actionKey:`planner-${decisionEvent.event_sha256}`,profileId:decision.profile_id,
|
|
1438
|
+
epoch:state.mutation_epoch,policy,codingRuntime,signingKeyPath});
|
|
1227
1439
|
} else if (decision.action === 'pause') {
|
|
1228
1440
|
await appendEvent(ctx,events,signingKeyPath,'goal_paused',{
|
|
1229
1441
|
reason:decision.reason, planner_summary:decision.summary
|
|
@@ -1245,6 +1457,83 @@ async function executeDecision({ ctx, events, goal, state, decisionEvent, policy
|
|
|
1245
1457
|
return outcome;
|
|
1246
1458
|
}
|
|
1247
1459
|
|
|
1460
|
+
function effectDescriptor(goal,state,events,decisionEvent){
|
|
1461
|
+
const decision=decisionEvent?.decision;
|
|
1462
|
+
let action=null,coordinates=null;
|
|
1463
|
+
if(decision?.schema==='deadbyte.autonomous-decision.v2'&&decision.kind==='act'){
|
|
1464
|
+
const loop=deriveLoopState(goal,events);
|
|
1465
|
+
if(!loop.plan_id||!loop.current_step?.step_id) return null;
|
|
1466
|
+
action=decision.action;
|
|
1467
|
+
coordinates={planId:loop.plan_id,stepId:loop.current_step.step_id};
|
|
1468
|
+
}else if(['patch','delegate','run_profile'].includes(decision?.action)){
|
|
1469
|
+
coordinates=patchActionCoordinates(state);
|
|
1470
|
+
if(decision.action==='patch') action={kind:'patch',operations:decision.operations};
|
|
1471
|
+
else if(decision.action==='delegate') action={kind:'delegate',operation:decision.operation};
|
|
1472
|
+
else action={kind:'run_profile',profile_id:decision.profile_id};
|
|
1473
|
+
}
|
|
1474
|
+
if(!action||!coordinates) return null;
|
|
1475
|
+
const observed=[...events].reverse().find(event=>[
|
|
1476
|
+
'inspection_completed','inspect_completed','profile_completed','delegated_action_completed','observation_completed'
|
|
1477
|
+
].includes(event.type)&&SHA256_RE.test(event.event_sha256??''))?.event_sha256 ?? state.journal_head_sha256;
|
|
1478
|
+
return {action,planId:coordinates.planId,stepId:coordinates.stepId,observationHeadSha256:observed};
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
async function executeDecision(args) {
|
|
1482
|
+
const {ctx,events,goal,state,decisionEvent,signingKeyPath}=args;
|
|
1483
|
+
const descriptor=effectDescriptor(goal,state,events,decisionEvent);
|
|
1484
|
+
if(!descriptor) return executeDecisionCore(args);
|
|
1485
|
+
const lease=issueObservationLease({goalId:goal.goal_id,mutationEpoch:state.mutation_epoch,
|
|
1486
|
+
observations:[{event_sha256:descriptor.observationHeadSha256}],ttlMs:120000});
|
|
1487
|
+
verifyObservationLease(lease,{goalId:goal.goal_id,currentMutationEpoch:state.mutation_epoch,
|
|
1488
|
+
observationHeadSha256:descriptor.observationHeadSha256});
|
|
1489
|
+
if(!events.some(event=>event.type==='observation_lease_issued'&&event.payload?.lease_id===lease.lease_id)){
|
|
1490
|
+
await appendEvent(ctx,events,signingKeyPath,'observation_lease_issued',{
|
|
1491
|
+
lease_id:lease.lease_id,mutation_epoch:lease.mutation_epoch,
|
|
1492
|
+
observation_head_sha256:lease.observation_head_sha256,expires_at_ms:lease.expires_at_ms,
|
|
1493
|
+
decision_event_sha256:decisionEvent.event_sha256
|
|
1494
|
+
});
|
|
1495
|
+
}
|
|
1496
|
+
const effect=effectIdentity({goalId:goal.goal_id,planId:descriptor.planId,stepId:descriptor.stepId,
|
|
1497
|
+
mutationEpoch:state.mutation_epoch,action:descriptor.action,observationHeadSha256:descriptor.observationHeadSha256});
|
|
1498
|
+
const guard=loopGuardDisposition(events,effect,{maxRepeats:2,window:48});
|
|
1499
|
+
if(!guard.allowed){
|
|
1500
|
+
await appendEvent(ctx,events,signingKeyPath,'effect_guard_blocked',{
|
|
1501
|
+
effect_id:effect.effect_id,fingerprint:effect.fingerprint,repeated_count:guard.repeated_count,
|
|
1502
|
+
max_repeats:guard.max_repeats,reason:guard.reason,decision_event_sha256:decisionEvent.event_sha256
|
|
1503
|
+
});
|
|
1504
|
+
await appendEvent(ctx,events,signingKeyPath,'goal_paused',{reason:'effect_repeat_limit',
|
|
1505
|
+
effect_id:effect.effect_id,fingerprint:effect.fingerprint});
|
|
1506
|
+
return {status:'paused',reason:'effect_repeat_limit'};
|
|
1507
|
+
}
|
|
1508
|
+
if(!events.some(event=>event.type==='effect_started'&&event.payload?.effect_id===effect.effect_id)){
|
|
1509
|
+
await appendEvent(ctx,events,signingKeyPath,'effect_started',{
|
|
1510
|
+
...effect,observation_lease_id:lease.lease_id,decision_event_sha256:decisionEvent.event_sha256
|
|
1511
|
+
});
|
|
1512
|
+
}
|
|
1513
|
+
try{
|
|
1514
|
+
const outcome=await executeDecisionCore(args);
|
|
1515
|
+
if(!events.some(event=>['effect_completed','effect_failed'].includes(event.type)&&event.payload?.effect_id===effect.effect_id)){
|
|
1516
|
+
const completion=bindEffectCompletion(effect,{status:outcome?.status??'completed',
|
|
1517
|
+
mutation_epoch:deriveState(goal,events).mutation_epoch,observation_lease_id:lease.lease_id});
|
|
1518
|
+
await appendEvent(ctx,events,signingKeyPath,'effect_completed',{
|
|
1519
|
+
...completion,observation_lease_id:lease.lease_id,decision_event_sha256:decisionEvent.event_sha256,
|
|
1520
|
+
outcome_status:outcome?.status??'completed'
|
|
1521
|
+
});
|
|
1522
|
+
}
|
|
1523
|
+
return outcome;
|
|
1524
|
+
}catch(error){
|
|
1525
|
+
if(!events.some(event=>['effect_completed','effect_failed'].includes(event.type)&&event.payload?.effect_id===effect.effect_id)){
|
|
1526
|
+
const completion=bindEffectCompletion(effect,{status:'failed',error:truncated(error,512),
|
|
1527
|
+
mutation_epoch:deriveState(goal,events).mutation_epoch,observation_lease_id:lease.lease_id});
|
|
1528
|
+
await appendEvent(ctx,events,signingKeyPath,'effect_failed',{
|
|
1529
|
+
...completion,observation_lease_id:lease.lease_id,decision_event_sha256:decisionEvent.event_sha256,
|
|
1530
|
+
detail:truncated(error,512)
|
|
1531
|
+
});
|
|
1532
|
+
}
|
|
1533
|
+
throw error;
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1248
1537
|
function terminalState(state) {
|
|
1249
1538
|
return ['succeeded','cancelled'].includes(state.state);
|
|
1250
1539
|
}
|
|
@@ -1269,9 +1558,13 @@ function isAuthorityUnavailable(error) {
|
|
|
1269
1558
|
}
|
|
1270
1559
|
|
|
1271
1560
|
export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRuntime, machineFsRuntime = null,
|
|
1272
|
-
observationRuntime = null, processRuntime = null, signingKeyPath, verifyKeyPath }) {
|
|
1561
|
+
observationRuntime = null, processRuntime = null, semanticRuntime = null, signingKeyPath, verifyKeyPath }) {
|
|
1273
1562
|
if (!policy || !codingRuntime || !nativeDiffRuntime) throw new Error('autonomous runtime requires policy/coding/native-diff runtimes');
|
|
1274
1563
|
if (!signingKeyPath || !verifyKeyPath) throw new Error('autonomous runtime requires trust keys');
|
|
1564
|
+
const capabilityManifest=configuredCapabilityManifest({machineFsRuntime,observationRuntime,processRuntime,semanticRuntime});
|
|
1565
|
+
const profileTimeoutCeiling=Math.max(120000,...Object.values(policy.profiles??{}).map(profile=>
|
|
1566
|
+
Number.isInteger(profile?.timeout_ms)&&profile.timeout_ms>0?profile.timeout_ms+120000:120000));
|
|
1567
|
+
const workerScheduler=createWorkerScheduler({maxConcurrent:2,totalCpuUnits:2,totalMemoryMb:2048,leaseMs:profileTimeoutCeiling});
|
|
1275
1568
|
async function sessionStatus() {
|
|
1276
1569
|
const autonomous = await autonomousSessionStatus(policy);
|
|
1277
1570
|
const coding = await codingRuntime.sessionStatus();
|
|
@@ -1330,8 +1623,9 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
|
|
|
1330
1623
|
const journal = await readEvents(ctx,verifyKeyPath);
|
|
1331
1624
|
const derived = deriveState(goal,journal);
|
|
1332
1625
|
const loop = publicLoopState(loopStateOrNull(goal,journal));
|
|
1626
|
+
const lock=await runLockStatus(ctx);
|
|
1333
1627
|
return { status:'ok', goal_id:goalId, goal_sha256:goal.goal_sha256,
|
|
1334
|
-
title:goal.title, root_id:goal.root_id, journal_verified:true, ...derived,
|
|
1628
|
+
title:goal.title, root_id:goal.root_id, journal_verified:true, ...derived, ...lock,
|
|
1335
1629
|
...(loop ? {loop} : {}) };
|
|
1336
1630
|
}
|
|
1337
1631
|
|
|
@@ -1407,7 +1701,7 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
|
|
|
1407
1701
|
}
|
|
1408
1702
|
state = deriveState(goal,journal);
|
|
1409
1703
|
const profiles = await runRequiredReleaseProfiles({ ctx,events:journal,goal,state,
|
|
1410
|
-
policy,codingRuntime,signingKeyPath });
|
|
1704
|
+
policy,codingRuntime,signingKeyPath,workerScheduler });
|
|
1411
1705
|
if (profiles.some(item => item.status === 'paused')) {
|
|
1412
1706
|
return { status:'paused', goal_id:goal.goal_id, ready:false,
|
|
1413
1707
|
reason:'release_profile_interrupted', mutation_epoch:state.mutation_epoch };
|
|
@@ -1488,7 +1782,7 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
|
|
|
1488
1782
|
try {
|
|
1489
1783
|
outcome = await executeDecision({ ctx,events:journal,goal,state,
|
|
1490
1784
|
decisionEvent:state.pending_decision,policy,codingRuntime,nativeDiffRuntime,machineFsRuntime,
|
|
1491
|
-
observationRuntime,processRuntime,assertRunAuthority,signingKeyPath,verifyKeyPath });
|
|
1785
|
+
observationRuntime,processRuntime,semanticRuntime,assertRunAuthority,signingKeyPath,verifyKeyPath,workerScheduler });
|
|
1492
1786
|
} catch (error) {
|
|
1493
1787
|
const loop=loopStateOrNull(goal,journal);
|
|
1494
1788
|
if (!loop || loop.pending_action || !isAuthorityUnavailable(error)) throw error;
|
|
@@ -1512,7 +1806,7 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
|
|
|
1512
1806
|
}
|
|
1513
1807
|
continue;
|
|
1514
1808
|
}
|
|
1515
|
-
const accepted = await acceptPlannerDecision({ ctx,events:journal,goal,state,policy,codingRuntime,
|
|
1809
|
+
const accepted = await acceptPlannerDecision({ ctx,events:journal,goal,state,policy,codingRuntime,capabilityManifest,
|
|
1516
1810
|
signingKeyPath,plannerResponse:suppliedResponse });
|
|
1517
1811
|
suppliedResponse = null;
|
|
1518
1812
|
if (accepted?.needs_planner) {
|