deadbyte-mcp 0.10.0 → 0.11.1
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 +81 -59
- package/README.txt +13 -14
- 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 +3 -3
- package/controller/deadbyte-controller.ps1 +1 -1
- package/controller/deadbyte-process-policy.json +1 -1
- package/docs/ARCHITECTURE.md +1 -1
- package/package.json +1 -1
- package/scripts/build-containment.ps1 +15 -15
- package/scripts/deferred-slot-operation-r37-0110.mjs +124 -0
- package/scripts/deferred-slot-operation.mjs +1 -1
- package/scripts/final-closure-r36.mjs +113 -0
- package/scripts/final-closure-r37-0110.mjs +113 -0
- package/scripts/final-closure-verify-r36.mjs +208 -0
- package/scripts/final-closure-verify-r37-0110.mjs +208 -0
- package/scripts/final-closure-verify.mjs +48 -48
- package/scripts/final-closure.mjs +13 -13
- package/scripts/gate-windows-r36.ps1 +42 -0
- package/scripts/gate-windows-r37-0110.ps1 +42 -0
- package/scripts/gate-windows.ps1 +3 -3
- package/scripts/release-parity-r36.mjs +200 -0
- package/scripts/release-parity-r37-0110.mjs +200 -0
- package/scripts/release-parity-tests.ps1 +2 -2
- package/scripts/release-parity.mjs +37 -37
- package/scripts/windows-gate-evidence-r36.mjs +52 -0
- package/scripts/windows-gate-evidence-r37-0110.mjs +52 -0
- package/scripts/windows-gate-evidence.mjs +5 -5
- package/src/agent-memory-plane.mjs +98 -0
- package/src/autonomous-output-contracts.mjs +5 -2
- package/src/autonomous-runtime.mjs +155 -31
- package/src/autonomous-timeout-recovery.mjs +27 -0
- package/src/deadbyte-cli.mjs +90 -94
- package/src/effect-ledger.mjs +47 -0
- package/src/observation-lease.mjs +32 -0
- package/src/remote-live-log.mjs +81 -0
- package/src/remote-mcp-autonomous-smoke-client.mjs +15 -9
- package/src/remote-result-journal.mjs +23 -4
- package/src/version.mjs +1 -1
- package/src/worker-scheduler.mjs +53 -0
- package/test/autonomous-output-contract.test.mjs +1 -1
- package/test/cli-entrypoint.test.mjs +9 -0
- package/test/containment.test.mjs +18 -0
- package/test/core.test.mjs +1 -1
- package/test/production-docs.test.mjs +5 -5
- package/test/r33-closeout-regression.test.mjs +4 -4
- package/test/r33-finalization.test.mjs +6 -6
- package/test/r36-finalization.test.mjs +5 -5
- package/test/r36-release-identity.test.mjs +12 -19
- package/test/r37-0110-history.test.mjs +20 -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/r37-remote-tool-call-timeline.test.mjs +94 -0
- package/test/release-version.test.mjs +35 -36
- package/test/remote-live-log-r37.test.mjs +50 -0
- package/test/remote-session-cli.test.mjs +86 -68
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { mkdir, open, readFile } from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
|
|
7
|
+
const here=path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
const root=path.resolve(here,'..');
|
|
9
|
+
const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
10
|
+
const marker='DEADBYTE V0.11.0 / R37 WINDOWS BATCH GATE: PASS';
|
|
11
|
+
function insist(ok,message){if(!ok) throw new Error(message);}
|
|
12
|
+
|
|
13
|
+
export async function writeWindowsGateEvidence({
|
|
14
|
+
candidateRoot=root,
|
|
15
|
+
stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp')),
|
|
16
|
+
clock=()=>new Date()
|
|
17
|
+
}={}){
|
|
18
|
+
const candidate=path.resolve(candidateRoot);
|
|
19
|
+
const manifestBytes=await readFile(path.join(candidate,'MANIFEST.SHA256'));
|
|
20
|
+
const manifestSha256=sha256(manifestBytes);
|
|
21
|
+
const pkg=JSON.parse(await readFile(path.join(candidate,'package.json'),'utf8'));
|
|
22
|
+
insist(pkg.version==='0.11.0',`Windows gate evidence requires V0.11.0, found ${pkg.version}`);
|
|
23
|
+
const completed=clock();
|
|
24
|
+
insist(completed instanceof Date&&!Number.isNaN(completed.getTime()),'Windows gate evidence clock invalid');
|
|
25
|
+
const evidence={
|
|
26
|
+
schema:'deadbyte.r37-windows-gate.v1',status:'passed',exit_code:0,version:'0.11.0',
|
|
27
|
+
marker,completed_at_utc:completed.toISOString(),manifest_sha256:manifestSha256
|
|
28
|
+
};
|
|
29
|
+
const bytes=Buffer.from(`${JSON.stringify(evidence,null,2)}\n`,'utf8');
|
|
30
|
+
const dir=path.join(path.resolve(stateRoot),'evidence','release');
|
|
31
|
+
await mkdir(dir,{recursive:true});
|
|
32
|
+
const file=path.join(dir,`r37-windows-gate-${manifestSha256.slice(0,16)}.json`);
|
|
33
|
+
try{
|
|
34
|
+
const handle=await open(file,'wx',0o600);
|
|
35
|
+
try{await handle.writeFile(bytes);await handle.sync();}finally{await handle.close();}
|
|
36
|
+
return {status:'written',path:file,sha256:sha256(bytes),manifest_sha256:manifestSha256};
|
|
37
|
+
}catch(error){
|
|
38
|
+
if(error?.code!=='EEXIST') throw error;
|
|
39
|
+
const existingBytes=await readFile(file);
|
|
40
|
+
const existing=JSON.parse(existingBytes.toString('utf8'));
|
|
41
|
+
insist(existing.schema===evidence.schema&&existing.status==='passed'&&existing.exit_code===0,'existing Windows gate evidence invalid');
|
|
42
|
+
insist(existing.version==='0.11.0'&&existing.marker===marker&&existing.manifest_sha256===manifestSha256,'existing Windows gate evidence binding mismatch');
|
|
43
|
+
return {status:'existing',path:file,sha256:sha256(existingBytes),manifest_sha256:manifestSha256};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const invoked=process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url);
|
|
48
|
+
if(invoked){
|
|
49
|
+
writeWindowsGateEvidence()
|
|
50
|
+
.then(result=>console.log(JSON.stringify(result)))
|
|
51
|
+
.catch(error=>{console.error(error instanceof Error?error.stack:String(error));process.exitCode=1;});
|
|
52
|
+
}
|
|
@@ -7,7 +7,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
7
7
|
const here=path.dirname(fileURLToPath(import.meta.url));
|
|
8
8
|
const root=path.resolve(here,'..');
|
|
9
9
|
const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
10
|
-
const marker='DEADBYTE V0.
|
|
10
|
+
const marker='DEADBYTE V0.11.1 / R37 WINDOWS BATCH GATE: PASS';
|
|
11
11
|
function insist(ok,message){if(!ok) throw new Error(message);}
|
|
12
12
|
|
|
13
13
|
export async function writeWindowsGateEvidence({
|
|
@@ -19,17 +19,17 @@ export async function writeWindowsGateEvidence({
|
|
|
19
19
|
const manifestBytes=await readFile(path.join(candidate,'MANIFEST.SHA256'));
|
|
20
20
|
const manifestSha256=sha256(manifestBytes);
|
|
21
21
|
const pkg=JSON.parse(await readFile(path.join(candidate,'package.json'),'utf8'));
|
|
22
|
-
insist(pkg.version==='0.
|
|
22
|
+
insist(pkg.version==='0.11.1',`Windows gate evidence requires V0.11.1, found ${pkg.version}`);
|
|
23
23
|
const completed=clock();
|
|
24
24
|
insist(completed instanceof Date&&!Number.isNaN(completed.getTime()),'Windows gate evidence clock invalid');
|
|
25
25
|
const evidence={
|
|
26
|
-
schema:'deadbyte.
|
|
26
|
+
schema:'deadbyte.r37-windows-gate.v1',status:'passed',exit_code:0,version:'0.11.1',
|
|
27
27
|
marker,completed_at_utc:completed.toISOString(),manifest_sha256:manifestSha256
|
|
28
28
|
};
|
|
29
29
|
const bytes=Buffer.from(`${JSON.stringify(evidence,null,2)}\n`,'utf8');
|
|
30
30
|
const dir=path.join(path.resolve(stateRoot),'evidence','release');
|
|
31
31
|
await mkdir(dir,{recursive:true});
|
|
32
|
-
const file=path.join(dir,`
|
|
32
|
+
const file=path.join(dir,`r37-windows-gate-${manifestSha256.slice(0,16)}.json`);
|
|
33
33
|
try{
|
|
34
34
|
const handle=await open(file,'wx',0o600);
|
|
35
35
|
try{await handle.writeFile(bytes);await handle.sync();}finally{await handle.close();}
|
|
@@ -39,7 +39,7 @@ export async function writeWindowsGateEvidence({
|
|
|
39
39
|
const existingBytes=await readFile(file);
|
|
40
40
|
const existing=JSON.parse(existingBytes.toString('utf8'));
|
|
41
41
|
insist(existing.schema===evidence.schema&&existing.status==='passed'&&existing.exit_code===0,'existing Windows gate evidence invalid');
|
|
42
|
-
insist(existing.version==='0.
|
|
42
|
+
insist(existing.version==='0.11.1'&&existing.marker===marker&&existing.manifest_sha256===manifestSha256,'existing Windows gate evidence binding mismatch');
|
|
43
43
|
return {status:'existing',path:file,sha256:sha256(existingBytes),manifest_sha256:manifestSha256};
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { canonicalJson } from './canonical-json.mjs';
|
|
3
|
+
|
|
4
|
+
export const AGENT_MEMORY_SCHEMA='deadbyte.agent-memory.v1';
|
|
5
|
+
const HEX64=/^[0-9a-f]{64}$/;
|
|
6
|
+
const sha=value=>createHash('sha256').update(Buffer.from(canonicalJson(value),'utf8')).digest('hex');
|
|
7
|
+
const uniq=values=>[...new Set(values.filter(v=>typeof v==='string'&&v.length>0))];
|
|
8
|
+
|
|
9
|
+
function tokens(text){return uniq(String(text??'').toLowerCase().split(/[^a-z0-9_.\/-]+/).filter(x=>x.length>1));}
|
|
10
|
+
function compactEvent(event){
|
|
11
|
+
const p=event?.payload&&typeof event.payload==='object'?event.payload:{};
|
|
12
|
+
const safe={seq:event?.seq??null,type:event?.type??'unknown',event_sha256:HEX64.test(event?.event_sha256??'')?event.event_sha256:null};
|
|
13
|
+
for(const key of ['reason','profile_id','mutation_epoch','receipt_sha256','diff_receipt_sha256','action_key']){
|
|
14
|
+
if(p[key]!==undefined) safe[key]=p[key];
|
|
15
|
+
}
|
|
16
|
+
if(Array.isArray(p.paths)) safe.paths=p.paths.filter(x=>typeof x==='string').slice(0,32);
|
|
17
|
+
return safe;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function deriveAgentMemory(events,{maxArchival=96}={}){
|
|
21
|
+
if(!Array.isArray(events)) throw new Error('memory events must be array');
|
|
22
|
+
const acceptance=[],proven=[],rejected=[],blockers=new Set(),files=new Map(),profiles=new Map();
|
|
23
|
+
const archival=[];
|
|
24
|
+
for(const event of events){
|
|
25
|
+
const p=event?.payload&&typeof event.payload==='object'?event.payload:{};
|
|
26
|
+
if(event?.type==='goal_created'&&typeof p.acceptance==='string'&&p.acceptance) acceptance.push(p.acceptance);
|
|
27
|
+
if(event?.type==='profile_completed'&&typeof p.profile_id==='string'){
|
|
28
|
+
profiles.set(p.profile_id,{id:`profile:${p.profile_id}`,kind:'profile',label:p.profile_id,passed:p.passed===true,
|
|
29
|
+
receipt_sha256:HEX64.test(p.receipt_sha256??'')?p.receipt_sha256:null});
|
|
30
|
+
if(p.passed===true){proven.push(`${p.profile_id}:passed`);blockers.delete(`profile:${p.profile_id}`);}
|
|
31
|
+
else blockers.add(`profile:${p.profile_id}`);
|
|
32
|
+
}
|
|
33
|
+
if(event?.type==='native_diff_committed'){
|
|
34
|
+
for(const file of p.paths??[]) if(typeof file==='string'&&file) files.set(file,{id:`file:${file}`,kind:'file',label:file});
|
|
35
|
+
}
|
|
36
|
+
if(event?.type==='planner_rejected'&&typeof p.reason==='string') rejected.push(p.reason);
|
|
37
|
+
if(event?.type==='waiting_entered'&&typeof p.reason==='string') blockers.add(`wait:${p.reason}`);
|
|
38
|
+
if(event?.type==='waiting_resumed'&&typeof p.previous_reason==='string') blockers.delete(`wait:${p.previous_reason}`);
|
|
39
|
+
if(['planner_rejected','profile_completed','native_diff_committed','waiting_entered','waiting_resumed','release_completed'].includes(event?.type)){
|
|
40
|
+
archival.push(compactEvent(event));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const core={acceptance_constraints:uniq(acceptance),proven_invariants:uniq(proven),
|
|
44
|
+
rejected_approaches:uniq(rejected),unresolved_blockers:[...blockers].sort()};
|
|
45
|
+
const nodes=[
|
|
46
|
+
{id:'goal:current',kind:'goal',label:core.acceptance_constraints.join(' | ')||'current goal'},
|
|
47
|
+
...[...files.values()].sort((a,b)=>a.id.localeCompare(b.id,'en')),
|
|
48
|
+
...[...profiles.values()].sort((a,b)=>a.id.localeCompare(b.id,'en')),
|
|
49
|
+
...core.unresolved_blockers.map(id=>({id:`blocker:${id}`,kind:'blocker',label:id}))
|
|
50
|
+
];
|
|
51
|
+
const edges=[];
|
|
52
|
+
for(const node of nodes){
|
|
53
|
+
if(node.id==='goal:current') continue;
|
|
54
|
+
edges.push({source:'goal:current',target:node.id,kind:node.kind==='file'?'touches':node.kind==='profile'?'verified_by':'blocked_by'});
|
|
55
|
+
}
|
|
56
|
+
const body={schema:AGENT_MEMORY_SCHEMA,core,archival:archival.slice(-maxArchival),graph:{nodes,edges}};
|
|
57
|
+
return Object.freeze({...body,memory_sha256:sha(body)});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function score(value,needles){
|
|
61
|
+
const text=JSON.stringify(value).toLowerCase();
|
|
62
|
+
return needles.reduce((n,t)=>n+(text.includes(t)?1:0),0);
|
|
63
|
+
}
|
|
64
|
+
function ranked(values,needles,limit){
|
|
65
|
+
return values.map(value=>({value,score:score(value,needles)})).filter(x=>x.score>0)
|
|
66
|
+
.sort((a,b)=>b.score-a.score||JSON.stringify(a.value).localeCompare(JSON.stringify(b.value),'en'))
|
|
67
|
+
.slice(0,limit).map(x=>x.value);
|
|
68
|
+
}
|
|
69
|
+
export function queryAgentMemory(memory,{query,mode='local',limit=12}={}){
|
|
70
|
+
if(!memory||memory.schema!==AGENT_MEMORY_SCHEMA) throw new Error('memory snapshot invalid');
|
|
71
|
+
if(!['local','global','drift'].includes(mode)) throw new Error('memory query mode invalid');
|
|
72
|
+
if(!Number.isInteger(limit)||limit<1||limit>128) throw new Error('memory query limit invalid');
|
|
73
|
+
const needles=tokens(query);
|
|
74
|
+
let results=[];
|
|
75
|
+
if(mode==='global'){
|
|
76
|
+
results=[
|
|
77
|
+
{kind:'core',...memory.core},
|
|
78
|
+
{kind:'graph_summary',node_count:memory.graph.nodes.length,edge_count:memory.graph.edges.length,
|
|
79
|
+
node_kinds:Object.fromEntries([...new Set(memory.graph.nodes.map(n=>n.kind))].sort().map(k=>[k,memory.graph.nodes.filter(n=>n.kind===k).length]))}
|
|
80
|
+
];
|
|
81
|
+
if(needles.length) results=ranked([...results,...memory.archival],needles,limit);
|
|
82
|
+
else results=results.slice(0,limit);
|
|
83
|
+
}else{
|
|
84
|
+
const local=ranked([...memory.graph.nodes,...memory.archival],needles,limit);
|
|
85
|
+
results=[...local];
|
|
86
|
+
if(mode==='drift'){
|
|
87
|
+
const ids=new Set(local.filter(x=>x?.id).map(x=>x.id));
|
|
88
|
+
const neighborIds=new Set();
|
|
89
|
+
for(const edge of memory.graph.edges){
|
|
90
|
+
if(ids.has(edge.source)) neighborIds.add(edge.target);
|
|
91
|
+
if(ids.has(edge.target)) neighborIds.add(edge.source);
|
|
92
|
+
}
|
|
93
|
+
for(const node of memory.graph.nodes) if(neighborIds.has(node.id)&&!results.some(x=>x?.id===node.id)) results.push(node);
|
|
94
|
+
results=results.slice(0,limit);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return Object.freeze({schema:'deadbyte.agent-memory-query.v1',mode,query:String(query??''),memory_sha256:memory.memory_sha256,results});
|
|
98
|
+
}
|
|
@@ -98,9 +98,12 @@ export const autonomousGoalRunOutputSchema = z.strictObject({
|
|
|
98
98
|
if (value.status === 'input_required') requireFields(value,ctx,['planner_request']);
|
|
99
99
|
});
|
|
100
100
|
export const autonomousGoalStatusOutputSchema = statusContract({
|
|
101
|
-
statuses:['ok','failed'], success:['ok'], required:['goal_id','goal_sha256','title','root_id','journal_verified'
|
|
101
|
+
statuses:['ok','failed'], success:['ok'], required:['goal_id','goal_sha256','title','root_id','journal_verified',
|
|
102
|
+
'run_busy','run_owner_pid','run_lock_created_at_utc',...Object.keys(derivedShape)],
|
|
102
103
|
shape:{ goal_id:goalId.optional(), goal_sha256:hex64.optional(), title:z.string().optional(), root_id:z.string().optional(),
|
|
103
|
-
journal_verified:z.literal(true).optional(),
|
|
104
|
+
journal_verified:z.literal(true).optional(), run_busy:z.boolean().optional(),
|
|
105
|
+
run_owner_pid:z.number().int().min(1).nullable().optional(),
|
|
106
|
+
run_lock_created_at_utc:z.string().nullable().optional(), loop:publicLoopSchema.optional(), ...runShape }
|
|
104
107
|
});
|
|
105
108
|
export const autonomousGoalEventsOutputSchema = statusContract({
|
|
106
109
|
statuses:['ok','failed'], success:['ok'], required:['goal_id','journal_verified','journal_head_sha256','events'],
|
|
@@ -12,6 +12,10 @@ 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
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';
|
|
15
19
|
|
|
16
20
|
export const AUTONOMOUS_GOAL_SCHEMA = 'deadbyte.autonomous-goal.v1';
|
|
17
21
|
export const AUTONOMOUS_EVENT_SCHEMA = 'deadbyte.autonomous-event.v1';
|
|
@@ -164,6 +168,22 @@ async function acquireLock(ctx) {
|
|
|
164
168
|
throw new Error('autonomous lock acquisition failed');
|
|
165
169
|
}
|
|
166
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
|
+
}
|
|
167
187
|
async function readCancel(ctx, verifyKeyPath) {
|
|
168
188
|
if (!await exists(ctx.cancelPath)) return null;
|
|
169
189
|
const parsed = JSON.parse(await readFile(ctx.cancelPath,'utf8'));
|
|
@@ -339,11 +359,12 @@ function configuredCapabilityManifest({machineFsRuntime,observationRuntime,proce
|
|
|
339
359
|
entries:Object.freeze(entries)});
|
|
340
360
|
}
|
|
341
361
|
|
|
342
|
-
async function plannerView(goal, state, codingRuntime, capabilityManifest) {
|
|
362
|
+
async function plannerView(goal, state, events, codingRuntime, capabilityManifest) {
|
|
343
363
|
const tree = await codingRuntime.tree({ rootId:goal.root_id, path:'.', maxDepth:4, maxEntries:600 });
|
|
364
|
+
const memory=deriveAgentMemory(events,{maxArchival:24});
|
|
344
365
|
return { mutation_epoch:state.mutation_epoch, planner_round:state.planner_round, tree:tree.entries,
|
|
345
366
|
contexts:state.contexts.slice(-16), observations:state.observations.slice(-24), active_plan:state.active_plan,
|
|
346
|
-
capabilities:capabilityManifest,
|
|
367
|
+
capabilities:capabilityManifest, project_memory:memory,
|
|
347
368
|
recent_decisions:state.decisions.slice(-8).map(item => ({ planner_round:item.planner_round,
|
|
348
369
|
action:item.decision?.action, summary:item.decision?.summary })) };
|
|
349
370
|
}
|
|
@@ -361,7 +382,7 @@ async function requestPlanner(ctx, goal, events, state, policy, codingRuntime, c
|
|
|
361
382
|
await appendEvent(ctx,events,signingKeyPath,'goal_paused',{ reason:'wall_time_limit', max_wall_ms:policy.limits.max_wall_ms });
|
|
362
383
|
return null;
|
|
363
384
|
}
|
|
364
|
-
const view = await plannerView(goal,state,codingRuntime,capabilityManifest);
|
|
385
|
+
const view = await plannerView(goal,state,events,codingRuntime,capabilityManifest);
|
|
365
386
|
let prompt = buildPlannerPrompt({ goal:{ title:goal.title, goal:goal.goal, acceptance:goal.acceptance }, policy, view });
|
|
366
387
|
const repair = [...(state.planner_rejections ?? [])].reverse().find(item => item.planner_round === round) ?? null;
|
|
367
388
|
if (repair) {
|
|
@@ -749,14 +770,36 @@ async function executeDelegate({ ctx, events, goal, decisionEvent, decision, pol
|
|
|
749
770
|
}
|
|
750
771
|
}
|
|
751
772
|
|
|
752
|
-
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 }) {
|
|
753
796
|
const profileIds = Object.entries(policy.profiles)
|
|
754
797
|
.filter(([,profile]) => profile.run_after_mutation)
|
|
755
798
|
.map(([id]) => id);
|
|
756
799
|
const results = [];
|
|
757
800
|
for (const profileId of profileIds) {
|
|
758
|
-
const result = await
|
|
759
|
-
profileId,
|
|
801
|
+
const result = await executeProfileWithLease({workerScheduler,ctx,events,goal,epoch,
|
|
802
|
+
actionKey:`${actionKey}:${profileId}`,profileId,policy,codingRuntime,signingKeyPath});
|
|
760
803
|
results.push({ profile_id:profileId, status:result.status, observation:result.observation });
|
|
761
804
|
if (result.status === 'paused') break;
|
|
762
805
|
}
|
|
@@ -817,7 +860,7 @@ async function appendPatchCommit({ctx,events,signingKeyPath,started,decisionEven
|
|
|
817
860
|
});
|
|
818
861
|
}
|
|
819
862
|
async function executePatch({ ctx, events, goal, state, decisionEvent, decision, nativeDiffRuntime,
|
|
820
|
-
policy, codingRuntime, signingKeyPath, actionCoordinatesOverride = null }) {
|
|
863
|
+
policy, codingRuntime, signingKeyPath, workerScheduler, actionCoordinatesOverride = null }) {
|
|
821
864
|
let started = patchStartedForDecision(events,decisionEvent.event_sha256);
|
|
822
865
|
if (!started && state.mutation_count + decision.operations.length > policy.limits.max_mutations) {
|
|
823
866
|
await appendEvent(ctx,events,signingKeyPath,'goal_paused',{
|
|
@@ -853,7 +896,7 @@ async function executePatch({ ctx, events, goal, state, decisionEvent, decision,
|
|
|
853
896
|
if (!committed) throw new Error('completed patch action missing native diff commit');
|
|
854
897
|
const epoch = committed.payload.mutation_epoch;
|
|
855
898
|
const profiles = await runMutationProfiles({ ctx,events,goal,epoch,
|
|
856
|
-
actionKey:`mutation-${epoch}`,policy,codingRuntime,signingKeyPath });
|
|
899
|
+
actionKey:`mutation-${epoch}`,policy,codingRuntime,signingKeyPath,workerScheduler });
|
|
857
900
|
return { status:profiles.some(item => item.status === 'paused') ? 'paused' : 'completed',
|
|
858
901
|
diff_id:diffId, mutation_epoch:epoch, profiles, recovered:true };
|
|
859
902
|
}
|
|
@@ -901,12 +944,12 @@ async function executePatch({ ctx, events, goal, state, decisionEvent, decision,
|
|
|
901
944
|
}
|
|
902
945
|
const epoch = committed.payload.mutation_epoch;
|
|
903
946
|
const profiles = await runMutationProfiles({ ctx,events,goal,epoch,
|
|
904
|
-
actionKey:`mutation-${epoch}`,policy,codingRuntime,signingKeyPath });
|
|
947
|
+
actionKey:`mutation-${epoch}`,policy,codingRuntime,signingKeyPath,workerScheduler });
|
|
905
948
|
return { status:profiles.some(item => item.status === 'paused') ? 'paused' : 'completed',
|
|
906
949
|
diff_id:diffId, mutation_epoch:epoch, profiles, recovered };
|
|
907
950
|
}
|
|
908
951
|
async function executePreparedDiff({ctx,events,goal,state,decisionEvent,diffId,expectedOperationCount,
|
|
909
|
-
policy,codingRuntime,nativeDiffRuntime,signingKeyPath}) {
|
|
952
|
+
policy,codingRuntime,nativeDiffRuntime,signingKeyPath,workerScheduler}) {
|
|
910
953
|
let started=patchStartedForDecision(events,decisionEvent.event_sha256);
|
|
911
954
|
if(!started&&state.mutation_count+expectedOperationCount>policy.limits.max_mutations){
|
|
912
955
|
await appendEvent(ctx,events,signingKeyPath,'goal_paused',{reason:'mutation_limit',max_mutations:policy.limits.max_mutations});
|
|
@@ -929,7 +972,7 @@ async function executePreparedDiff({ctx,events,goal,state,decisionEvent,diffId,e
|
|
|
929
972
|
const committed=patchCommitForAction(events,actionId);
|
|
930
973
|
if(!committed) throw new Error('completed prepared diff action missing native diff commit');
|
|
931
974
|
const epoch=committed.payload.mutation_epoch;
|
|
932
|
-
const profiles=await runMutationProfiles({ctx,events,goal,epoch,actionKey:`mutation-${epoch}`,policy,codingRuntime,signingKeyPath});
|
|
975
|
+
const profiles=await runMutationProfiles({ctx,events,goal,epoch,actionKey:`mutation-${epoch}`,policy,codingRuntime,signingKeyPath,workerScheduler});
|
|
933
976
|
return {status:profiles.some(item=>item.status==='paused')?'paused':'completed',diff_id:diffId,mutation_epoch:epoch,profiles,recovered:true};
|
|
934
977
|
}
|
|
935
978
|
const reconciliation=await reconcileStartedAction({startedEvent:started,journal:events,runtimes:{nativeDiffRuntime,codingRuntime}});
|
|
@@ -963,10 +1006,10 @@ async function executePreparedDiff({ctx,events,goal,state,decisionEvent,diffId,e
|
|
|
963
1006
|
receipt_sha256:verified.receipt_sha256,recovered});
|
|
964
1007
|
}
|
|
965
1008
|
const epoch=committed.payload.mutation_epoch;
|
|
966
|
-
const profiles=await runMutationProfiles({ctx,events,goal,epoch,actionKey:`mutation-${epoch}`,policy,codingRuntime,signingKeyPath});
|
|
1009
|
+
const profiles=await runMutationProfiles({ctx,events,goal,epoch,actionKey:`mutation-${epoch}`,policy,codingRuntime,signingKeyPath,workerScheduler});
|
|
967
1010
|
return {status:profiles.some(item=>item.status==='paused')?'paused':'completed',diff_id:diffId,mutation_epoch:epoch,profiles,recovered};
|
|
968
1011
|
}
|
|
969
|
-
async function runRequiredReleaseProfiles({ ctx, events, goal, state, policy, codingRuntime, signingKeyPath }) {
|
|
1012
|
+
async function runRequiredReleaseProfiles({ ctx, events, goal, state, policy, codingRuntime, signingKeyPath, workerScheduler }) {
|
|
970
1013
|
const requiredIds = Object.entries(policy.profiles)
|
|
971
1014
|
.filter(([,profile]) => profile.required_for_release)
|
|
972
1015
|
.map(([id]) => id);
|
|
@@ -977,9 +1020,9 @@ async function runRequiredReleaseProfiles({ ctx, events, goal, state, policy, co
|
|
|
977
1020
|
results.push({ profile_id:profileId, status:'passed', observation:existing, existing:true });
|
|
978
1021
|
continue;
|
|
979
1022
|
}
|
|
980
|
-
const result = await
|
|
981
|
-
actionKey:`release-${state.mutation_epoch}:${profileId}`,
|
|
982
|
-
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});
|
|
983
1026
|
results.push({ profile_id:profileId, ...result });
|
|
984
1027
|
if (result.status === 'paused') break;
|
|
985
1028
|
}
|
|
@@ -1153,7 +1196,7 @@ function r34ReasonHash(goal,decisionEvent,reason) {
|
|
|
1153
1196
|
}
|
|
1154
1197
|
async function executeR34Decision({ctx,events,goal,state,decisionEvent,decision,policy,codingRuntime,
|
|
1155
1198
|
nativeDiffRuntime,machineFsRuntime,observationRuntime,processRuntime,semanticRuntime,assertRunAuthority,
|
|
1156
|
-
signingKeyPath,verifyKeyPath}) {
|
|
1199
|
+
signingKeyPath,verifyKeyPath,workerScheduler}) {
|
|
1157
1200
|
let loop=deriveLoopState(goal,events);
|
|
1158
1201
|
if (decision.kind === 'plan_create') {
|
|
1159
1202
|
if (loop.phase !== 'PLAN' || loop.plan) throw new Error('R34 plan_create requires empty PLANNING state');
|
|
@@ -1196,7 +1239,7 @@ async function executeR34Decision({ctx,events,goal,state,decisionEvent,decision,
|
|
|
1196
1239
|
try {
|
|
1197
1240
|
outcome=await executePatch({ctx,events,goal,state,decisionEvent,
|
|
1198
1241
|
decision:{operations:decision.action.operations,summary:`R34 ${currentStep.step_id}`},nativeDiffRuntime,
|
|
1199
|
-
policy,codingRuntime,signingKeyPath,actionCoordinatesOverride:{planId:loop.plan_id,
|
|
1242
|
+
policy,codingRuntime,signingKeyPath,workerScheduler,actionCoordinatesOverride:{planId:loop.plan_id,
|
|
1200
1243
|
planVersion:loop.plan_version,stepId:currentStep.step_id}});
|
|
1201
1244
|
} catch (error) {
|
|
1202
1245
|
const detail=truncated(error,512);
|
|
@@ -1209,7 +1252,7 @@ async function executeR34Decision({ctx,events,goal,state,decisionEvent,decision,
|
|
|
1209
1252
|
}
|
|
1210
1253
|
} else if (decision.action.kind === 'run_profile') {
|
|
1211
1254
|
await assertRunAuthority(goal.root_id);
|
|
1212
|
-
outcome=await
|
|
1255
|
+
outcome=await executeProfileWithLease({workerScheduler,ctx,events,goal,
|
|
1213
1256
|
actionKey:`r34-${decisionEvent.event_sha256}`,profileId:decision.action.profile_id,
|
|
1214
1257
|
epoch:state.mutation_epoch,policy,codingRuntime,signingKeyPath,r34ResumePhase:loop.phase});
|
|
1215
1258
|
} else if (decision.action.kind === 'delegate') {
|
|
@@ -1219,7 +1262,7 @@ async function executeR34Decision({ctx,events,goal,state,decisionEvent,decision,
|
|
|
1219
1262
|
} else if (decision.action.kind === 'native_diff_apply') {
|
|
1220
1263
|
await assertRunAuthority(goal.root_id);
|
|
1221
1264
|
outcome=await executePreparedDiff({ctx,events,goal,state,decisionEvent,diffId:decision.action.diff_id,
|
|
1222
|
-
expectedOperationCount:decision.action.expected_operation_count,policy,codingRuntime,nativeDiffRuntime,signingKeyPath});
|
|
1265
|
+
expectedOperationCount:decision.action.expected_operation_count,policy,codingRuntime,nativeDiffRuntime,signingKeyPath,workerScheduler});
|
|
1223
1266
|
} else if (['machine_fs_mkdir','machine_fs_move','machine_fs_delete'].includes(decision.action.kind)) {
|
|
1224
1267
|
await assertRunAuthority(goal.root_id);
|
|
1225
1268
|
if(!machineFsRuntime) throw new Error('machine filesystem runtime unavailable');
|
|
@@ -1240,7 +1283,7 @@ async function executeR34Decision({ctx,events,goal,state,decisionEvent,decision,
|
|
|
1240
1283
|
}
|
|
1241
1284
|
}
|
|
1242
1285
|
outcome=await executePatch({ctx,events,goal,state,decisionEvent,decision:{operations,summary:`R36 ${decision.action.kind}`},
|
|
1243
|
-
nativeDiffRuntime,policy,codingRuntime,signingKeyPath});
|
|
1286
|
+
nativeDiffRuntime,policy,codingRuntime,signingKeyPath,workerScheduler});
|
|
1244
1287
|
} else if (capabilityIdForOperation(decision.action)) {
|
|
1245
1288
|
outcome=await executeDelegate({ctx,events,goal,decisionEvent,
|
|
1246
1289
|
decision:{operation:decision.action},policy,
|
|
@@ -1347,14 +1390,14 @@ async function executeR34Decision({ctx,events,goal,state,decisionEvent,decision,
|
|
|
1347
1390
|
throw new Error(`unsupported R34 decision '${String(decision.kind)}'`);
|
|
1348
1391
|
}
|
|
1349
1392
|
|
|
1350
|
-
async function
|
|
1393
|
+
async function executeDecisionCore({ ctx, events, goal, state, decisionEvent, policy, codingRuntime,
|
|
1351
1394
|
nativeDiffRuntime, machineFsRuntime, observationRuntime, processRuntime, semanticRuntime, assertRunAuthority,
|
|
1352
|
-
signingKeyPath, verifyKeyPath }) {
|
|
1395
|
+
signingKeyPath, verifyKeyPath, workerScheduler }) {
|
|
1353
1396
|
const decision = decisionEvent.decision;
|
|
1354
1397
|
if (decision?.schema === 'deadbyte.autonomous-decision.v2') {
|
|
1355
1398
|
const outcome=await executeR34Decision({ctx,events,goal,state,decisionEvent,decision,policy,codingRuntime,
|
|
1356
1399
|
nativeDiffRuntime,machineFsRuntime,observationRuntime,processRuntime,semanticRuntime,assertRunAuthority,
|
|
1357
|
-
signingKeyPath,verifyKeyPath});
|
|
1400
|
+
signingKeyPath,verifyKeyPath,workerScheduler});
|
|
1358
1401
|
await appendEvent(ctx,events,signingKeyPath,'decision_completed',{
|
|
1359
1402
|
decision_event_sha256:decisionEvent.event_sha256,action:decision.kind,
|
|
1360
1403
|
outcome_status:outcome.status ?? 'completed'
|
|
@@ -1384,15 +1427,15 @@ async function executeDecision({ ctx, events, goal, state, decisionEvent, policy
|
|
|
1384
1427
|
} else if (decision.action === 'patch') {
|
|
1385
1428
|
await assertRunAuthority(goal.root_id);
|
|
1386
1429
|
outcome = await executePatch({ ctx,events,goal,state,decisionEvent,decision,nativeDiffRuntime,
|
|
1387
|
-
policy,codingRuntime,signingKeyPath });
|
|
1430
|
+
policy,codingRuntime,signingKeyPath,workerScheduler });
|
|
1388
1431
|
} else if (decision.action === 'delegate') {
|
|
1389
1432
|
outcome = await executeDelegate({ ctx,events,goal,decisionEvent,decision,policy,
|
|
1390
1433
|
runtimes:{ machineFsRuntime,observationRuntime,processRuntime },assertRunAuthority,signingKeyPath,verifyKeyPath });
|
|
1391
1434
|
} else if (decision.action === 'run_profile') {
|
|
1392
1435
|
await assertRunAuthority(goal.root_id);
|
|
1393
|
-
outcome = await
|
|
1394
|
-
actionKey:`planner-${decisionEvent.event_sha256}`,
|
|
1395
|
-
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});
|
|
1396
1439
|
} else if (decision.action === 'pause') {
|
|
1397
1440
|
await appendEvent(ctx,events,signingKeyPath,'goal_paused',{
|
|
1398
1441
|
reason:decision.reason, planner_summary:decision.summary
|
|
@@ -1414,6 +1457,83 @@ async function executeDecision({ ctx, events, goal, state, decisionEvent, policy
|
|
|
1414
1457
|
return outcome;
|
|
1415
1458
|
}
|
|
1416
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
|
+
|
|
1417
1537
|
function terminalState(state) {
|
|
1418
1538
|
return ['succeeded','cancelled'].includes(state.state);
|
|
1419
1539
|
}
|
|
@@ -1442,6 +1562,9 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
|
|
|
1442
1562
|
if (!policy || !codingRuntime || !nativeDiffRuntime) throw new Error('autonomous runtime requires policy/coding/native-diff runtimes');
|
|
1443
1563
|
if (!signingKeyPath || !verifyKeyPath) throw new Error('autonomous runtime requires trust keys');
|
|
1444
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});
|
|
1445
1568
|
async function sessionStatus() {
|
|
1446
1569
|
const autonomous = await autonomousSessionStatus(policy);
|
|
1447
1570
|
const coding = await codingRuntime.sessionStatus();
|
|
@@ -1500,8 +1623,9 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
|
|
|
1500
1623
|
const journal = await readEvents(ctx,verifyKeyPath);
|
|
1501
1624
|
const derived = deriveState(goal,journal);
|
|
1502
1625
|
const loop = publicLoopState(loopStateOrNull(goal,journal));
|
|
1626
|
+
const lock=await runLockStatus(ctx);
|
|
1503
1627
|
return { status:'ok', goal_id:goalId, goal_sha256:goal.goal_sha256,
|
|
1504
|
-
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,
|
|
1505
1629
|
...(loop ? {loop} : {}) };
|
|
1506
1630
|
}
|
|
1507
1631
|
|
|
@@ -1577,7 +1701,7 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
|
|
|
1577
1701
|
}
|
|
1578
1702
|
state = deriveState(goal,journal);
|
|
1579
1703
|
const profiles = await runRequiredReleaseProfiles({ ctx,events:journal,goal,state,
|
|
1580
|
-
policy,codingRuntime,signingKeyPath });
|
|
1704
|
+
policy,codingRuntime,signingKeyPath,workerScheduler });
|
|
1581
1705
|
if (profiles.some(item => item.status === 'paused')) {
|
|
1582
1706
|
return { status:'paused', goal_id:goal.goal_id, ready:false,
|
|
1583
1707
|
reason:'release_profile_interrupted', mutation_epoch:state.mutation_epoch };
|
|
@@ -1658,7 +1782,7 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
|
|
|
1658
1782
|
try {
|
|
1659
1783
|
outcome = await executeDecision({ ctx,events:journal,goal,state,
|
|
1660
1784
|
decisionEvent:state.pending_decision,policy,codingRuntime,nativeDiffRuntime,machineFsRuntime,
|
|
1661
|
-
observationRuntime,processRuntime,semanticRuntime,assertRunAuthority,signingKeyPath,verifyKeyPath });
|
|
1785
|
+
observationRuntime,processRuntime,semanticRuntime,assertRunAuthority,signingKeyPath,verifyKeyPath,workerScheduler });
|
|
1662
1786
|
} catch (error) {
|
|
1663
1787
|
const loop=loopStateOrNull(goal,journal);
|
|
1664
1788
|
if (!loop || loop.pending_action || !isAuthorityUnavailable(error)) throw error;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const HEX64=/^[0-9a-f]{64}$/;
|
|
2
|
+
|
|
3
|
+
export function classifyAutonomousTimeoutRecovery(status,{beforeJournalHead}={}){
|
|
4
|
+
if(!status||typeof status!=='object'||Array.isArray(status)) throw new Error('autonomous timeout status invalid');
|
|
5
|
+
if(!HEX64.test(beforeJournalHead??'')) throw new Error('autonomous timeout before journal head invalid');
|
|
6
|
+
if(status.status!=='ok') throw new Error('autonomous timeout status not ok');
|
|
7
|
+
if(!HEX64.test(status.journal_head_sha256??'')) throw new Error('autonomous timeout journal head invalid');
|
|
8
|
+
if(status.state==='succeeded') return Object.freeze({kind:'completed',state:'succeeded',journal_head_sha256:status.journal_head_sha256});
|
|
9
|
+
if(status.state==='cancelled'||status.state==='paused'){
|
|
10
|
+
return Object.freeze({kind:'terminal_failure',state:status.state,reason:status.reason??null,journal_head_sha256:status.journal_head_sha256});
|
|
11
|
+
}
|
|
12
|
+
if(status.state!=='pending'&&status.state!=='running') throw new Error(`autonomous timeout unexpected state: ${status.state}`);
|
|
13
|
+
if(status.run_busy===true){
|
|
14
|
+
return Object.freeze({kind:'wait',state:status.state,reason:'server_run_in_flight',journal_head_sha256:status.journal_head_sha256});
|
|
15
|
+
}
|
|
16
|
+
if(status.run_busy!==false) throw new Error('autonomous timeout run-lock state unavailable');
|
|
17
|
+
if(status.pending_request!==null&&status.pending_request!==undefined){
|
|
18
|
+
return Object.freeze({kind:'wait',state:status.state,reason:'planner_request_in_flight',journal_head_sha256:status.journal_head_sha256});
|
|
19
|
+
}
|
|
20
|
+
if(status.pending_decision!==null&&status.pending_decision!==undefined){
|
|
21
|
+
return Object.freeze({kind:'wait',state:status.state,reason:'decision_in_flight',journal_head_sha256:status.journal_head_sha256});
|
|
22
|
+
}
|
|
23
|
+
if(status.journal_head_sha256===beforeJournalHead){
|
|
24
|
+
return Object.freeze({kind:'wait',state:status.state,reason:'no_durable_progress',journal_head_sha256:status.journal_head_sha256});
|
|
25
|
+
}
|
|
26
|
+
return Object.freeze({kind:'resumable',state:status.state,reason:'durable_cycle_completed',journal_head_sha256:status.journal_head_sha256});
|
|
27
|
+
}
|