deadbyte-mcp 0.12.0 → 0.14.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.
Files changed (90) hide show
  1. package/.gitattributes +7 -0
  2. package/AGENTS.md +25 -0
  3. package/CONTEXT.md +3 -3
  4. package/MANIFEST.SHA256 +89 -45
  5. package/R41-PARENT.json +15 -0
  6. package/R42-PARENT.json +19 -0
  7. package/README.txt +2 -2
  8. package/bin/appcontainer-stage.obj +0 -0
  9. package/bin/bootstrap-advapi32.obj +0 -0
  10. package/bin/bootstrap-exitcode.obj +0 -0
  11. package/bin/bootstrap-kernel32.obj +0 -0
  12. package/bin/child-control-probe.obj +0 -0
  13. package/bin/child-control-stage.obj +0 -0
  14. package/bin/contained-reverse-worker.obj +0 -0
  15. package/bin/contained-transform-worker.obj +0 -0
  16. package/bin/containment-probe.obj +0 -0
  17. package/bin/deadbyte-contain.obj +0 -0
  18. package/bin/deadbyte-exec.obj +0 -0
  19. package/bin/deadbyte-process-host.obj +0 -0
  20. package/bin/deadbyte-tunnel-host.obj +0 -0
  21. package/controller/README.TXT +1 -1
  22. package/controller/deadbyte-controller.ps1 +1 -1
  23. package/controller/deadbyte-desktop-policy.json +5 -5
  24. package/controller/deadbyte-process-policy.json +4 -4
  25. package/docs/ARCHITECTURE.md +1 -1
  26. package/docs/superpowers/specs/2026-09-20-r41-deterministic-memory-design.md +132 -0
  27. package/harness/r42-agent-evals.json +48 -0
  28. package/harness/task-contract.schema.json +33 -0
  29. package/package.json +11 -7
  30. package/proof/CONTAINMENT-BUILD.txt +6 -6
  31. package/scripts/agent-eval-r42.mjs +46 -0
  32. package/scripts/build-containment.ps1 +24 -14
  33. package/scripts/build-desktop-r40.ps1 +15 -9
  34. package/scripts/deferred-slot-operation-r41.mjs +127 -0
  35. package/scripts/deferred-slot-operation-r42.mjs +126 -0
  36. package/scripts/final-closure-r41.mjs +116 -0
  37. package/scripts/final-closure-r42.mjs +116 -0
  38. package/scripts/final-closure-verify-r41.mjs +215 -0
  39. package/scripts/final-closure-verify-r42.mjs +223 -0
  40. package/scripts/gate-windows-r41.ps1 +48 -0
  41. package/scripts/gate-windows-r42.ps1 +54 -0
  42. package/scripts/init-desktop-policy-r40.ps1 +10 -4
  43. package/scripts/release-parity-r41.mjs +221 -0
  44. package/scripts/release-parity-r42.mjs +235 -0
  45. package/scripts/release-parity-tests-r41.ps1 +9 -0
  46. package/scripts/release-parity-tests-r42.ps1 +6 -0
  47. package/scripts/verify-memory-r41.mjs +88 -0
  48. package/scripts/verify-r41-parent.mjs +61 -0
  49. package/scripts/verify-r42-parent.mjs +101 -0
  50. package/scripts/windows-gate-evidence-r41.mjs +53 -0
  51. package/scripts/windows-gate-evidence-r42.mjs +64 -0
  52. package/src/agent-eval-r42.mjs +73 -0
  53. package/src/agent-eval-runner-r42.mjs +138 -0
  54. package/src/agent-governance-r42.mjs +142 -0
  55. package/src/autonomous-context-engine.mjs +4 -1
  56. package/src/autonomous-loop-state.mjs +10 -0
  57. package/src/autonomous-mcp-tools.mjs +21 -6
  58. package/src/autonomous-output-contracts.mjs +18 -2
  59. package/src/autonomous-planner-contracts.mjs +3 -0
  60. package/src/autonomous-planner.mjs +48 -6
  61. package/src/autonomous-policy.mjs +10 -2
  62. package/src/autonomous-runtime.mjs +144 -25
  63. package/src/autonomous-supervisor.mjs +1 -1
  64. package/src/evidence-publisher-r42.mjs +76 -0
  65. package/src/mcp-server.mjs +15 -2
  66. package/src/memory-r41.mjs +692 -0
  67. package/src/provider-circuit.mjs +4 -4
  68. package/src/version.mjs +1 -1
  69. package/test/agent-eval-r42.test.mjs +39 -0
  70. package/test/agent-eval-runner-r42.test.mjs +61 -0
  71. package/test/agent-governance-r42.test.mjs +77 -0
  72. package/test/autonomous-r34-e2e.test.mjs +2 -1
  73. package/test/cli-entrypoint.test.mjs +1 -1
  74. package/test/controller-desktop-r40.test.mjs +2 -1
  75. package/test/core.test.mjs +1 -1
  76. package/test/evidence-publisher-r42.test.mjs +53 -0
  77. package/test/helpers/autonomous-r34-fixture.mjs +3 -3
  78. package/test/human-clarification-r42.test.mjs +53 -0
  79. package/test/memory-autonomous-integration-r41.test.mjs +31 -0
  80. package/test/memory-history-r41.test.mjs +126 -0
  81. package/test/memory-projections-r41.test.mjs +92 -0
  82. package/test/memory-retrieval-r41.test.mjs +124 -0
  83. package/test/memory-snapshot-r41.test.mjs +106 -0
  84. package/test/provider-responses-r42.test.mjs +90 -0
  85. package/test/r33-closeout-regression.test.mjs +27 -12
  86. package/test/r33-finalization.test.mjs +4 -4
  87. package/test/r41-finalization.test.mjs +38 -0
  88. package/test/r42-finalization.test.mjs +38 -0
  89. package/test/release-version.test.mjs +14 -13
  90. package/test/task-contract-r42.test.mjs +41 -0
