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
@@ -276,7 +276,7 @@ export function parseR34PlannerDecision(rawText, policy) {
276
276
  assertR34UniqueSteps(decision.steps,'R34 replan');
277
277
  return decision;
278
278
  }
279
- if (decision.kind === 'pause' || decision.kind === 'finish') return decision;
279
+ if (decision.kind === 'clarify' || decision.kind === 'pause' || decision.kind === 'finish') return decision;
280
280
  throw new Error('R34 planner decision kind unsupported');
281
281
  }
282
282
 
@@ -355,6 +355,7 @@ export function buildPlannerPrompt({ goal, policy, view }) {
355
355
  decisions:view.recent_decisions ?? [],
356
356
  projectMemory:view.project_memory ?? null,
357
357
  desktopMemory:view.desktop_memory ?? null,
358
+ longTermMemory:view.long_term_memory ?? null,
358
359
  capabilities:view.capabilities ?? null
359
360
  });
360
361
  const stateJson = canonicalJson(state);
@@ -362,7 +363,7 @@ export function buildPlannerPrompt({ goal, policy, view }) {
362
363
  'You are the DEADBYTE R24 autonomous coding planner.',
363
364
  'Return exactly one JSON object and no Markdown or prose outside JSON.',
364
365
  `The object schema is ${AUTONOMOUS_DECISION_SCHEMA}.`,
365
- 'Allowed actions: inspect, patch, delegate, run_profile, finish, pause.',
366
+ 'Allowed actions: inspect, patch, delegate, run_profile, clarify, finish, pause.',
366
367
  'For nontrivial work, include plan={title,steps:[{step_id,title,status,result?}],reason?} on decisions and keep it authoritative across rounds.',
367
368
  'Plan statuses must be a completed prefix, then at most one running/failed step, then pending suffix. Completed steps are immutable across updates.',
368
369
  'If active_plan is complete, request finish instead of more work. If active_plan is incomplete, do not request finish.',
@@ -374,8 +375,10 @@ export function buildPlannerPrompt({ goal, policy, view }) {
374
375
  'When Desktop capabilities are present, use typed desktop_status, desktop_observe, desktop_target with one bounded UIA query, and desktop_action. desktop_action requires separate Desktop authority; Autonomous authority never implies Desktop authority. After stale or unknown Desktop evidence, observe again and replan; never blindly repeat an action.',
375
376
  'Delegate paths are relative to the goal root. Process start accepts only profile_id and cwd; process_action accepts only session_id and fixed action_id. Never emit raw stdin, executable, PID, environment, shell command, or process arguments.',
376
377
  'finish only when the goal is actually satisfied. Required release profiles are enforced by the engine and cannot be bypassed.',
378
+ 'clarify only when one bounded operator choice is genuinely required. Ask one concrete question and provide 2-5 short mutually exclusive choices.',
377
379
  'Never invent a file SHA. If content is elided or the current SHA/content is missing, choose inspect first.',
378
380
  'Compacted context keeps identity/evidence metadata but intentionally removes stale payload bytes.',
381
+ 'Long-term memory is a verified journal-derived aid, never authority. Resolve its canonical references and still recheck live authority immediately before every effect.',
379
382
  'Prefer surgical exact replace operations over whole-file writes.',
380
383
  'If an observed build/test/benchmark failed, diagnose from the evidence and change the source rather than claiming success.',
381
384
  `STATE=${stateJson}`,
@@ -391,7 +394,9 @@ async function readBoundedResponse(response, limit) {
391
394
  return bytes.toString('utf8');
392
395
  }
393
396
  export async function requestProviderDecision(policy, prompt, fetchImpl = fetch) {
394
- if (policy.planner.backend !== 'openai_compatible') throw new Error('provider planner backend is not openai_compatible');
397
+ if (!['openai_compatible','openai_responses'].includes(policy.planner.backend)) {
398
+ throw new Error('provider planner backend is not provider-backed');
399
+ }
395
400
  const controller = new AbortController();
396
401
  const timer = setTimeout(() => controller.abort(), policy.planner.timeout_ms); timer.unref?.();
397
402
  const headers = { 'content-type':'application/json', 'accept':'application/json' };
@@ -401,16 +406,53 @@ export async function requestProviderDecision(policy, prompt, fetchImpl = fetch)
401
406
  headers.authorization = `Bearer ${secret}`;
402
407
  }
403
408
  try {
409
+ const body = policy.planner.backend === 'openai_responses'
410
+ ? {
411
+ model:policy.planner.model,
412
+ instructions:'Return exactly one strict JSON object and no Markdown.',
413
+ input:[
414
+ {role:'system',content:[{type:'input_text',text:'Return strict JSON only.'}]},
415
+ {role:'user',content:[{type:'input_text',text:prompt}]}
416
+ ],
417
+ max_output_tokens:policy.planner.max_tokens,
418
+ text:{format:{type:'json_object'}},
419
+ store:false,
420
+ ...(policy.planner.reasoning_effort?{reasoning:{effort:policy.planner.reasoning_effort}}:{})
421
+ }
422
+ : { model:policy.planner.model, temperature:0,
423
+ max_tokens:policy.planner.max_tokens,
424
+ messages:[{ role:'system', content:'Return strict JSON only.' },{ role:'user', content:prompt }] };
404
425
  const response = await fetchImpl(policy.planner.endpoint, {
405
426
  method:'POST', redirect:'error', signal:controller.signal, headers,
406
- body:JSON.stringify({ model:policy.planner.model, temperature:0,
407
- max_tokens:policy.planner.max_tokens,
408
- messages:[{ role:'system', content:'Return strict JSON only.' },{ role:'user', content:prompt }] })
427
+ body:JSON.stringify(body)
409
428
  });
410
429
  const rawBody = await readBoundedResponse(response, policy.planner.max_response_bytes);
411
430
  if (!response.ok) throw new Error(`planner HTTP ${response.status}: ${rawBody.slice(0,512)}`);
412
431
  let parsed;
413
432
  try { parsed = JSON.parse(rawBody); } catch { throw new Error('planner HTTP response is not JSON'); }
433
+ if (policy.planner.backend === 'openai_responses') {
434
+ if (parsed?.status !== 'completed') throw new Error(`planner Responses API response not completed: ${String(parsed?.status ?? 'missing')}`);
435
+ const content=[];
436
+ let refused=false;
437
+ for (const item of Array.isArray(parsed?.output) ? parsed.output : []) {
438
+ if (item?.type !== 'message') continue;
439
+ for (const part of Array.isArray(item.content) ? item.content : []) {
440
+ if (part?.type === 'refusal') refused=true;
441
+ if (part?.type === 'output_text' && typeof part.text === 'string') content.push(part.text);
442
+ }
443
+ }
444
+ if (refused) throw new Error('planner Responses API refusal');
445
+ if (content.length < 1) throw new Error('planner Responses API response missing output_text');
446
+ const usage=parsed?.usage && Number.isInteger(parsed.usage.input_tokens) && Number.isInteger(parsed.usage.output_tokens) && Number.isInteger(parsed.usage.total_tokens)
447
+ ? {input_tokens:parsed.usage.input_tokens,output_tokens:parsed.usage.output_tokens,total_tokens:parsed.usage.total_tokens}
448
+ : null;
449
+ return {
450
+ backend:'openai_responses', model:typeof parsed.model === 'string' ? parsed.model.slice(0,128) : policy.planner.model,
451
+ raw_text:content.join(''),
452
+ response_id:typeof parsed.id === 'string' ? parsed.id.slice(0,160) : null,
453
+ usage
454
+ };
455
+ }
414
456
  const content = parsed?.choices?.[0]?.message?.content;
415
457
  if (typeof content !== 'string') throw new Error('planner HTTP response missing choices[0].message.content');
416
458
  return { backend:'openai_compatible', model:typeof parsed.model === 'string' ? parsed.model : policy.planner.model,
@@ -33,7 +33,7 @@ function normalizeProviderCircuit(raw) {
33
33
  function normalizePlanner(raw) {
34
34
  if (!raw || typeof raw !== 'object' || Array.isArray(raw)) throw new Error('autonomous planner missing');
35
35
  const backend = raw.backend;
36
- if (!['client_sampling', 'openai_compatible'].includes(backend)) throw new Error('autonomous planner backend invalid');
36
+ if (!['client_sampling', 'openai_compatible', 'openai_responses'].includes(backend)) throw new Error('autonomous planner backend invalid');
37
37
  const common = { backend, max_tokens: integer(raw.max_tokens, 'planner.max_tokens', 256, 16384, 4096) };
38
38
  if (backend === 'client_sampling') return common;
39
39
  if (typeof raw.endpoint !== 'string') throw new Error('planner.endpoint required');
@@ -46,12 +46,20 @@ function normalizePlanner(raw) {
46
46
  if (typeof raw.model !== 'string' || raw.model.length < 1 || raw.model.length > 128) throw new Error('planner.model invalid');
47
47
  const apiKeyEnv = raw.api_key_env ?? null;
48
48
  if (apiKeyEnv !== null && !ENV_RE.test(apiKeyEnv)) throw new Error('planner.api_key_env invalid');
49
- return {
49
+ const provider = {
50
50
  ...common, endpoint: endpoint.toString(), model: raw.model, api_key_env: apiKeyEnv,
51
51
  timeout_ms: integer(raw.timeout_ms, 'planner.timeout_ms', 1000, 300000, 60000),
52
52
  max_response_bytes: integer(raw.max_response_bytes, 'planner.max_response_bytes', 4096, 2 * 1024 * 1024, 512 * 1024),
53
53
  circuit:normalizeProviderCircuit(raw.circuit)
54
54
  };
55
+ if (backend === 'openai_responses') {
56
+ const effort = raw.reasoning_effort ?? null;
57
+ if (effort !== null && !['minimal','low','medium','high','xhigh'].includes(effort)) {
58
+ throw new Error('planner.reasoning_effort invalid');
59
+ }
60
+ return { ...provider, reasoning_effort:effort, store:false };
61
+ }
62
+ return provider;
55
63
  }
56
64
  function normalizeProfile(id, raw, codingPolicy) {
57
65
  if (!ID_RE.test(id)) throw new Error(`invalid autonomous profile '${id}'`);
@@ -10,6 +10,7 @@ import { createPlan, replanPlan, completePlanStep, planIsComplete as r34PlanIsCo
10
10
  import { deriveLoopState, repairFingerprint } from './autonomous-loop-state.mjs';
11
11
  import { judgeProgress, stallDisposition } from './autonomous-progress.mjs';
12
12
  import { classifyProviderFailure, deriveCircuit, providerCallDisposition, providerCircuitId } from './provider-circuit.mjs';
13
+ import { bindApprovalSubject, deriveEffectiveRigor, taskDagFromPlan, validateBoundApproval } from './agent-governance-r42.mjs';
13
14
  import { verifyObservationReceiptFile } from './observation-runtime.mjs';
14
15
  import { R36_CAPABILITY_LEDGER } from './capability-ledger.mjs';
15
16
  import { deriveAgentMemory } from './agent-memory-plane.mjs';
@@ -129,6 +130,11 @@ function deriveState(goal, events) {
129
130
  const binding = { ...p, event_sha256:event.event_sha256 };
130
131
  observations.push(binding);
131
132
  }
133
+ if (event.type === 'human_input_provided') {
134
+ observations.push({kind:'human_input',question:p.question,answer:p.answer,
135
+ answer_sha256:p.answer_sha256,trust_class:'operator_input',observed_at_utc:event.created_at_utc,
136
+ event_sha256:event.event_sha256});
137
+ }
132
138
  if (event.type === 'native_diff_committed') {
133
139
  mutationEpoch = Number(p.mutation_epoch ?? mutationEpoch + 1); mutationCount += Number(p.mutation_count ?? 1);
134
140
  diffs.push({ ...p, event_sha256:event.event_sha256 });
@@ -325,7 +331,31 @@ function releaseReadiness(policy, state) {
325
331
  });
326
332
  return { ready:results.every(item => item.passed), mutation_epoch:state.mutation_epoch, required_profiles:results };
327
333
  }
328
- function normalizeGoal(policy, { submissionId, rootId, title = '', goal, acceptance = '', maxIterations = null }) {
334
+ function normalizeTaskContract(raw) {
335
+ const value=raw ?? {schema:'deadbyte.task-contract.v1',scope:[],non_goals:[],constraints:[],
336
+ evidence_requirements:[],risk_level:'medium',clarification_policy:'ask_when_blocked',
337
+ project_default:'structured',explicit_override:null};
338
+ if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error('autonomous task contract invalid');
339
+ const allowed=['schema','scope','non_goals','constraints','evidence_requirements','risk_level','clarification_policy','project_default','explicit_override'];
340
+ const unknown=Object.keys(value).filter(key=>!allowed.includes(key));
341
+ if (unknown.length) throw new Error(`autonomous task contract unknown field '${unknown[0]}'`);
342
+ if (value.schema !== 'deadbyte.task-contract.v1') throw new Error('autonomous task contract schema invalid');
343
+ const list=(field,maxItems,maxLength)=>{
344
+ const items=value[field] ?? [];
345
+ if (!Array.isArray(items) || items.length > maxItems || items.some(item=>typeof item !== 'string' || item.length < 1 || item.length > maxLength || item.includes('\0'))) {
346
+ throw new Error(`autonomous task contract ${field} invalid`);
347
+ }
348
+ return [...items];
349
+ };
350
+ if (!['low','medium','high'].includes(value.risk_level)) throw new Error('autonomous task contract risk_level invalid');
351
+ if (!['ask_when_blocked','fail_closed'].includes(value.clarification_policy)) throw new Error('autonomous task contract clarification_policy invalid');
352
+ const rigor=deriveEffectiveRigor({project_default:value.project_default??'structured',risk_level:value.risk_level,
353
+ explicit_override:value.explicit_override??null});
354
+ return Object.freeze({schema:value.schema,scope:list('scope',32,512),non_goals:list('non_goals',24,512),
355
+ constraints:list('constraints',32,512),evidence_requirements:list('evidence_requirements',32,512),
356
+ risk_level:value.risk_level,clarification_policy:value.clarification_policy,...rigor});
357
+ }
358
+ function normalizeGoal(policy, { submissionId, rootId, title = '', goal, acceptance = '', taskContract = null, maxIterations = null }) {
329
359
  if (!ID_RE.test(submissionId ?? '')) throw new Error('autonomous submission_id invalid');
330
360
  if (!policy.root_ids.includes(rootId)) throw new Error(`autonomous root '${rootId}' is not allowed`);
331
361
  if (typeof title !== 'string' || title.length > 160) throw new Error('autonomous title must be <=160 characters');
@@ -335,7 +365,7 @@ function normalizeGoal(policy, { submissionId, rootId, title = '', goal, accepta
335
365
  if (!Number.isInteger(iterations) || iterations < 1 || iterations > policy.limits.max_iterations) throw new Error('autonomous max_iterations exceeds policy');
336
366
  const body = { schema:AUTONOMOUS_GOAL_SCHEMA, policy_sha256:policy.policy_sha256,
337
367
  coding_policy_sha256:policy.coding_policy_sha256, submission_id:submissionId, root_id:rootId,
338
- title, goal, acceptance, max_iterations:iterations };
368
+ title, goal, acceptance, task_contract:normalizeTaskContract(taskContract),max_iterations:iterations };
339
369
  return Object.freeze({ ...body, goal_sha256:sha256Object(body) });
340
370
  }
341
371
 
@@ -360,20 +390,24 @@ function configuredCapabilityManifest({machineFsRuntime,observationRuntime,proce
360
390
  entries:Object.freeze(entries)});
361
391
  }
362
392
 
363
- async function plannerView(goal, state, events, codingRuntime, capabilityManifest, desktopMemoryProvider=null) {
393
+ async function plannerView(goal, state, events, codingRuntime, capabilityManifest, desktopMemoryProvider=null,memoryProvider=null) {
364
394
  const tree = await codingRuntime.tree({ rootId:goal.root_id, path:'.', maxDepth:4, maxEntries:600 });
365
395
  const memory=deriveAgentMemory(events,{maxArchival:24});
366
396
  const desktopMemory=desktopMemoryProvider?await desktopMemoryProvider.plannerContext():null;
397
+ const codingAuthority=memoryProvider?await codingRuntime.sessionStatus():null;
398
+ const longTerm=memoryProvider?await memoryProvider.refresh({goal,events,currentPlan:state.active_plan,currentFiles:[],currentSymbols:[],
399
+ currentAuthority:{coding:{armed:codingAuthority.armed,reason:codingAuthority.reason}}}):null;
367
400
  return { mutation_epoch:state.mutation_epoch, planner_round:state.planner_round, tree:tree.entries,
368
401
  contexts:state.contexts.slice(-16), observations:state.observations.slice(-24), active_plan:state.active_plan,
369
402
  capabilities:capabilityManifest, project_memory:memory, desktop_memory:desktopMemory,
403
+ long_term_memory:longTerm?.planner_context??null,memory_evidence:longTerm,
370
404
  recent_decisions:state.decisions.slice(-8).map(item => ({ planner_round:item.planner_round,
371
405
  action:item.decision?.action, summary:item.decision?.summary })) };
372
406
  }
373
407
  function requestIdFor(goalId, plannerRound, journalHead) {
374
408
  return sha256Object({ schema:'deadbyte.autonomous-planner-request.v1', goal_id:goalId, planner_round:plannerRound, journal_head_sha256:journalHead });
375
409
  }
376
- async function requestPlanner(ctx, goal, events, state, policy, codingRuntime, capabilityManifest, desktopMemoryProvider, signingKeyPath) {
410
+ async function requestPlanner(ctx, goal, events, state, policy, codingRuntime, capabilityManifest, desktopMemoryProvider,memoryProvider, signingKeyPath) {
377
411
  if (state.pending_request) return state.pending_request;
378
412
  const round = state.planner_round + 1;
379
413
  if (round > goal.max_iterations) {
@@ -384,8 +418,9 @@ async function requestPlanner(ctx, goal, events, state, policy, codingRuntime, c
384
418
  await appendEvent(ctx,events,signingKeyPath,'goal_paused',{ reason:'wall_time_limit', max_wall_ms:policy.limits.max_wall_ms });
385
419
  return null;
386
420
  }
387
- const view = await plannerView(goal,state,events,codingRuntime,capabilityManifest,desktopMemoryProvider);
388
- let prompt = buildPlannerPrompt({ goal:{ title:goal.title, goal:goal.goal, acceptance:goal.acceptance }, policy, view });
421
+ const view = await plannerView(goal,state,events,codingRuntime,capabilityManifest,desktopMemoryProvider,memoryProvider);
422
+ let prompt = buildPlannerPrompt({ goal:{ goal_id:goal.goal_id,title:goal.title, goal:goal.goal, acceptance:goal.acceptance,
423
+ task_contract:goal.task_contract }, policy, view });
389
424
  const repair = [...(state.planner_rejections ?? [])].reverse().find(item => item.planner_round === round) ?? null;
390
425
  if (repair) {
391
426
  const repairState = canonicalJson({ request_id:repair.request_id, response_sha256:repair.response_sha256,
@@ -397,6 +432,14 @@ Repair only the decision contract. Return one corrected strict JSON decision; do
397
432
  const requestId = requestIdFor(goal.goal_id,round,state.journal_head_sha256);
398
433
  const payload = { request_id:requestId, planner_round:round, mutation_epoch:state.mutation_epoch,
399
434
  prompt, prompt_sha256:sha256Bytes(Buffer.from(prompt,'utf8')), backend:policy.planner.backend,
435
+ ...(view.memory_evidence?{
436
+ working_memory_sha256:view.memory_evidence.working_memory_sha256,
437
+ memory_snapshot_sha256:view.memory_evidence.snapshot_sha256,
438
+ memory_index_sha256:view.memory_evidence.index_sha256,
439
+ historical_archive_sha256:view.memory_evidence.historical_archive_sha256,
440
+ historical_index_sha256:view.memory_evidence.historical_index_sha256,
441
+ memory_source_release_manifest:view.memory_evidence.source_release_manifest
442
+ }:{}),
400
443
  ...(repair ? { repair_of_request_id:repair.request_id, rejection_event_sha256:repair.event_sha256 } : {}) };
401
444
  await appendEvent(ctx,events,signingKeyPath,'planner_requested',payload);
402
445
  return payload;
@@ -440,7 +483,24 @@ function legacyPublicLoopPhase(phase) {
440
483
  return ({PLAN:'PLANNING',INSPECT:'INSPECTING',ACT:'ACTING',VERIFY:'VERIFYING',CRITIC:'REPLANNING',
441
484
  REPAIR:'REPLANNING',RELEASE:'VERIFYING',WAITING:'WAITING',SUCCEEDED:'COMPLETE',FAILED:'WAITING'})[phase] ?? 'WAITING';
442
485
  }
443
- function publicLoopState(loop) {
486
+ function approvalScopeFor(reason){
487
+ if(reason==='human_input_required') return 'human_clarification';
488
+ if(String(reason??'').startsWith('desktop_')) return 'desktop_resume';
489
+ if(['ambiguous_interrupted_action','profile_execution_without_receipt'].includes(reason)) return 'interrupted_effect_resume';
490
+ return 'resume_goal';
491
+ }
492
+ function pendingApprovalSubject(goal,events,loop){
493
+ if(!loop?.pending_approval) return null;
494
+ const waiting=[...events].reverse().find(event=>event.type==='waiting_entered')??null;
495
+ if(!waiting) return null;
496
+ const payload=waiting.payload??{};
497
+ return bindApprovalSubject({
498
+ goal_id:goal.goal_id,reviewed_event_seq:waiting.seq,reviewed_event_sha256:waiting.event_sha256,
499
+ journal_head_sha256:events.at(-1)?.event_sha256??ZERO_HASH,scope:approvalScopeFor(payload.reason),
500
+ subject:{reason:payload.reason??loop.wait_reason??'paused',waiting_payload_sha256:sha256Object(payload)}
501
+ });
502
+ }
503
+ function publicLoopState(loop,goal=null,events=null) {
444
504
  if (!loop) return null;
445
505
  const currentStep=loop.current_step ? {
446
506
  step_id:loop.current_step.step_id,intent:loop.current_step.intent,status:loop.current_step.status
@@ -456,15 +516,18 @@ function publicLoopState(loop) {
456
516
  return {
457
517
  schema:'deadbyte.autonomous-loop-state.v1',phase:legacyPublicLoopPhase(loop.phase),plan_id:loop.plan_id,plan_version:loop.plan_version,
458
518
  current_step:currentStep,replan_count:loop.replan_count,progress,
459
- pending_action:pendingAction,pending_approval:loop.pending_approval,wait_reason:loop.wait_reason
519
+ pending_action:pendingAction,pending_approval:loop.pending_approval,wait_reason:loop.wait_reason,
520
+ clarification:loop.clarification ?? null,
521
+ approval_subject:goal&&events?pendingApprovalSubject(goal,events,loop):null,
522
+ task_dag:goal&&loop.plan?taskDagFromPlan({run_id:goal.goal_id,goal_id:goal.goal_id,plan:loop.plan}):null
460
523
  };
461
524
  }
462
525
  function withLoopResult(goal,events,result) {
463
- const loop=publicLoopState(loopStateOrNull(goal,events));
526
+ const loop=publicLoopState(loopStateOrNull(goal,events),goal,events);
464
527
  return loop ? {...result,loop} : result;
465
528
  }
466
529
  function providerCircuitSnapshot(policy,events,observedAtUtc=new Date().toISOString()) {
467
- if (policy.planner.backend !== 'openai_compatible') return null;
530
+ if (!['openai_compatible','openai_responses'].includes(policy.planner.backend)) return null;
468
531
  return deriveCircuit(events,providerCircuitId(policy.planner),policy.planner.circuit,observedAtUtc);
469
532
  }
470
533
  async function enterProviderCircuitWait({ctx,events,goal,policy,signingKeyPath,reason,circuit}) {
@@ -505,7 +568,9 @@ async function requestProviderWithCircuit({ctx,events,goal,policy,pending,signin
505
568
  try {
506
569
  const response=await requestProviderDecision(policy,pending.prompt);
507
570
  await appendEvent(ctx,events,signingKeyPath,'provider_call_succeeded',{
508
- provider_id:providerId,request_id:pending.request_id,probe:disposition.probe===true
571
+ provider_id:providerId,request_id:pending.request_id,probe:disposition.probe===true,
572
+ ...(response.response_id?{response_id:response.response_id}:{}),
573
+ ...(response.usage?{usage:response.usage}:{})
509
574
  });
510
575
  return {response};
511
576
  } catch (error) {
@@ -524,14 +589,14 @@ async function requestProviderWithCircuit({ctx,events,goal,policy,pending,signin
524
589
  throw error;
525
590
  }
526
591
  }
527
- async function acceptPlannerDecision({ ctx, events, goal, state, policy, codingRuntime, capabilityManifest, desktopMemoryProvider, signingKeyPath, plannerResponse }) {
592
+ async function acceptPlannerDecision({ ctx, events, goal, state, policy, codingRuntime, capabilityManifest, desktopMemoryProvider,memoryProvider, signingKeyPath, plannerResponse }) {
528
593
  let currentState = state;
529
- let pending = currentState.pending_request ?? await requestPlanner(ctx,goal,events,currentState,policy,codingRuntime,capabilityManifest,desktopMemoryProvider,signingKeyPath);
594
+ let pending = currentState.pending_request ?? await requestPlanner(ctx,goal,events,currentState,policy,codingRuntime,capabilityManifest,desktopMemoryProvider,memoryProvider,signingKeyPath);
530
595
  if (!pending) return null;
531
596
  let suppliedResponse = plannerResponse;
532
597
  while (pending) {
533
598
  let response;
534
- if (policy.planner.backend === 'openai_compatible') {
599
+ if (['openai_compatible','openai_responses'].includes(policy.planner.backend)) {
535
600
  const provider=await requestProviderWithCircuit({ctx,events,goal,policy,pending,signingKeyPath});
536
601
  if (provider.waiting) return {needs_planner:false,rejected:false,paused:true,provider_waiting:true};
537
602
  response=provider.response;
@@ -565,7 +630,7 @@ async function acceptPlannerDecision({ ctx, events, goal, state, policy, codingR
565
630
  return { needs_planner:false, rejected:true, paused:true };
566
631
  }
567
632
  currentState = deriveState(goal,events);
568
- pending = await requestPlanner(ctx,goal,events,currentState,policy,codingRuntime,capabilityManifest,desktopMemoryProvider,signingKeyPath);
633
+ pending = await requestPlanner(ctx,goal,events,currentState,policy,codingRuntime,capabilityManifest,desktopMemoryProvider,memoryProvider,signingKeyPath);
569
634
  if (!pending) return null;
570
635
  if (policy.planner.backend === 'client_sampling') return { needs_planner:true, request:pending };
571
636
  continue;
@@ -573,6 +638,14 @@ async function acceptPlannerDecision({ ctx, events, goal, state, policy, codingR
573
638
  const event = await appendEvent(ctx,events,signingKeyPath,'planner_decision',{
574
639
  request_id:pending.request_id, planner_round:pending.planner_round, mutation_epoch:pending.mutation_epoch,
575
640
  backend:response.backend, model:response.model ?? 'unknown', response_sha256:sha256Bytes(Buffer.from(response.raw_text,'utf8')),
641
+ ...(response.response_id?{response_id:response.response_id}:{}),
642
+ ...(response.usage?{usage:response.usage}:{}),
643
+ ...(pending.working_memory_sha256?{
644
+ working_memory_sha256:pending.working_memory_sha256,memory_snapshot_sha256:pending.memory_snapshot_sha256,
645
+ memory_index_sha256:pending.memory_index_sha256,
646
+ historical_archive_sha256:pending.historical_archive_sha256,historical_index_sha256:pending.historical_index_sha256,
647
+ memory_source_release_manifest:pending.memory_source_release_manifest
648
+ }:{}),
576
649
  decision
577
650
  });
578
651
  return { needs_planner:false, event, decision };
@@ -1488,6 +1561,20 @@ async function executeR34Decision({ctx,events,goal,state,decisionEvent,decision,
1488
1561
  return r34EnterWaiting({ctx,events,goal,signingKeyPath,reason:decision.reason,resumePhase:loop.phase});
1489
1562
  }
1490
1563
 
1564
+ if (decision.kind === 'clarify') {
1565
+ await appendEvent(ctx,events,signingKeyPath,'human_input_requested',{
1566
+ decision_event_sha256:decisionEvent.event_sha256,question:decision.question,choices:decision.choices
1567
+ });
1568
+ await appendEvent(ctx,events,signingKeyPath,'waiting_entered',{
1569
+ reason:'human_input_required',requires_approval:true,resume_phase:'PLAN',
1570
+ question:decision.question,choices:decision.choices
1571
+ });
1572
+ await appendEvent(ctx,events,signingKeyPath,'goal_paused',{
1573
+ reason:'human_input_required',decision_event_sha256:decisionEvent.event_sha256
1574
+ });
1575
+ return {status:'paused',reason:'human_input_required'};
1576
+ }
1577
+
1491
1578
  if (decision.kind === 'finish') {
1492
1579
  if (!r34PlanIsComplete(loop.plan)) {
1493
1580
  await appendEvent(ctx,events,signingKeyPath,'plan_guard_blocked',{
@@ -1658,7 +1745,7 @@ function terminalState(state) {
1658
1745
  }
1659
1746
  function pauseState(state) { return state.state === 'paused'; }
1660
1747
  async function resumeProviderWaitIfReady({ctx,journal,goal,state,policy,signingKeyPath}) {
1661
- if (state.state!=='paused'||state.reason!=='provider_circuit_open'||policy.planner.backend!=='openai_compatible') return state;
1748
+ if (state.state!=='paused'||state.reason!=='provider_circuit_open'||!['openai_compatible','openai_responses'].includes(policy.planner.backend)) return state;
1662
1749
  const circuit=providerCircuitSnapshot(policy,journal);
1663
1750
  const disposition=providerCallDisposition(circuit);
1664
1751
  if (!disposition.allowed||circuit.state!=='HALF_OPEN') return state;
@@ -1678,7 +1765,7 @@ function isAuthorityUnavailable(error) {
1678
1765
 
1679
1766
  export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRuntime, machineFsRuntime = null,
1680
1767
  observationRuntime = null, processRuntime = null, semanticRuntime = null, desktopRuntime = null,
1681
- desktopMemoryProvider = null, signingKeyPath, verifyKeyPath }) {
1768
+ desktopMemoryProvider = null,memoryProvider=null, signingKeyPath, verifyKeyPath }) {
1682
1769
  if (!policy || !codingRuntime || !nativeDiffRuntime) throw new Error('autonomous runtime requires policy/coding/native-diff runtimes');
1683
1770
  if (!signingKeyPath || !verifyKeyPath) throw new Error('autonomous runtime requires trust keys');
1684
1771
  const capabilityManifest=configuredCapabilityManifest({machineFsRuntime,observationRuntime,processRuntime,semanticRuntime,desktopRuntime});
@@ -1697,7 +1784,7 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
1697
1784
  coding_policy_sha256:policy.coding_policy_sha256 };
1698
1785
  }
1699
1786
  async function providerCircuitStatus({goalId}) {
1700
- if (policy.planner.backend!=='openai_compatible') return null;
1787
+ if (!['openai_compatible','openai_responses'].includes(policy.planner.backend)) return null;
1701
1788
  const ctx=goalContext(policy,goalId);
1702
1789
  await loadGoal(ctx,policy,verifyKeyPath);
1703
1790
  const journal=await readEvents(ctx,verifyKeyPath);
@@ -1712,9 +1799,9 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
1712
1799
  return { autonomous, coding };
1713
1800
  }
1714
1801
 
1715
- async function submit({ submissionId, rootId, title = '', goal, acceptance = '', maxIterations = null }) {
1802
+ async function submit({ submissionId, rootId, title = '', goal, acceptance = '', taskContract = null, maxIterations = null }) {
1716
1803
  await assertRunAuthority(rootId);
1717
- const normalized = normalizeGoal(policy,{ submissionId,rootId,title,goal,acceptance,maxIterations });
1804
+ const normalized = normalizeGoal(policy,{ submissionId,rootId,title,goal,acceptance,taskContract,maxIterations });
1718
1805
  const goalId = goalIdFor(policy.policy_sha256,submissionId);
1719
1806
  const ctx = goalContext(policy,goalId);
1720
1807
  if (await exists(ctx.dir)) {
@@ -1731,8 +1818,10 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
1731
1818
  await writeFile(ctx.goalPath,`${canonicalJson(envelope)}\n`,{flag:'wx'});
1732
1819
  const journal = [];
1733
1820
  await appendEvent(ctx,journal,signingKeyPath,'goal_created',{
1734
- submission_id:submissionId, root_id:rootId, title, goal_sha256:normalized.goal_sha256,
1735
- max_iterations:normalized.max_iterations
1821
+ submission_id:submissionId, root_id:rootId, title, acceptance:normalized.acceptance,
1822
+ task_contract:normalized.task_contract,goal_sha256:normalized.goal_sha256,
1823
+ max_iterations:normalized.max_iterations,
1824
+ ...(memoryProvider?{source_release_manifest:memoryProvider.source_release_manifest}:{})
1736
1825
  });
1737
1826
  return { status:'accepted', goal_id:goalId, goal_sha256:normalized.goal_sha256, state:'pending' };
1738
1827
  }
@@ -1742,7 +1831,7 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
1742
1831
  const goal = await loadGoal(ctx,policy,verifyKeyPath);
1743
1832
  const journal = await readEvents(ctx,verifyKeyPath);
1744
1833
  const derived = deriveState(goal,journal);
1745
- const loop = publicLoopState(loopStateOrNull(goal,journal));
1834
+ const loop = publicLoopState(loopStateOrNull(goal,journal),goal,journal);
1746
1835
  const lock=await runLockStatus(ctx);
1747
1836
  return { status:'ok', goal_id:goalId, goal_sha256:goal.goal_sha256,
1748
1837
  title:goal.title, root_id:goal.root_id, journal_verified:true, ...derived, ...lock,
@@ -1776,8 +1865,11 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
1776
1865
  return { status:'existing', goal_id:goalId, state:current.state };
1777
1866
  }
1778
1867
  }
1779
- async function approve({ goalId, decision = 'approve' }) {
1868
+ async function approve({ goalId, decision = 'approve', answer = null, approvalSubjectSha256 = null, expiresInMs = 300000 }) {
1780
1869
  if (!['approve','reject'].includes(decision)) throw new Error('autonomous approval decision invalid');
1870
+ if (answer !== null && (typeof answer !== 'string' || answer.length < 1 || answer.length > 4096 || answer.includes('\0'))) {
1871
+ throw new Error('autonomous approval answer invalid');
1872
+ }
1781
1873
  const ctx = goalContext(policy,goalId);
1782
1874
  await acquireLock(ctx);
1783
1875
  try {
@@ -1792,7 +1884,34 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
1792
1884
  }
1793
1885
  if (hasR34Loop(journal)) {
1794
1886
  await assertRunAuthority(goal.root_id);
1887
+ const loopState=loopStateOrNull(goal,journal);
1888
+ const approvalSubject=pendingApprovalSubject(goal,journal,loopState);
1889
+ if(!approvalSubject) throw new Error('autonomous approval subject unavailable');
1890
+ if(typeof approvalSubjectSha256!=='string'||approvalSubjectSha256!==approvalSubject.approval_subject_sha256){
1891
+ throw new Error('autonomous approval subject mismatch');
1892
+ }
1893
+ if(!Number.isInteger(expiresInMs)||expiresInMs<1000||expiresInMs>3_600_000) throw new Error('autonomous approval lifetime invalid');
1795
1894
  const waiting=[...journal].reverse().find(event=>event.type==='waiting_entered') ?? null;
1895
+ if (waiting?.payload?.reason === 'human_input_required' && answer === null) {
1896
+ throw new Error('autonomous clarification answer is required');
1897
+ }
1898
+ if (waiting?.payload?.reason !== 'human_input_required' && answer !== null) {
1899
+ throw new Error('autonomous approval answer is only valid for human clarification');
1900
+ }
1901
+ const issuedAt=new Date();
1902
+ const approval={schema:'deadbyte.bound-approval.v1',approval_subject_sha256:approvalSubjectSha256,
1903
+ reviewed_event_seq:approvalSubject.reviewed_event_seq,reviewed_event_sha256:approvalSubject.reviewed_event_sha256,
1904
+ journal_head_sha256:approvalSubject.journal_head_sha256,scope:approvalSubject.scope,
1905
+ issued_at_utc:issuedAt.toISOString(),expires_at_utc:new Date(issuedAt.getTime()+expiresInMs).toISOString(),
1906
+ provenance:'operator_mcp'};
1907
+ validateBoundApproval({approval,subject:approvalSubject,now:issuedAt});
1908
+ await appendEvent(ctx,journal,signingKeyPath,'approval_granted',approval);
1909
+ if (waiting?.payload?.reason === 'human_input_required') {
1910
+ await appendEvent(ctx,journal,signingKeyPath,'human_input_provided',{
1911
+ request_event_sha256:waiting.event_sha256,question:waiting.payload.question,
1912
+ answer,answer_sha256:sha256Bytes(Buffer.from(answer,'utf8'))
1913
+ });
1914
+ }
1796
1915
  const resumePhase=typeof waiting?.payload?.resume_phase === 'string' ? waiting.payload.resume_phase : 'PLAN';
1797
1916
  await appendEvent(ctx,journal,signingKeyPath,'waiting_resumed',{
1798
1917
  to:resumePhase,reason:waiting?.payload?.reason ?? current.reason ?? 'operator_approved',
@@ -1927,7 +2046,7 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
1927
2046
  continue;
1928
2047
  }
1929
2048
  const accepted = await acceptPlannerDecision({ ctx,events:journal,goal,state,policy,codingRuntime,capabilityManifest,
1930
- desktopMemoryProvider,signingKeyPath,plannerResponse:suppliedResponse });
2049
+ desktopMemoryProvider,memoryProvider,signingKeyPath,plannerResponse:suppliedResponse });
1931
2050
  suppliedResponse = null;
1932
2051
  if (accepted?.needs_planner) {
1933
2052
  state = deriveState(goal,journal);
@@ -24,7 +24,7 @@ async function listGoalIds(policy) {
24
24
  export function startAutonomousSupervisor({ runtime, policy = runtime?.policy,
25
25
  idleDelayMs = 750, maxCycles = 32, logger = console, continuous = true } = {}) {
26
26
  if (!runtime || !policy) throw new Error('autonomous supervisor requires runtime + policy');
27
- const providerBacked = policy.planner.backend === 'openai_compatible';
27
+ const providerBacked = ['openai_compatible','openai_responses'].includes(policy.planner.backend);
28
28
  if (!Number.isInteger(idleDelayMs) || idleDelayMs < 25 || idleDelayMs > 60_000) {
29
29
  throw new Error('autonomous supervisor idleDelayMs out of range');
30
30
  }
@@ -0,0 +1,76 @@
1
+ import { createHash, randomUUID } from 'node:crypto';
2
+ import { link, mkdir, open, readFile, realpath, rm } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { canonicalJson } from './canonical-json.mjs';
5
+
6
+ const HEX64=/^[0-9a-f]{64}$/;
7
+ const ID=/^[A-Za-z0-9._-]{1,96}$/;
8
+ const shaBytes=bytes=>createHash('sha256').update(bytes).digest('hex');
9
+ const sha=value=>shaBytes(Buffer.from(canonicalJson(value),'utf8'));
10
+ function object(value,label){if(!value||typeof value!=='object'||Array.isArray(value))throw new Error(`${label} invalid`);return value;}
11
+ 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]}'`);}
12
+ function id(value,label){if(typeof value!=='string'||!ID.test(value))throw new Error(`${label} invalid`);return value;}
13
+ function hex(value,label){if(typeof value!=='string'||!HEX64.test(value))throw new Error(`${label} invalid`);return value;}
14
+ function iso(value,label){if(typeof value!=='string'||!Number.isFinite(Date.parse(value)))throw new Error(`${label} invalid`);return value;}
15
+
16
+ export async function publishEvidenceAtomic({root,kind,evidenceId=null,payload}){
17
+ if(typeof root!=='string'||!path.isAbsolute(root)) throw new Error('evidence root must be absolute');
18
+ id(kind,'evidence kind');object(payload,'evidence payload');
19
+ const payloadSha=sha(payload);
20
+ const resolvedId=id(evidenceId??payloadSha,'evidence id');
21
+ const body={schema:'deadbyte.evidence-publication.v1',kind,evidence_id:resolvedId,payload_sha256:payloadSha,payload:structuredClone(payload)};
22
+ const envelope={...body,evidence_sha256:sha(body)};
23
+ const bytes=Buffer.from(`${canonicalJson(envelope)}\n`,'utf8');
24
+ const base=path.resolve(root);await mkdir(base,{recursive:true});
25
+ const canonicalRoot=await realpath(base);
26
+ const pendingDir=path.join(canonicalRoot,'.pending');const finalDir=path.join(canonicalRoot,kind);
27
+ await mkdir(pendingDir,{recursive:true});await mkdir(finalDir,{recursive:true});
28
+ const target=path.join(finalDir,`${resolvedId}.json`);
29
+ const temp=path.join(pendingDir,`${kind}-${resolvedId}-${randomUUID()}.tmp`);
30
+ let handle;
31
+ try{
32
+ handle=await open(temp,'wx',0o600);await handle.writeFile(bytes);await handle.sync();await handle.close();handle=null;
33
+ const staged=await readFile(temp);
34
+ if(shaBytes(staged)!==shaBytes(bytes)) throw new Error('staged evidence hash verification failed');
35
+ try{
36
+ await link(temp,target);
37
+ return Object.freeze({status:'created',kind,evidence_id:resolvedId,evidence_sha256:envelope.evidence_sha256,
38
+ bytes:bytes.length,path:target});
39
+ }catch(error){
40
+ if(error?.code!=='EEXIST') throw error;
41
+ const existing=await readFile(target);
42
+ if(!existing.equals(bytes)){
43
+ const conflict=new Error(`EVIDENCE_ID_CONFLICT: ${kind}/${resolvedId}`);conflict.code='EVIDENCE_ID_CONFLICT';throw conflict;
44
+ }
45
+ return Object.freeze({status:'existing',kind,evidence_id:resolvedId,evidence_sha256:envelope.evidence_sha256,
46
+ bytes:bytes.length,path:target});
47
+ }
48
+ }finally{
49
+ if(handle) await handle.close().catch(()=>{});
50
+ await rm(temp,{force:true}).catch(()=>{});
51
+ }
52
+ }
53
+
54
+ export function createExecutionReceipt(raw){
55
+ const value=object(raw,'execution receipt');
56
+ keys(value,['execution_id','subject_sha256','request_sha256','observed_exit_code','started_at_utc','completed_at_utc'],'execution receipt');
57
+ const core={schema:'deadbyte.execution-receipt.v1',execution_id:id(value.execution_id,'execution_id'),
58
+ subject_sha256:hex(value.subject_sha256,'execution subject_sha256'),request_sha256:hex(value.request_sha256,'execution request_sha256'),
59
+ observed_exit_code:value.observed_exit_code,started_at_utc:iso(value.started_at_utc,'execution started_at_utc'),
60
+ completed_at_utc:iso(value.completed_at_utc,'execution completed_at_utc')};
61
+ if(!Number.isInteger(core.observed_exit_code)) throw new Error('execution exit code invalid');
62
+ if(Date.parse(core.completed_at_utc)<Date.parse(core.started_at_utc)) throw new Error('execution time order invalid');
63
+ return Object.freeze({...core,receipt_sha256:sha(core)});
64
+ }
65
+
66
+ export function createVerificationResult(raw){
67
+ const value=object(raw,'verification result');
68
+ keys(value,['verification_id','subject_sha256','execution_receipt_sha256','outcome_passed','oracle','evidence_refs'],'verification result');
69
+ if(typeof value.outcome_passed!=='boolean') throw new Error('verification outcome invalid');
70
+ 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('verification evidence refs invalid');
71
+ const core={schema:'deadbyte.verification-result.v1',verification_id:id(value.verification_id,'verification_id'),
72
+ subject_sha256:hex(value.subject_sha256,'verification subject_sha256'),
73
+ execution_receipt_sha256:hex(value.execution_receipt_sha256,'verification receipt_sha256'),
74
+ outcome_passed:value.outcome_passed,oracle:id(value.oracle,'verification oracle'),evidence_refs:[...value.evidence_refs]};
75
+ return Object.freeze({...core,verification_sha256:sha(core)});
76
+ }
@@ -1,3 +1,4 @@
1
+ import { createHash } from 'node:crypto';
1
2
  import { access, readFile } from 'node:fs/promises';
2
3
  import path from 'node:path';
3
4
  import os from 'node:os';
@@ -37,6 +38,7 @@ import { createNativeDesktopInputProvider } from './desktop-input-r40.mjs';
37
38
  import { createNativeDesktopGrounder } from './desktop-uia-r40.mjs';
38
39
  import { createDesktopRuntime } from './desktop-runtime-r40.mjs';
39
40
  import { createDesktopMemoryProvider } from './desktop-memory-r40.mjs';
41
+ import { createR41MemoryProvider } from './memory-r41.mjs';
40
42
  import { registerDesktopTools } from './desktop-mcp-tools-r40.mjs';
41
43
  import { loadAutonomousPolicy } from './autonomous-policy.mjs';
42
44
  import { createNativeDiffRuntime } from './native-diff.mjs';
@@ -61,6 +63,7 @@ import {
61
63
  } from './output-contracts.mjs';
62
64
 
63
65
  const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
66
+ const packageManifestSha256=createHash('sha256').update(await readFile(path.join(packageRoot,'MANIFEST.SHA256'))).digest('hex');
64
67
  const workspaceRoot = path.resolve(process.env.DEADBYTE_WORKSPACE_ROOT ?? path.join(packageRoot, 'workspaces'));
65
68
  const signingKeyPath = process.env.DEADBYTE_SIGNING_KEY ?? defaultPrivateKeyPath();
66
69
  const verifyKeyPath = process.env.DEADBYTE_VERIFY_KEY ?? defaultPublicKeyPath();
@@ -187,9 +190,19 @@ if (autonomousRuntimeMode === '1' && !autonomousPolicyPath) throw new Error('DEA
187
190
  const autonomousPolicy = autonomousRuntimeMode === '1' ? await loadAutonomousPolicy(autonomousPolicyPath,codingPolicy) : null;
188
191
  const nativeDiffRuntime = autonomousPolicy ? createNativeDiffRuntime({ policy:autonomousPolicy,codingRuntime,machineFsRuntime,signingKeyPath,verifyKeyPath }) : null;
189
192
  semanticRuntime = codingRuntime ? createSemanticCodeRuntime({ codingRuntime, backends: semanticLsp.backends, nativeDiffRuntime }) : null;
193
+ const autonomousMemorySigningKey=autonomousPolicy?await loadPrivateSigningKey(signingKeyPath):null;
194
+ const autonomousMemoryVerifyKey=autonomousPolicy?await loadPublicVerifyKey(verifyKeyPath):null;
195
+ if(autonomousPolicy&&autonomousMemorySigningKey.keyId!==autonomousMemoryVerifyKey.keyId) throw new Error('R41 memory signing/verify key mismatch');
196
+ const memoryProvider=autonomousPolicy?createR41MemoryProvider({
197
+ memoryRoot:path.join(autonomousPolicy.evidence_dir,'memory-r41',packageManifestSha256),sourceReleaseManifest:packageManifestSha256,
198
+ journalRoot:path.join(autonomousPolicy.evidence_dir,'goals'),
199
+ writerVersion:DEADBYTE_VERSION,privateKey:autonomousMemorySigningKey.privateKey,
200
+ publicKey:autonomousMemoryVerifyKey.publicKey,keyId:autonomousMemorySigningKey.keyId,
201
+ byteBudget:Math.min(262144,Math.max(65536,Math.floor(autonomousPolicy.limits.max_context_bytes/2))),semantic:{enabled:false}
202
+ }):null;
190
203
  const autonomousRuntime = autonomousPolicy ? createAutonomousRuntime({ policy:autonomousPolicy,codingRuntime,nativeDiffRuntime,
191
- machineFsRuntime,observationRuntime,processRuntime,semanticRuntime,desktopRuntime,desktopMemoryProvider,signingKeyPath,verifyKeyPath }) : null;
192
- const autonomousSupervisor = autonomousRuntime && autonomousPolicy.planner.backend === 'openai_compatible' &&
204
+ machineFsRuntime,observationRuntime,processRuntime,semanticRuntime,desktopRuntime,desktopMemoryProvider,memoryProvider,signingKeyPath,verifyKeyPath }) : null;
205
+ const autonomousSupervisor = autonomousRuntime && ['openai_compatible','openai_responses'].includes(autonomousPolicy.planner.backend) &&
193
206
  autonomousSupervisorMode === 'in_process'
194
207
  ? startAutonomousSupervisor({ runtime: autonomousRuntime, policy: autonomousPolicy })
195
208
  : null;