@@ -0,0 +1,64 @@
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
+ import { canonicalJson } from '../src/canonical-json.mjs';
7
+ import { readAndVerifyR42EvalEvidence } from '../src/agent-eval-runner-r42.mjs';
8
+
9
+ const here=path.dirname(fileURLToPath(import.meta.url));
10
+ const root=path.resolve(here,'..');
11
+ const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
12
+ const marker='DEADBYTE V0.14.0 / R42 WINDOWS BATCH GATE: PASS';
13
+ function insist(ok,message){if(!ok) throw new Error(message);}
14
+
15
+ export async function writeWindowsGateEvidence({
16
+ candidateRoot=root,
17
+ stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp')),
18
+ clock=()=>new Date()
19
+ }={}){
20
+ const candidate=path.resolve(candidateRoot);
21
+ const manifestBytes=await readFile(path.join(candidate,'MANIFEST.SHA256'));
22
+ const manifestSha256=sha256(manifestBytes);
23
+ const pkg=JSON.parse(await readFile(path.join(candidate,'package.json'),'utf8'));
24
+ insist(pkg.version==='0.14.0',`Windows gate evidence requires V0.14.0, found ${pkg.version}`);
25
+
26
+ const suite=JSON.parse(await readFile(path.join(candidate,'harness','r42-agent-evals.json'),'utf8'));
27
+ const suiteSha256=sha256(Buffer.from(canonicalJson(suite),'utf8'));
28
+ const evalId=`r42-${manifestSha256.slice(0,16)}-${suiteSha256.slice(0,16)}`;
29
+ const evalPath=path.join(path.resolve(stateRoot),'evidence','release','r42-agent-evals','agent_eval',`${evalId}.json`);
30
+ const evalVerified=await readAndVerifyR42EvalEvidence(evalPath,{subjectManifestSha256:manifestSha256,suiteSha256});
31
+
32
+ const completed=clock();
33
+ insist(completed instanceof Date&&!Number.isNaN(completed.getTime()),'Windows gate evidence clock invalid');
34
+ const evidence={
35
+ schema:'deadbyte.r42-windows-gate.v1',status:'passed',exit_code:0,version:'0.14.0',
36
+ marker,completed_at_utc:completed.toISOString(),manifest_sha256:manifestSha256,
37
+ model_eval:{path:evalPath,evidence_sha256:evalVerified.evidence_sha256,payload_sha256:evalVerified.payload_sha256,
38
+ suite_sha256:suiteSha256,case_count:evalVerified.payload.case_count}
39
+ };
40
+ const bytes=Buffer.from(`${JSON.stringify(evidence,null,2)}\n`,'utf8');
41
+ const dir=path.join(path.resolve(stateRoot),'evidence','release');
42
+ await mkdir(dir,{recursive:true});
43
+ const file=path.join(dir,`r42-windows-gate-${manifestSha256.slice(0,16)}.json`);
44
+ try{
45
+ const handle=await open(file,'wx',0o600);
46
+ try{await handle.writeFile(bytes);await handle.sync();}finally{await handle.close();}
47
+ return {status:'written',path:file,sha256:sha256(bytes),manifest_sha256:manifestSha256,model_eval:evidence.model_eval};
48
+ }catch(error){
49
+ if(error?.code!=='EEXIST') throw error;
50
+ const existingBytes=await readFile(file);
51
+ const existing=JSON.parse(existingBytes.toString('utf8').replace(/^\uFEFF/,''));
52
+ insist(existing.schema===evidence.schema&&existing.status==='passed'&&existing.exit_code===0,'existing R42 Windows gate evidence invalid');
53
+ insist(existing.version==='0.14.0'&&existing.marker===marker&&existing.manifest_sha256===manifestSha256,'existing R42 Windows gate identity mismatch');
54
+ insist(existing.model_eval?.evidence_sha256===evidence.model_eval.evidence_sha256&&existing.model_eval?.suite_sha256===suiteSha256,'existing R42 Windows gate model-eval mismatch');
55
+ return {status:'existing',path:file,sha256:sha256(existingBytes),manifest_sha256:manifestSha256,model_eval:existing.model_eval};
56
+ }
57
+ }
58
+
59
+ const invoked=process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url);
60
+ if(invoked){
61
+ writeWindowsGateEvidence()
62
+ .then(result=>console.log(JSON.stringify(result)))
63
+ .catch(error=>{console.error(error instanceof Error?error.stack:String(error));process.exitCode=1;});
64
+ }
@@ -0,0 +1,73 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { canonicalJson } from './canonical-json.mjs';
3
+
4
+ const HEX64=/^[0-9a-f]{64}$/;
5
+ const ID=/^[A-Za-z0-9._-]{1,96}$/;
6
+ const SEVERITY=new Set(['info','low','medium','high','critical']);
7
+ const sha=value=>createHash('sha256').update(Buffer.from(canonicalJson(value),'utf8')).digest('hex');
8
+ function object(value,label){if(!value||typeof value!=='object'||Array.isArray(value))throw new Error(`${label} invalid`);return value;}
9
+ function keys(value,allowed,label){const extra=Object.keys(value).filter(key=>!allowed.includes(key));if(extra.length)throw new Error(`${label} unknown field '${extra[0]}'`);}
10
+ function id(value,label){if(typeof value!=='string'||!ID.test(value))throw new Error(`${label} invalid`);return value;}
11
+ function text(value,label,max=8192){if(typeof value!=='string'||value.length<1||value.length>max||value.includes('\0'))throw new Error(`${label} invalid`);return value;}
12
+ function textList(value,label,maxItems=32,maxLength=1024){if(!Array.isArray(value)||value.length>maxItems||value.some(item=>typeof item!=='string'||item.length<1||item.length>maxLength))throw new Error(`${label} invalid`);return [...value];}
13
+
14
+ function normalizeCase(raw){
15
+ const value=object(raw,'agent eval case');keys(value,['schema','case_id','task','allowed_context','hidden_oracle','acceptance'],'agent eval case');
16
+ if(value.schema!=='deadbyte.agent-eval-case.v1')throw new Error('agent eval case schema invalid');
17
+ const core={schema:value.schema,case_id:id(value.case_id,'eval case_id'),task:text(value.task,'eval task'),
18
+ allowed_context:structuredClone(object(value.allowed_context,'eval allowed_context')),
19
+ hidden_oracle:structuredClone(object(value.hidden_oracle,'eval hidden_oracle')),
20
+ acceptance:textList(value.acceptance,'eval acceptance')};
21
+ return Object.freeze({...core,case_sha256:sha(core)});
22
+ }
23
+
24
+ function normalizeJudgeResult(raw){
25
+ const value=object(raw,'judge result');keys(value,['schema','verdict','advisory','findings','evidence_refs'],'judge result');
26
+ if(value.schema!==undefined&&value.schema!=='deadbyte.agent-eval-judge-result.v1')throw new Error('judge result schema invalid');
27
+ if(!['pass','fail'].includes(value.verdict))throw new Error('judge verdict invalid');
28
+ if(value.advisory!==undefined&&value.advisory!==true)throw new Error('judge result must remain advisory');
29
+ if(!Array.isArray(value.findings)||value.findings.length>64)throw new Error('judge findings invalid');
30
+ const findings=value.findings.map(finding=>{
31
+ object(finding,'judge finding');keys(finding,['code','severity','evidence'],'judge finding');
32
+ if(!SEVERITY.has(finding.severity))throw new Error('judge finding severity invalid');
33
+ return {code:id(finding.code,'judge finding code'),severity:finding.severity,evidence:text(finding.evidence,'judge finding evidence',2048)};
34
+ });
35
+ if(!Array.isArray(value.evidence_refs)||value.evidence_refs.length<1||value.evidence_refs.length>64||value.evidence_refs.some(ref=>!HEX64.test(ref)))throw new Error('judge evidence refs invalid');
36
+ return Object.freeze({schema:'deadbyte.agent-eval-judge-result.v1',verdict:value.verdict,advisory:true,findings,evidence_refs:[...value.evidence_refs]});
37
+ }
38
+
39
+ export async function runIsolatedEvaluation({caseSpec,generator,judge}){
40
+ const normalized=normalizeCase(caseSpec);
41
+ if(typeof generator!=='function'||typeof judge!=='function')throw new Error('eval generator and judge required');
42
+ const generatorInput=Object.freeze({schema:'deadbyte.agent-eval-generator-input.v1',case_id:normalized.case_id,
43
+ task:normalized.task,allowed_context:structuredClone(normalized.allowed_context),acceptance:[...normalized.acceptance]});
44
+ const generated=object(await generator(generatorInput),'generator result');
45
+ keys(generated,['artifact','trace'],'generator result');
46
+ const artifact=structuredClone(object(generated.artifact,'generator artifact'));
47
+ const candidateSha=sha(artifact);
48
+ const judgeInput=Object.freeze({schema:'deadbyte.agent-eval-judge-input.v1',case_id:normalized.case_id,
49
+ task:normalized.task,acceptance:[...normalized.acceptance],candidate:artifact,candidate_sha256:candidateSha,
50
+ hidden_oracle:structuredClone(normalized.hidden_oracle)});
51
+ const judged=normalizeJudgeResult(await judge(judgeInput));
52
+ const core={schema:'deadbyte.agent-eval-result.v1',case_id:normalized.case_id,case_sha256:normalized.case_sha256,
53
+ candidate_sha256:candidateSha,verdict:judged.verdict,advisory:true,findings:judged.findings,evidence_refs:judged.evidence_refs};
54
+ return Object.freeze({...core,result_sha256:sha(core)});
55
+ }
56
+
57
+ export function buildFreshCriticContext(raw){
58
+ const value=object(raw,'fresh critic context');keys(value,['case_id','artifact','evidence','criteria'],'fresh critic context');
59
+ id(value.case_id,'critic case_id');object(value.artifact,'critic artifact');
60
+ if(!Array.isArray(value.evidence)||value.evidence.length>128)throw new Error('critic evidence invalid');
61
+ return Object.freeze({schema:'deadbyte.fresh-critic-context.v1',case_id:value.case_id,
62
+ artifact:structuredClone(value.artifact),evidence:structuredClone(value.evidence),
63
+ criteria:textList(value.criteria,'critic criteria',64,1024)});
64
+ }
65
+
66
+ export function triageJudgeResult(raw,{critical_action,noncritical_action}){
67
+ const judge=normalizeJudgeResult(raw);
68
+ if(judge.advisory!==true)throw new Error('judge result must remain advisory');
69
+ if(!['pause','repair','continue'].includes(critical_action)||!['pause','repair','continue'].includes(noncritical_action))throw new Error('judge triage action invalid');
70
+ const critical=judge.findings.some(finding=>finding.severity==='critical'||finding.severity==='high');
71
+ return Object.freeze({action:judge.verdict==='pass'?'continue':(critical?critical_action:noncritical_action),
72
+ reason_codes:judge.findings.map(finding=>finding.code),judge_advisory:true});
73
+ }
@@ -0,0 +1,138 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { readFile } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { canonicalJson } from './canonical-json.mjs';
5
+ import { runIsolatedEvaluation } from './agent-eval-r42.mjs';
6
+ import { publishEvidenceAtomic } from './evidence-publisher-r42.mjs';
7
+
8
+ const HEX64=/^[0-9a-f]{64}$/;
9
+ const ID=/^[A-Za-z0-9._-]{1,96}$/;
10
+ const sha=value=>createHash('sha256').update(Buffer.from(canonicalJson(value),'utf8')).digest('hex');
11
+ const shaText=value=>createHash('sha256').update(Buffer.from(String(value),'utf8')).digest('hex');
12
+
13
+ function object(value,label){if(!value||typeof value!=='object'||Array.isArray(value))throw new Error(`${label} invalid`);return value;}
14
+ function keys(value,allowed,label){const extra=Object.keys(value).filter(key=>!allowed.includes(key));if(extra.length)throw new Error(`${label} unknown field '${extra[0]}'`);}
15
+ function parseJson(raw,label){
16
+ if(typeof raw!=='string'||raw.length<2||raw.length>1024*1024)throw new Error(`${label} response invalid`);
17
+ let value;try{value=JSON.parse(raw);}catch{throw new Error(`${label} response must be strict JSON`);}
18
+ return object(value,label);
19
+ }
20
+ function providerMeta(raw){
21
+ const value=object(raw,'model response');
22
+ const meta={
23
+ backend:typeof value.backend==='string'?value.backend:'injected',
24
+ model:typeof value.model==='string'?value.model.slice(0,128):'injected',
25
+ response_id:typeof value.response_id==='string'?value.response_id.slice(0,160):null,
26
+ raw_response_sha256:HEX64.test(value.raw_response_sha256??'')?value.raw_response_sha256:shaText(value.raw_text??''),
27
+ usage:value.usage&&Number.isInteger(value.usage.input_tokens)&&Number.isInteger(value.usage.output_tokens)&&Number.isInteger(value.usage.total_tokens)
28
+ ?{input_tokens:value.usage.input_tokens,output_tokens:value.usage.output_tokens,total_tokens:value.usage.total_tokens}:null
29
+ };
30
+ return Object.freeze(meta);
31
+ }
32
+ function normalizeSuite(raw){
33
+ const value=object(raw,'eval suite');keys(value,['schema','suite_id','cases'],'eval suite');
34
+ if(value.schema!=='deadbyte.agent-eval-suite.v1')throw new Error('eval suite schema invalid');
35
+ if(typeof value.suite_id!=='string'||!ID.test(value.suite_id))throw new Error('eval suite_id invalid');
36
+ if(!Array.isArray(value.cases)||value.cases.length<1||value.cases.length>32)throw new Error('eval suite cases invalid');
37
+ const ids=new Set();
38
+ for(const item of value.cases){
39
+ object(item,'eval suite case');
40
+ if(item.schema!=='deadbyte.agent-eval-case.v1'||typeof item.case_id!=='string'||!ID.test(item.case_id)||ids.has(item.case_id))throw new Error('eval suite case identity invalid');
41
+ ids.add(item.case_id);
42
+ }
43
+ const copy=structuredClone(value);
44
+ return Object.freeze({...copy,suite_sha256:sha(copy)});
45
+ }
46
+ function generatorPrompt(input){
47
+ return [
48
+ 'You are the implementation-side evaluator for DEADBYTE R42.',
49
+ 'Return exactly one JSON object with shape {"artifact":{...}} and no Markdown.',
50
+ 'Do not invent authority, credentials, or evidence. Prefer bounded, typed, fail-closed behavior.',
51
+ `INPUT=${canonicalJson(input)}`
52
+ ].join('\n');
53
+ }
54
+ function judgePrompt(input){
55
+ return [
56
+ 'You are an independent advisory judge for DEADBYTE R42.',
57
+ 'Return exactly one JSON object with schema deadbyte.agent-eval-judge-result.v1.',
58
+ 'Shape: {"schema":"deadbyte.agent-eval-judge-result.v1","verdict":"pass|fail","advisory":true,"findings":[{"code":"ID","severity":"info|low|medium|high|critical","evidence":"text"}],"evidence_refs":["64hex"]}.',
59
+ 'Judge only the supplied candidate against acceptance and hidden oracle. Do not assume implementer reasoning.',
60
+ 'Use candidate_sha256 as at least one evidence_refs entry.',
61
+ `INPUT=${canonicalJson(input)}`
62
+ ].join('\n');
63
+ }
64
+
65
+ export function verifyR42EvalPayload(payload,{subjectManifestSha256=null,suiteSha256=null}={}){
66
+ const value=object(payload,'R42 eval payload');
67
+ keys(value,['schema','status','subject_manifest_sha256','suite_id','suite_sha256','case_count','cases','completed_at_utc'],'R42 eval payload');
68
+ if(value.schema!=='deadbyte.r42-model-eval.v1'||value.status!=='passed')throw new Error('R42 eval payload is not passed');
69
+ if(!HEX64.test(value.subject_manifest_sha256??''))throw new Error('R42 eval manifest invalid');
70
+ if(subjectManifestSha256!==null&&value.subject_manifest_sha256!==subjectManifestSha256)throw new Error('R42 eval manifest mismatch');
71
+ if(!HEX64.test(value.suite_sha256??''))throw new Error('R42 eval suite hash invalid');
72
+ if(suiteSha256!==null&&value.suite_sha256!==suiteSha256)throw new Error('R42 eval suite hash mismatch');
73
+ if(typeof value.suite_id!=='string'||!ID.test(value.suite_id))throw new Error('R42 eval suite id invalid');
74
+ if(!Number.isInteger(value.case_count)||value.case_count<1||!Array.isArray(value.cases)||value.cases.length!==value.case_count)throw new Error('R42 eval cases invalid');
75
+ const seen=new Set();
76
+ for(const item of value.cases){
77
+ object(item,'R42 eval case result');keys(item,['case_id','result','generator','judge'],'R42 eval case result');
78
+ if(typeof item.case_id!=='string'||!ID.test(item.case_id)||seen.has(item.case_id))throw new Error('R42 eval case result identity invalid');
79
+ seen.add(item.case_id);
80
+ if(item.result?.schema!=='deadbyte.agent-eval-result.v1'||item.result?.verdict!=='pass'||item.result?.advisory!==true||!HEX64.test(item.result?.result_sha256??''))throw new Error(`R42 eval case did not pass: ${item.case_id}`);
81
+ for(const role of ['generator','judge']){
82
+ if(!HEX64.test(item[role]?.raw_response_sha256??''))throw new Error(`R42 eval ${role} provenance invalid`);
83
+ }
84
+ }
85
+ if(typeof value.completed_at_utc!=='string'||!Number.isFinite(Date.parse(value.completed_at_utc)))throw new Error('R42 eval completion time invalid');
86
+ return true;
87
+ }
88
+
89
+ export async function runAgentEvalSuiteR42({suite,subjectManifestSha256,requestModel,evidenceRoot=null,clock=()=>new Date()}){
90
+ const normalized=normalizeSuite(suite);
91
+ if(!HEX64.test(subjectManifestSha256??''))throw new Error('R42 eval subject manifest invalid');
92
+ if(typeof requestModel!=='function')throw new Error('R42 eval requestModel required');
93
+ const rows=[];
94
+ for(const caseSpec of normalized.cases){
95
+ let generatorMeta=null,judgeMeta=null;
96
+ const result=await runIsolatedEvaluation({
97
+ caseSpec,
98
+ generator:async input=>{
99
+ const response=object(await requestModel({role:'generator',case_id:caseSpec.case_id,prompt:generatorPrompt(input)}),'generator model response');
100
+ generatorMeta=providerMeta(response);
101
+ const parsed=parseJson(response.raw_text,'generator');
102
+ keys(parsed,['artifact'],'generator response');
103
+ return {artifact:object(parsed.artifact,'generator artifact')};
104
+ },
105
+ judge:async input=>{
106
+ const response=object(await requestModel({role:'judge',case_id:caseSpec.case_id,prompt:judgePrompt(input)}),'judge model response');
107
+ judgeMeta=providerMeta(response);
108
+ return parseJson(response.raw_text,'judge');
109
+ }
110
+ });
111
+ rows.push({case_id:caseSpec.case_id,result,generator:generatorMeta,judge:judgeMeta});
112
+ }
113
+ if(rows.some(row=>row.result.verdict!=='pass'))throw new Error('R42 model-backed eval suite failed');
114
+ const completed=clock();if(!(completed instanceof Date)||Number.isNaN(completed.getTime()))throw new Error('R42 eval clock invalid');
115
+ const payload={
116
+ schema:'deadbyte.r42-model-eval.v1',status:'passed',subject_manifest_sha256:subjectManifestSha256,
117
+ suite_id:normalized.suite_id,suite_sha256:normalized.suite_sha256,case_count:rows.length,cases:rows,
118
+ completed_at_utc:completed.toISOString()
119
+ };
120
+ verifyR42EvalPayload(payload,{subjectManifestSha256,suiteSha256:normalized.suite_sha256});
121
+ let publication=null;
122
+ if(evidenceRoot!==null){
123
+ if(typeof evidenceRoot!=='string'||!path.isAbsolute(evidenceRoot))throw new Error('R42 eval evidence root must be absolute');
124
+ const evidenceId=`r42-${subjectManifestSha256.slice(0,16)}-${normalized.suite_sha256.slice(0,16)}`;
125
+ publication=await publishEvidenceAtomic({root:evidenceRoot,kind:'agent_eval',evidenceId,payload});
126
+ }
127
+ return Object.freeze({payload,publication});
128
+ }
129
+
130
+ export async function readAndVerifyR42EvalEvidence(file,{subjectManifestSha256,suiteSha256}={}){
131
+ const envelope=JSON.parse(await readFile(path.resolve(file),'utf8'));
132
+ if(envelope?.schema!=='deadbyte.evidence-publication.v1'||envelope?.kind!=='agent_eval')throw new Error('R42 eval evidence envelope invalid');
133
+ if(!HEX64.test(envelope.payload_sha256??'')||sha(envelope.payload)!==envelope.payload_sha256)throw new Error('R42 eval payload hash mismatch');
134
+ const {evidence_sha256,...body}=envelope;
135
+ if(!HEX64.test(evidence_sha256??'')||sha(body)!==evidence_sha256)throw new Error('R42 eval evidence hash mismatch');
136
+ verifyR42EvalPayload(envelope.payload,{subjectManifestSha256,suiteSha256});
137
+ return Object.freeze({status:'passed',evidence_sha256,payload_sha256:envelope.payload_sha256,payload:envelope.payload});
138
+ }
@@ -0,0 +1,142 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { canonicalJson } from './canonical-json.mjs';
3
+
4
+ const HEX64=/^[0-9a-f]{64}$/;
5
+ const ID=/^[A-Za-z0-9._-]{1,64}$/;
6
+ const RIGOR=Object.freeze({lightweight:0,structured:1,agentic:2});
7
+ const RISK_MINIMUM=Object.freeze({low:'lightweight',medium:'structured',high:'agentic'});
8
+ const EVIDENCE=Object.freeze({assumption:1,source:2,traced_path:3,automated:4,runtime:5});
9
+
10
+ const sha=value=>createHash('sha256').update(Buffer.from(canonicalJson(value),'utf8')).digest('hex');
11
+ function object(value,label){if(!value||typeof value!=='object'||Array.isArray(value)) throw new Error(`${label} invalid`);return value;}
12
+ function keys(value,allowed,label){const extra=Object.keys(value).filter(key=>!allowed.includes(key));if(extra.length) throw new Error(`${label} unknown field '${extra[0]}'`);}
13
+ function id(value,label){if(typeof value!=='string'||!ID.test(value)) throw new Error(`${label} invalid`);return value;}
14
+ function hex(value,label){if(typeof value!=='string'||!HEX64.test(value)) throw new Error(`${label} invalid`);return value;}
15
+ function text(value,label,max=2048){if(typeof value!=='string'||value.length<1||value.length>max||value.includes('\0')) throw new Error(`${label} invalid`);return value;}
16
+ function idList(value,label,max=128){if(!Array.isArray(value)||value.length>max||value.some(item=>typeof item!=='string'||!ID.test(item))||new Set(value).size!==value.length) throw new Error(`${label} invalid`);return [...value];}
17
+
18
+ export function bindApprovalSubject(raw){
19
+ const value=object(raw,'approval subject');
20
+ keys(value,['goal_id','reviewed_event_seq','reviewed_event_sha256','journal_head_sha256','scope','subject'],'approval subject');
21
+ hex(value.goal_id,'approval goal_id');
22
+ if(!Number.isInteger(value.reviewed_event_seq)||value.reviewed_event_seq<1) throw new Error('approval reviewed_event_seq invalid');
23
+ hex(value.reviewed_event_sha256,'approval reviewed_event_sha256');
24
+ hex(value.journal_head_sha256,'approval journal_head_sha256');
25
+ id(value.scope,'approval scope'); object(value.subject,'approval canonical subject');
26
+ const normalized=structuredClone(value);
27
+ return Object.freeze({...normalized,approval_subject_sha256:sha({schema:'deadbyte.approval-subject.v1',...normalized})});
28
+ }
29
+
30
+ export function validateBoundApproval({approval,subject,now=new Date()}){
31
+ const {approval_subject_sha256:claimedSubjectSha,...subjectBody}=object(subject,'approval subject');
32
+ const bound=bindApprovalSubject(subjectBody);
33
+ if(claimedSubjectSha!==undefined&&claimedSubjectSha!==bound.approval_subject_sha256) throw new Error('approval subject hash mismatch');
34
+ const value=object(approval,'bound approval');
35
+ keys(value,['schema','approval_subject_sha256','reviewed_event_seq','reviewed_event_sha256','journal_head_sha256','scope','issued_at_utc','expires_at_utc','provenance'],'bound approval');
36
+ if(value.schema!=='deadbyte.bound-approval.v1') throw new Error('bound approval schema invalid');
37
+ if(value.approval_subject_sha256!==bound.approval_subject_sha256) throw new Error('bound approval subject mismatch');
38
+ if(value.reviewed_event_seq!==bound.reviewed_event_seq||value.reviewed_event_sha256!==bound.reviewed_event_sha256) throw new Error('bound approval reviewed event mismatch');
39
+ if(value.journal_head_sha256!==bound.journal_head_sha256) throw new Error('bound approval journal head mismatch');
40
+ if(value.scope!==bound.scope) throw new Error('bound approval scope mismatch');
41
+ if(value.provenance!=='operator_mcp') throw new Error('bound approval provenance invalid');
42
+ const issued=Date.parse(value.issued_at_utc),expires=Date.parse(value.expires_at_utc),observed=now.getTime();
43
+ if(!Number.isFinite(issued)||!Number.isFinite(expires)||expires<=issued||expires-issued>3_600_000) throw new Error('bound approval lifetime invalid');
44
+ if(observed<issued||observed>=expires) throw new Error('bound approval expired or not yet valid');
45
+ return true;
46
+ }
47
+
48
+ export function createTaskDag(raw){
49
+ const value=object(raw,'task DAG'); keys(value,['run_id','goal_id','tasks'],'task DAG');
50
+ id(value.run_id,'task DAG run_id'); hex(value.goal_id,'task DAG goal_id');
51
+ if(!Array.isArray(value.tasks)||value.tasks.length<1||value.tasks.length>256) throw new Error('task DAG tasks invalid');
52
+ const tasks=value.tasks.map(item=>{
53
+ object(item,'task DAG task');keys(item,['task_id','depends_on','input_artifacts','output_artifacts','state'],'task DAG task');
54
+ return {task_id:id(item.task_id,'task_id'),depends_on:idList(item.depends_on,'depends_on'),
55
+ input_artifacts:idList(item.input_artifacts,'input_artifacts'),output_artifacts:idList(item.output_artifacts,'output_artifacts'),
56
+ state:item.state??'PENDING'};
57
+ });
58
+ const ids=new Set(tasks.map(task=>task.task_id)); if(ids.size!==tasks.length) throw new Error('task DAG duplicate task_id');
59
+ for(const task of tasks) if(task.depends_on.some(dep=>!ids.has(dep))) throw new Error('task DAG dependency missing');
60
+ if(tasks.some(task=>!['PENDING','RUNNING','COMPLETE','FAILED','STALE'].includes(task.state))) throw new Error('task DAG state invalid');
61
+ const visiting=new Set(),visited=new Set(),byId=new Map(tasks.map(task=>[task.task_id,task]));
62
+ const visit=taskId=>{if(visiting.has(taskId)) throw new Error('task DAG cycle detected');if(visited.has(taskId))return;visiting.add(taskId);for(const dep of byId.get(taskId).depends_on)visit(dep);visiting.delete(taskId);visited.add(taskId);};
63
+ for(const task of tasks) visit(task.task_id);
64
+ const core={schema:'deadbyte.task-dag.v1',run_id:value.run_id,goal_id:value.goal_id,tasks};
65
+ return Object.freeze({...core,dag_sha256:sha(core)});
66
+ }
67
+
68
+ export function invalidateTaskDag(dag,{changed_artifact_ids}){
69
+ const changed=new Set(idList(changed_artifact_ids,'changed_artifact_ids'));
70
+ const stale=new Set(dag.tasks.filter(task=>task.input_artifacts.some(artifact=>changed.has(artifact))).map(task=>task.task_id));
71
+ let grew=true;while(grew){grew=false;for(const task of dag.tasks){if(!stale.has(task.task_id)&&task.depends_on.some(dep=>stale.has(dep))){stale.add(task.task_id);grew=true;}}}
72
+ return createTaskDag({run_id:dag.run_id,goal_id:dag.goal_id,tasks:dag.tasks.map(task=>({...task,state:stale.has(task.task_id)?'STALE':task.state}))});
73
+ }
74
+
75
+ export function taskDagFromPlan({run_id,goal_id,plan}){
76
+ object(plan,'task DAG plan');
77
+ if(!Array.isArray(plan.steps)||plan.steps.length<1) throw new Error('task DAG plan steps invalid');
78
+ const tasks=plan.steps.map((step,index)=>{
79
+ const previous=index===0?null:plan.steps[index-1].step_id;
80
+ return {task_id:step.step_id,depends_on:previous?[previous]:[],
81
+ input_artifacts:previous?[`${previous}.result`]:[],output_artifacts:[`${step.step_id}.result`],
82
+ state:step.status==='completed'?'COMPLETE':step.status==='active'?'RUNNING':'PENDING'};
83
+ });
84
+ return createTaskDag({run_id,goal_id,tasks});
85
+ }
86
+
87
+ export function createEvidenceClaim(raw){
88
+ const value=object(raw,'evidence claim');keys(value,['claim_id','statement','level','refs'],'evidence claim');
89
+ id(value.claim_id,'claim_id');text(value.statement,'claim statement',2048);
90
+ if(!Object.hasOwn(EVIDENCE,value.level)) throw new Error('evidence level invalid');
91
+ if(!Array.isArray(value.refs)||value.refs.length>64||value.refs.some(ref=>!HEX64.test(ref))) throw new Error('evidence reference invalid');
92
+ if(value.level!=='assumption'&&value.refs.length<1) throw new Error('evidence reference required');
93
+ const core={schema:'deadbyte.evidence-claim.v1',claim_id:value.claim_id,statement:value.statement,level:value.level,refs:[...value.refs]};
94
+ return Object.freeze({...core,claim_sha256:sha(core)});
95
+ }
96
+ export function evidenceSatisfies(claim,minimum){if(!Object.hasOwn(EVIDENCE,minimum)) throw new Error('minimum evidence level invalid');return EVIDENCE[claim.level]>=EVIDENCE[minimum];}
97
+
98
+ export function deriveEffectiveRigor({project_default,risk_level,explicit_override=null}){
99
+ if(!Object.hasOwn(RIGOR,project_default)) throw new Error('project default rigor invalid');
100
+ if(!Object.hasOwn(RISK_MINIMUM,risk_level)) throw new Error('risk level invalid');
101
+ if(explicit_override!==null&&!Object.hasOwn(RIGOR,explicit_override)) throw new Error('explicit rigor override invalid');
102
+ const risk_minimum=RISK_MINIMUM[risk_level];
103
+ const values=[project_default,risk_minimum,...(explicit_override?[explicit_override]:[])];
104
+ const effective_rigor=values.reduce((best,item)=>RIGOR[item]>RIGOR[best]?item:best,'lightweight');
105
+ return Object.freeze({project_default,risk_minimum,explicit_override,effective_rigor});
106
+ }
107
+
108
+ export function createDecisionRecord(raw){
109
+ const value=object(raw,'decision record');keys(value,['decision_id','decision','reason','evidence_refs','invalidates_if'],'decision record');
110
+ id(value.decision_id,'decision_id');text(value.decision,'decision',2048);text(value.reason,'decision reason',2048);
111
+ if(!Array.isArray(value.evidence_refs)||value.evidence_refs.length<1||value.evidence_refs.length>64||value.evidence_refs.some(ref=>!HEX64.test(ref))) throw new Error('decision evidence refs invalid');
112
+ if(!Array.isArray(value.invalidates_if)||value.invalidates_if.length>32) throw new Error('decision invalidation rules invalid');
113
+ const rules=value.invalidates_if.map(rule=>{
114
+ object(rule,'decision invalidation rule');
115
+ if(rule.kind==='artifact_sha_changed'){
116
+ keys(rule,['kind','artifact_id','expected_sha256'],'artifact invalidation rule');
117
+ return {kind:rule.kind,artifact_id:id(rule.artifact_id,'artifact_id'),expected_sha256:hex(rule.expected_sha256,'expected artifact sha256')};
118
+ }
119
+ if(rule.kind==='policy_sha_changed'){
120
+ keys(rule,['kind','expected_sha256'],'policy invalidation rule');
121
+ return {kind:rule.kind,expected_sha256:hex(rule.expected_sha256,'expected policy sha256')};
122
+ }
123
+ throw new Error('decision invalidation rule kind invalid');
124
+ });
125
+ const core={schema:'deadbyte.decision-record.v1',decision_id:value.decision_id,decision:value.decision,reason:value.reason,
126
+ evidence_refs:[...value.evidence_refs],invalidates_if:rules};
127
+ return Object.freeze({...core,decision_sha256:sha(core)});
128
+ }
129
+
130
+ export function evaluateDecisionFreshness(record,observed){
131
+ object(record,'decision record');object(observed,'decision observed state');
132
+ const invalidated_by=[];
133
+ for(const rule of record.invalidates_if){
134
+ if(rule.kind==='artifact_sha_changed'){
135
+ const actual=observed.artifact_sha256?.[rule.artifact_id]??null;
136
+ if(actual!==rule.expected_sha256) invalidated_by.push({...rule,observed_sha256:actual});
137
+ }else if(rule.kind==='policy_sha_changed'&&observed.policy_sha256!==rule.expected_sha256){
138
+ invalidated_by.push({...rule,observed_sha256:observed.policy_sha256??null});
139
+ }
140
+ }
141
+ return Object.freeze({decision_id:record.decision_id,state:invalidated_by.length?'STALE':'CURRENT',invalidated_by});
142
+ }
@@ -1,6 +1,7 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import { canonicalJson } from './canonical-json.mjs';
3
3
  import { provenanceFor, dedupeEvidence } from './context-provenance.mjs';
4
+ import { taskDagFromPlan } from './agent-governance-r42.mjs';
4
5
 
5
6
  const SECRET_KEY = /(?:^|[_-])(token|password|secret|authorization|cookie|credential|credentials|api[_-]?key|private[_-]?key|recovery)(?:$|[_-])/i;
6
7
  const HEX64 = /^[0-9a-f]{64}$/;
@@ -213,7 +214,7 @@ function historicalEvidence({ contexts, observations, loopState }) {
213
214
  };
214
215
  }
215
216
 
216
- export function buildLoopContext({ goal, policy, loopState = {}, tree = [], contexts = [], observations = [], decisions = [], projectMemory = null, desktopMemory = null, capabilities = null }) {
217
+ export function buildLoopContext({ goal, policy, loopState = {}, tree = [], contexts = [], observations = [], decisions = [], projectMemory = null, desktopMemory = null, longTermMemory = null, capabilities = null }) {
217
218
  if (!policy?.limits || !Number.isInteger(policy.limits.max_context_bytes)) throw new Error('loop context policy byte limit missing');
218
219
  const relevanceEpoch=Number.isInteger(loopState?.mutation_epoch)&&loopState.mutation_epoch>=0?loopState.mutation_epoch:0;
219
220
  const retainedContexts=normalizeEvidence(contexts,{kind:'context',relevanceEpoch});
@@ -250,7 +251,9 @@ export function buildLoopContext({ goal, policy, loopState = {}, tree = [], cont
250
251
  historical_evidence:historicalEvidence({contexts:retainedContexts,observations:retainedObservations,loopState}),
251
252
  project_memory:memory,
252
253
  desktop_memory:desktopMemory===null?null:structuredClone(desktopMemory),
254
+ long_term_memory:longTermMemory===null?null:structuredClone(longTermMemory),
253
255
  capabilities:capabilities===null?null:structuredClone(capabilities),
256
+ task_dag:loopState.plan&&typeof goal?.goal_id==='string' ? taskDagFromPlan({run_id:goal.goal_id,goal_id:goal.goal_id,plan:loopState.plan}) : null,
254
257
  profiles
255
258
  };
256
259
  return compactLoopContext(state,policy.limits.max_context_bytes);
@@ -146,6 +146,7 @@ export function deriveLoopState(goal,events) {
146
146
  replan_count:0,
147
147
  pending_action:null,
148
148
  pending_approval:false,
149
+ clarification:null,
149
150
  progress:null,
150
151
  critic:null,
151
152
  repair:null,
@@ -223,6 +224,10 @@ export function deriveLoopState(goal,events) {
223
224
  state.phase='WAITING';
224
225
  state.wait_reason=requireText(payload.reason,'loop wait reason');
225
226
  state.pending_approval=payload.requires_approval===true;
227
+ state.clarification=payload.reason==='human_input_required' ? {
228
+ question:requireText(payload.question,'loop clarification question',1000),
229
+ choices:Array.isArray(payload.choices) ? payload.choices.map((choice,index)=>requireText(choice,`loop clarification choice ${index+1}`,256)) : []
230
+ } : null;
226
231
  break;
227
232
  case 'waiting_resumed': {
228
233
  if (state.phase !== 'WAITING') throw new Error('loop waiting_resumed outside WAITING phase');
@@ -231,6 +236,7 @@ export function deriveLoopState(goal,events) {
231
236
  state.phase=resumed;
232
237
  state.wait_reason=null;
233
238
  state.pending_approval=false;
239
+ state.clarification=null;
234
240
  break;
235
241
  }
236
242
  case 'planner_requested':
@@ -255,24 +261,28 @@ export function deriveLoopState(goal,events) {
255
261
  state.phase='PLAN';
256
262
  state.wait_reason=null;
257
263
  state.pending_approval=false;
264
+ state.clarification=null;
258
265
  }
259
266
  break;
260
267
  case 'goal_cancelled':
261
268
  state.phase='FAILED';
262
269
  state.wait_reason=typeof payload.reason==='string'&&payload.reason.length>0?payload.reason:'cancelled';
263
270
  state.pending_approval=false;
271
+ state.clarification=null;
264
272
  state.pending_action=null;
265
273
  break;
266
274
  case 'goal_failed':
267
275
  state.phase='FAILED';
268
276
  state.wait_reason=typeof payload.reason==='string'&&payload.reason.length>0?payload.reason:'failed';
269
277
  state.pending_approval=false;
278
+ state.clarification=null;
270
279
  state.pending_action=null;
271
280
  break;
272
281
  case 'release_completed':
273
282
  state.phase='SUCCEEDED';
274
283
  state.wait_reason=null;
275
284
  state.pending_approval=false;
285
+ state.clarification=null;
276
286
  state.pending_action=null;
277
287
  break;
278
288
  default:
@@ -25,6 +25,17 @@ const rmdirOperation = z.strictObject({ kind:z.literal('rmdir'), path:relPath, e
25
25
  const nativeOperation = z.union([writeOperation,replaceOperation,deleteOperation,mkdirOperation,moveOperation,rmdirOperation]);
26
26
  const plannerResponse = z.strictObject({ request_id:hex64, raw_text:z.string().min(2).max(8*1024*1024),
27
27
  model:z.string().min(1).max(128).default('client-model') });
28
+ const taskContract = z.strictObject({
29
+ schema:z.literal('deadbyte.task-contract.v1'),
30
+ scope:z.array(z.string().min(1).max(512)).max(32).default([]),
31
+ non_goals:z.array(z.string().min(1).max(512)).max(24).default([]),
32
+ constraints:z.array(z.string().min(1).max(512)).max(32).default([]),
33
+ evidence_requirements:z.array(z.string().min(1).max(512)).max(32).default([]),
34
+ risk_level:z.enum(['low','medium','high']).default('medium'),
35
+ clarification_policy:z.enum(['ask_when_blocked','fail_closed']).default('ask_when_blocked'),
36
+ project_default:z.enum(['lightweight','structured','agentic']).default('structured'),
37
+ explicit_override:z.enum(['lightweight','structured','agentic']).nullable().default(null)
38
+ });
28
39
  function result(schema,value,isError=false) { return autonomousStructuredResult(schema,value,isError); }
29
40
  function fail(schema,error,status='failed') { return result(schema,{ status, error:String(error) },true); }
30
41
 
@@ -60,11 +71,12 @@ export function registerAutonomousTools(server,{ autonomousRuntime, nativeDiffRu
60
71
  description:'Submit one bounded R24 production goal. Execution requires separate live coding and autonomous leases.',
61
72
  inputSchema:z.strictObject({ submission_id:id, root_id:id, title:z.string().max(160).default(''),
62
73
  goal:z.string().min(1).max(8192), acceptance:z.string().max(4096).default(''),
74
+ task_contract:taskContract.nullable().default(null),
63
75
  max_iterations:z.number().int().min(1).max(64).nullable().default(null) }),
64
76
  outputSchema:autonomousGoalSubmitOutputSchema
65
- },async({submission_id,root_id,title,goal,acceptance,max_iterations})=>{ try {
77
+ },async({submission_id,root_id,title,goal,acceptance,task_contract,max_iterations})=>{ try {
66
78
  return result(autonomousGoalSubmitOutputSchema,await autonomousRuntime.submit({ submissionId:submission_id,
67
- rootId:root_id,title,goal,acceptance,maxIterations:max_iterations })); }
79
+ rootId:root_id,title,goal,acceptance,taskContract:task_contract,maxIterations:max_iterations })); }
68
80
  catch(error){ return fail(autonomousGoalSubmitOutputSchema,error); } });
69
81
  server.registerTool('autonomous_goal_run',{
70
82
  description:'Advance one autonomous production goal through inspect/native-diff/build/test/benchmark/replan cycles. Client-planner mode returns a typed input_required sentinel for the Bridge MRTR adapter.',
@@ -100,11 +112,14 @@ export function registerAutonomousTools(server,{ autonomousRuntime, nativeDiffRu
100
112
  catch(error){ return fail(autonomousGoalCancelOutputSchema,error); } });
101
113
 
102
114
  server.registerTool('autonomous_goal_approve',{
103
- description:'Approve or reject resuming a paused autonomous goal. This never arms or renews any lease and cannot bypass release evidence.',
104
- inputSchema:z.strictObject({ goal_id:hex64, decision:z.enum(['approve','reject']).default('approve') }),
115
+ description:'Approve or reject resuming a paused autonomous goal, optionally supplying the bounded answer required by a typed human clarification. This never arms or renews any lease and cannot bypass release evidence.',
116
+ inputSchema:z.strictObject({ goal_id:hex64, decision:z.enum(['approve','reject']).default('approve'),
117
+ answer:z.string().min(1).max(4096).nullable().default(null),
118
+ approval_subject_sha256:hex64.nullable().default(null),
119
+ expires_in_ms:z.number().int().min(1000).max(3600000).default(300000) }),
105
120
  outputSchema:autonomousGoalApproveOutputSchema
106
- },async({goal_id,decision})=>{ try { return result(autonomousGoalApproveOutputSchema,
107
- await autonomousRuntime.approve({goalId:goal_id,decision})); }
121
+ },async({goal_id,decision,answer,approval_subject_sha256,expires_in_ms})=>{ try { return result(autonomousGoalApproveOutputSchema,
122
+ await autonomousRuntime.approve({goalId:goal_id,decision,answer,approvalSubjectSha256:approval_subject_sha256,expiresInMs:expires_in_ms})); }
108
123
  catch(error){ return fail(autonomousGoalApproveOutputSchema,error); } });
109
124
 
110
125
  server.registerTool('autonomous_goal_verify',{
@@ -15,12 +15,28 @@ const loopProgress = z.strictObject({
15
15
  const loopPendingAction = z.strictObject({
16
16
  action_id:hex64, request_sha256:hex64, kind:z.string().regex(/^[A-Za-z0-9._-]{1,64}$/)
17
17
  });
18
+ const loopClarification = z.strictObject({
19
+ question:z.string().min(1).max(1000), choices:z.array(z.string().min(1).max(256)).max(5)
20
+ });
21
+ const loopApprovalSubject = z.strictObject({
22
+ goal_id:hex64,reviewed_event_seq:z.number().int().min(1),reviewed_event_sha256:hex64,
23
+ journal_head_sha256:hex64,scope:z.enum(['resume_goal','human_clarification','desktop_resume','interrupted_effect_resume']),
24
+ subject:z.strictObject({reason:z.string().min(1).max(1024),waiting_payload_sha256:hex64}),approval_subject_sha256:hex64
25
+ });
26
+ const taskDagTask=z.strictObject({task_id:z.string().regex(/^[A-Za-z0-9._-]{1,64}$/),depends_on:z.array(z.string()).max(256),
27
+ input_artifacts:z.array(z.string()).max(128),output_artifacts:z.array(z.string()).max(128),
28
+ state:z.enum(['PENDING','RUNNING','COMPLETE','FAILED','STALE'])});
29
+ const taskDag=z.strictObject({schema:z.literal('deadbyte.task-dag.v1'),run_id:z.string().regex(/^[A-Za-z0-9._-]{1,96}$/),
30
+ goal_id:hex64,tasks:z.array(taskDagTask).min(1).max(256),dag_sha256:hex64});
18
31
  const publicLoopSchema = z.strictObject({
19
32
  schema:z.literal('deadbyte.autonomous-loop-state.v1'), phase:loopPhase,
20
33
  plan_id:hex64.nullable(), plan_version:z.number().int().min(1).nullable(),
21
34
  current_step:loopStep.nullable(), replan_count:z.number().int().min(0),
22
35
  progress:loopProgress.nullable(), pending_action:loopPendingAction.nullable(),
23
- pending_approval:z.boolean(), wait_reason:z.string().min(1).max(1024).nullable()
36
+ pending_approval:z.boolean(), wait_reason:z.string().min(1).max(1024).nullable(),
37
+ clarification:loopClarification.nullable().default(null),
38
+ approval_subject:loopApprovalSubject.nullable().default(null),
39
+ task_dag:taskDag.nullable().default(null)
24
40
  });
25
41
  function requireFields(value,ctx,fields) {
26
42
  for (const field of fields) if (value[field] === undefined) ctx.addIssue({ code:'custom', path:[field], message:`${field} is required` });
@@ -52,7 +68,7 @@ export const autonomousSessionStatusOutputSchema = statusContract({
52
68
  shape:{ configured:z.literal(true).optional(), armed:z.boolean().optional(), autonomous_armed:z.boolean().optional(),
53
69
  autonomous_reason:z.string().optional(), autonomous_expires_at_utc:z.string().nullable().optional(),
54
70
  coding_armed:z.boolean().optional(), coding_reason:z.string().optional(), root_ids:z.array(z.string()).max(64).optional(),
55
- planner_backend:z.enum(['client_sampling','openai_compatible']).optional(), profile_ids:z.array(z.string()).max(128).optional(),
71
+ planner_backend:z.enum(['client_sampling','openai_compatible','openai_responses']).optional(), profile_ids:z.array(z.string()).max(128).optional(),
56
72
  policy_sha256:hex64.optional(), coding_policy_sha256:hex64.optional() }
57
73
  });
58
74
 
@@ -163,6 +163,9 @@ export const r34PlannerDecisionSchema = z.discriminatedUnion('kind',[
163
163
  step_id:z.string().regex(ID),evidence:z.array(r34EvidenceSchema).min(1).max(32)}),
164
164
  z.strictObject({schema:z.literal('deadbyte.autonomous-decision.v2'),kind:z.literal('replan'),
165
165
  reason:z.string().min(1).max(512),steps:z.array(r34PlanStepSchema).min(1).max(24)}),
166
+ z.strictObject({schema:z.literal('deadbyte.autonomous-decision.v2'),kind:z.literal('clarify'),
167
+ question:z.string().min(1).max(1000),
168
+ choices:z.array(z.string().min(1).max(256)).min(2).max(5).default([])}),
166
169
  z.strictObject({schema:z.literal('deadbyte.autonomous-decision.v2'),kind:z.literal('pause'),
167
170
  reason:z.string().min(1).max(1000)}),
168
171
  z.strictObject({schema:z.literal('deadbyte.autonomous-decision.v2'),kind:z.literal('finish'),