deadbyte-mcp 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/MANIFEST.SHA256 +134 -92
  2. package/README.txt +19 -15
  3. package/bench/fixtures/corpus.json +32 -13
  4. package/bench/fixtures/r36/case-map.json +8 -0
  5. package/bin/WORKER-REGISTRY.txt +3 -3
  6. package/bin/appcontainer-stage.exe +0 -0
  7. package/bin/appcontainer-stage.obj +0 -0
  8. package/bin/bootstrap-advapi32.exe +0 -0
  9. package/bin/bootstrap-advapi32.obj +0 -0
  10. package/bin/bootstrap-exitcode.exe +0 -0
  11. package/bin/bootstrap-exitcode.obj +0 -0
  12. package/bin/bootstrap-kernel32.exe +0 -0
  13. package/bin/bootstrap-kernel32.obj +0 -0
  14. package/bin/child-control-probe.exe +0 -0
  15. package/bin/child-control-probe.obj +0 -0
  16. package/bin/child-control-stage.exe +0 -0
  17. package/bin/child-control-stage.obj +0 -0
  18. package/bin/contained-reverse-worker.exe +0 -0
  19. package/bin/contained-reverse-worker.obj +0 -0
  20. package/bin/contained-transform-worker.exe +0 -0
  21. package/bin/contained-transform-worker.obj +0 -0
  22. package/bin/containment-probe.exe +0 -0
  23. package/bin/containment-probe.obj +0 -0
  24. package/bin/deadbyte-contain.exe +0 -0
  25. package/bin/deadbyte-contain.obj +0 -0
  26. package/bin/deadbyte-exec.exe +0 -0
  27. package/bin/deadbyte-exec.obj +0 -0
  28. package/bin/deadbyte-process-host.exe +0 -0
  29. package/bin/deadbyte-process-host.obj +0 -0
  30. package/bin/deadbyte-tunnel-host.exe +0 -0
  31. package/bin/deadbyte-tunnel-host.obj +0 -0
  32. package/controller/README.TXT +8 -6
  33. package/controller/deadbyte-controller.ps1 +48 -2
  34. package/controller/deadbyte-process-policy.json +5 -5
  35. package/docs/ARCHITECTURE.md +1 -1
  36. package/docs/R36-CAPABILITY-EVIDENCE.md +43 -0
  37. package/docs/superpowers/plans/2026-09-18-r36-zero-loss-autonomy.md +739 -0
  38. package/docs/superpowers/specs/2026-09-18-r36-zero-loss-autonomy-design.md +640 -0
  39. package/package.json +1 -1
  40. package/proof/CONTAINMENT-BUILD.txt +6 -6
  41. package/scripts/deferred-slot-operation.mjs +53 -15
  42. package/scripts/final-closure-r36.mjs +113 -0
  43. package/scripts/final-closure-verify-r36.mjs +208 -0
  44. package/scripts/final-closure-verify.mjs +88 -39
  45. package/scripts/final-closure.mjs +63 -56
  46. package/scripts/gate-windows-r36.ps1 +42 -0
  47. package/scripts/gate-windows.ps1 +3 -3
  48. package/scripts/release-parity-r36.mjs +200 -0
  49. package/scripts/release-parity-tests.ps1 +9 -0
  50. package/scripts/release-parity.mjs +149 -139
  51. package/scripts/windows-gate-evidence-r36.mjs +52 -0
  52. package/scripts/windows-gate-evidence.mjs +5 -5
  53. package/src/agent-memory-plane.mjs +98 -0
  54. package/src/autonomous-context-engine.mjs +2 -1
  55. package/src/autonomous-mcp-tools.mjs +5 -1
  56. package/src/autonomous-output-contracts.mjs +9 -6
  57. package/src/autonomous-planner-contracts.mjs +36 -1
  58. package/src/autonomous-planner.mjs +25 -3
  59. package/src/autonomous-runtime.mjs +337 -43
  60. package/src/autonomous-timeout-recovery.mjs +27 -0
  61. package/src/capability-benchmark-runner.mjs +86 -1
  62. package/src/capability-benchmark.mjs +45 -0
  63. package/src/capability-ledger.mjs +158 -0
  64. package/src/coding-mcp-tools.mjs +31 -17
  65. package/src/coding-output-contracts.mjs +48 -10
  66. package/src/coding-plane.mjs +45 -9
  67. package/src/coding-search.mjs +130 -47
  68. package/src/compact-gateway-mcp-tools.mjs +128 -0
  69. package/src/compact-gateway-output-contracts.mjs +16 -0
  70. package/src/deadbyte-cli.mjs +62 -78
  71. package/src/effect-ledger.mjs +47 -0
  72. package/src/machine-fs-smoke-client.mjs +1 -1
  73. package/src/machine-fs.mjs +51 -8
  74. package/src/mcp-server.mjs +32 -9
  75. package/src/native-diff-v2.mjs +337 -0
  76. package/src/native-diff.mjs +50 -2
  77. package/src/observation-lease.mjs +32 -0
  78. package/src/observation-smoke-client.mjs +1 -1
  79. package/src/operator-surface.mjs +7 -1
  80. package/src/process-runtime.mjs +98 -11
  81. package/src/process-smoke-client.mjs +11 -3
  82. package/src/r36-compact-disarmed-probe.mjs +50 -0
  83. package/src/r36-full-surface-probe.mjs +56 -0
  84. package/src/remote-live-log.mjs +135 -0
  85. package/src/remote-mcp-autonomous-smoke-client.mjs +22 -12
  86. package/src/remote-mcp-coding-smoke-client.mjs +1 -1
  87. package/src/remote-mcp-r36-parity-client.mjs +175 -0
  88. package/src/remote-mcp-smoke-client.mjs +112 -56
  89. package/src/runtime-update.mjs +51 -1
  90. package/src/search-cursor.mjs +45 -0
  91. package/src/semantic-code.mjs +72 -5
  92. package/src/semantic-lsp-backend.mjs +39 -3
  93. package/src/version.mjs +1 -1
  94. package/src/worker-scheduler.mjs +53 -0
  95. package/test/autonomous-capability-r36.test.mjs +151 -0
  96. package/test/autonomous-output-contract.test.mjs +1 -1
  97. package/test/autonomous-runtime.test.mjs +2 -2
  98. package/test/capability-benchmark-r36.test.mjs +107 -0
  99. package/test/capability-benchmark-semantic-r36.test.mjs +52 -0
  100. package/test/capability-claims-r36.test.mjs +23 -0
  101. package/test/capability-ledger-r36.test.mjs +102 -0
  102. package/test/coding-catalog-consistency.test.mjs +2 -2
  103. package/test/coding-plane.test.mjs +2 -2
  104. package/test/coding-runtime.test.mjs +16 -0
  105. package/test/coding-search-r36.test.mjs +90 -0
  106. package/test/compact-catalog-r36.test.mjs +37 -0
  107. package/test/compact-gateway-r36.test.mjs +66 -0
  108. package/test/contained.test.mjs +1 -1
  109. package/test/core.test.mjs +1 -1
  110. package/test/deferred-slot-operation.test.mjs +9 -0
  111. package/test/fixtures/lsp-framed-server.mjs +2 -0
  112. package/test/helpers/autonomous-r34-fixture.mjs +5 -3
  113. package/test/multi-file-read.test.mjs +3 -0
  114. package/test/native-diff-topology-r36.test.mjs +105 -0
  115. package/test/package-boundary.test.mjs +6 -0
  116. package/test/process-longrun-r36.test.mjs +82 -0
  117. package/test/process-release-gate.test.mjs +9 -0
  118. package/test/production-docs.test.mjs +5 -5
  119. package/test/prompts-resources.test.mjs +7 -1
  120. package/test/r33-closeout-regression.test.mjs +4 -3
  121. package/test/r33-finalization.test.mjs +14 -9
  122. package/test/r36-finalization.test.mjs +104 -0
  123. package/test/r36-release-identity.test.mjs +45 -0
  124. package/test/r37-agent-fabric.test.mjs +92 -0
  125. package/test/r37-autonomous-timeout-recovery.test.mjs +60 -0
  126. package/test/r37-finalization.test.mjs +74 -0
  127. package/test/release-version.test.mjs +42 -33
  128. package/test/remote-live-log-r36.test.mjs +37 -0
  129. package/test/remote-live-log-r37.test.mjs +47 -0
  130. package/test/remote-live-log-recovery-r36.test.mjs +41 -0
  131. package/test/remote-r24-catalog.test.mjs +13 -0
  132. package/test/remote-session-cli.test.mjs +53 -66
  133. package/test/runtime-self-update.test.mjs +58 -1
  134. package/test/semantic-lsp-backend.test.mjs +9 -0
  135. package/test/semantic-r36-rename.test.mjs +82 -0
  136. package/deadbyte-mcp-0.8.9.tgz +0 -0
@@ -149,7 +149,7 @@ export function createTypeScriptSemanticBackend({codingRuntime}){
149
149
  }
150
150
  async function diagnostics({rootId,relativePath,maxResults=200}){
151
151
  if(!Number.isInteger(maxResults)||maxResults<1||maxResults>500) throw new Error('max_results must be in [1, 500]');
152
- await codingRuntime.fileRead({rootId,relativePath,encoding:'utf8'});
152
+ const file=await codingRuntime.fileRead({rootId,relativePath,encoding:'utf8'});
153
153
  const project=await buildProject(codingRuntime,rootId); const target=targetFile(project,relativePath);
154
154
  const all=[...project.service.getSyntacticDiagnostics(target.absolute),...project.service.getSemanticDiagnostics(target.absolute)];
155
155
  const diagnosticsOut=all.slice(0,maxResults).map(item=>{
@@ -157,23 +157,90 @@ export function createTypeScriptSemanticBackend({codingRuntime}){
157
157
  const loc=locationFromSpan(project,target.absolute,span,'','diagnostic');
158
158
  return {message:ts.flattenDiagnosticMessageText(item.messageText,'\n'),code:String(item.code),severity:diagnosticCategory(item.category),...(loc?{location:loc}:{})};
159
159
  });
160
- return {status:'ok',root_id:rootId,path:relativePath,engine:`typescript-${ts.version}`,diagnostics:diagnosticsOut,truncated:all.length>maxResults};
160
+ const stable={root_id:rootId,path:relativePath,file_sha256:file.sha256,engine:`typescript-${ts.version}`,diagnostics:diagnosticsOut,truncated:all.length>maxResults};
161
+ return {status:'ok',...stable,result_sha256:digest({schema:'deadbyte.semantic-diagnostics.v1',...stable})};
162
+ }
163
+ async function implementations({rootId,relativePath,line,column,maxResults=200}){
164
+ if(!Number.isInteger(maxResults)||maxResults<1||maxResults>500) throw new Error('max_results must be in [1, 500]');
165
+ const file=await codingRuntime.fileRead({rootId,relativePath,encoding:'utf8'});
166
+ const project=await buildProject(codingRuntime,rootId); const target=targetFile(project,relativePath); const pos=offsetAt(target.source,line,column);
167
+ const raw=project.service.getImplementationAtPosition(target.absolute,pos)??[];
168
+ const locations=raw.map(item=>locationFromSpan(project,item.fileName,item.textSpan,item.name??'',item.kind??'implementation')).filter(Boolean).slice(0,maxResults);
169
+ const stable={root_id:rootId,path:relativePath,line,column,file_sha256:file.sha256,engine:`typescript-${ts.version}`,locations,truncated:raw.length>maxResults};
170
+ return {status:'ok',...stable,result_sha256:digest({schema:'deadbyte.semantic-implementations.v1',...stable})};
161
171
  }
162
- return Object.freeze({id:'typescript',extensions:new Set(SOURCE_EXTENSIONS),outline,definition,references,replaceSymbol,diagnostics});
172
+ async function renameEdits({rootId,relativePath,line,column,newName}){
173
+ const file=await codingRuntime.fileRead({rootId,relativePath,encoding:'utf8'});
174
+ const project=await buildProject(codingRuntime,rootId); const target=targetFile(project,relativePath); const pos=offsetAt(target.source,line,column);
175
+ const info=project.service.getRenameInfo(target.absolute,pos,{allowRenameOfImportPath:false});
176
+ if(!info?.canRename) throw new Error(`semantic rename unavailable: ${info?.localizedErrorMessage??'symbol cannot be renamed'}`);
177
+ const raw=project.service.findRenameLocations(target.absolute,pos,false,false,true)??[];
178
+ if(raw.length<1) throw new Error('semantic rename produced no locations');
179
+ const edits=[];
180
+ for(const item of raw){
181
+ const loc=locationFromSpan(project,item.fileName,item.textSpan,'','rename');
182
+ if(!loc) continue;
183
+ edits.push({path:loc.path,start:item.textSpan.start,length:item.textSpan.length,new_text:`${item.prefixText??''}${newName}${item.suffixText??''}`});
184
+ }
185
+ if(edits.length<1) throw new Error('semantic rename produced no allowed edits');
186
+ edits.sort((a,b)=>a.path.localeCompare(b.path,'en')||a.start-b.start||a.length-b.length);
187
+ return {status:'ok',root_id:rootId,path:relativePath,engine:`typescript-${ts.version}`,target_file_sha256:file.sha256,edits};
188
+ }
189
+ return Object.freeze({id:'typescript',extensions:new Set(SOURCE_EXTENSIONS),outline,definition,references,replaceSymbol,diagnostics,implementations,renameEdits});
163
190
  }
164
191
 
165
- export function createSemanticCodeRuntime({codingRuntime,backends=[]}){
192
+ export function createSemanticCodeRuntime({codingRuntime,backends=[],nativeDiffRuntime=null}){
166
193
  if(!codingRuntime) throw new Error('semantic runtime requires coding runtime');
167
194
  if(!Array.isArray(backends)) throw new Error('semantic runtime backends must be an array');
168
195
  const typescript=createTypeScriptSemanticBackend({codingRuntime});
169
196
  const registry=createSemanticBackendRegistry({backends:[typescript,...backends]});
170
- const route=(method,args)=>registry.backendForPath(args.relativePath)[method](args);
197
+ const backendFor=args=>registry.backendForPath(args.relativePath);
198
+ const route=(method,args)=>{
199
+ const backend=backendFor(args);
200
+ if(typeof backend[method]!=='function') return {status:'unsupported',capability:method,engine:backend.id};
201
+ return backend[method](args);
202
+ };
203
+ async function renamePreview({rootId,relativePath,line,column,newName}){
204
+ if(typeof newName!=='string'||!/^[A-Za-z_$][A-Za-z0-9_$]{0,127}$/.test(newName)) throw new Error('semantic rename new name must be a valid bounded identifier');
205
+ if(!nativeDiffRuntime||typeof nativeDiffRuntime.preview!=='function') throw new Error('semantic rename preview requires Native Diff runtime');
206
+ const backend=backendFor({relativePath});
207
+ if(typeof backend.renameEdits!=='function') return {status:'unsupported',capability:'rename_preview',engine:backend.id};
208
+ const plan=await backend.renameEdits({rootId,relativePath,line,column,newName});
209
+ if(plan?.status==='unsupported') return plan;
210
+ if(!plan||plan.status!=='ok'||!Array.isArray(plan.edits)||plan.edits.length<1) throw new Error('semantic rename backend returned no normalized edits');
211
+ const groups=new Map();
212
+ for(const edit of plan.edits){
213
+ if(!edit||typeof edit.path!=='string'||!Number.isInteger(edit.start)||edit.start<0||!Number.isInteger(edit.length)||edit.length<0||typeof edit.new_text!=='string') throw new Error('semantic rename edit malformed');
214
+ const list=groups.get(edit.path)??[]; list.push(edit); groups.set(edit.path,list);
215
+ }
216
+ const operations=[]; const preimages=[]; let editCount=0;
217
+ for(const filePath of [...groups.keys()].sort((a,b)=>a.localeCompare(b,'en'))){
218
+ const file=await codingRuntime.fileRead({rootId,relativePath:filePath,encoding:'utf8'});
219
+ const edits=[...groups.get(filePath)].sort((a,b)=>a.start-b.start||a.length-b.length);
220
+ let priorEnd=-1;
221
+ for(const edit of edits){
222
+ if(edit.start<priorEnd) throw new Error(`semantic rename overlapping edits in ${filePath}`);
223
+ if(edit.start+edit.length>file.content.length) throw new Error(`semantic rename edit outside ${filePath}`);
224
+ priorEnd=edit.start+edit.length;
225
+ }
226
+ let next=file.content;
227
+ for(const edit of [...edits].sort((a,b)=>b.start-a.start)) next=next.slice(0,edit.start)+edit.new_text+next.slice(edit.start+edit.length);
228
+ operations.push({kind:'write',path:filePath,content:next,encoding:'utf8',expected_sha256:file.sha256});
229
+ preimages.push({path:filePath,sha256:file.sha256});
230
+ editCount+=edits.length;
231
+ }
232
+ const diff=await nativeDiffRuntime.preview({rootId,title:`semantic rename ${relativePath} -> ${newName}`,operations});
233
+ return {status:'ready',diff_id:diff.diff_id,affected_files:operations.length,edit_count:editCount,
234
+ backend:plan.engine??backend.id,preimages};
235
+ }
171
236
  return Object.freeze({
172
237
  outline:async args=>route('outline',args),
173
238
  definition:async args=>route('definition',args),
174
239
  references:async args=>route('references',args),
175
240
  replaceSymbol:async args=>route('replaceSymbol',args),
176
241
  diagnostics:async args=>route('diagnostics',args),
242
+ implementations:async args=>route('implementations',args),
243
+ renamePreview,
177
244
  languages:()=>registry.languages()
178
245
  });
179
246
  }
@@ -119,7 +119,7 @@ export function createSemanticLspBackend({id,extensions,codingRuntime,server}){
119
119
  const open=async ctx=>{
120
120
  const client=createLspStdioClient({executablePath:server.executable_path,expectedSha256:server.executable_sha256,args:server.args??[],cwd:ctx.root.real_path,env:server.env??{},dependencies:server.dependencies??[],requestTimeoutMs:server.request_timeout_ms??10000,maxMessageBytes:server.max_message_bytes??4*1024*1024});
121
121
  try{
122
- await client.initialize({processId:null,rootPath:ctx.root.real_path,rootUri:ctx.rootUri,workspaceFolders:[{uri:ctx.rootUri,name:path.basename(ctx.root.real_path)}],capabilities:{workspace:{workspaceFolders:true},textDocument:{documentSymbol:{hierarchicalDocumentSymbolSupport:true},definition:{},references:{},diagnostic:{}}},initializationOptions:server.initialization_options??{}});
122
+ await client.initialize({processId:null,rootPath:ctx.root.real_path,rootUri:ctx.rootUri,workspaceFolders:[{uri:ctx.rootUri,name:path.basename(ctx.root.real_path)}],capabilities:{workspace:{workspaceFolders:true},textDocument:{documentSymbol:{hierarchicalDocumentSymbolSupport:true},definition:{},references:{},implementation:{},rename:{prepareSupport:false},diagnostic:{}}},initializationOptions:server.initialization_options??{}});
123
123
  for(const document of await workspaceDocuments(ctx)) client.notify('textDocument/didOpen',{textDocument:{uri:document.uri,languageId,version:1,text:document.text}});
124
124
  if(startupSettleMs>0) await new Promise(resolve=>setTimeout(resolve,startupSettleMs));
125
125
  return client;
@@ -163,7 +163,43 @@ export function createSemanticLspBackend({id,extensions,codingRuntime,server}){
163
163
  const raw=await withClient(ctx,client=>requestRead(client,'textDocument/diagnostic',{textDocument:{uri:ctx.uri}}));
164
164
  const items=Array.isArray(raw?.items)?raw.items:[];
165
165
  const diagnosticsOut=items.slice(0,maxResults).filter(item=>validRange(item?.range)).map(item=>({message:String(item.message??''),code:String(item.code??''),severity:SEVERITY[Number(item.severity)]??'unknown',location:{path:ctx.relativePath,name:'',kind:'diagnostic',start_line:item.range.start.line,start_column:item.range.start.character,end_line:item.range.end.line,end_column:item.range.end.character}}));
166
- return {status:'ok',root_id:rootId,path:ctx.relativePath,engine:id,diagnostics:diagnosticsOut,truncated:items.length>maxResults};
166
+ const stable={root_id:rootId,path:ctx.relativePath,file_sha256:ctx.file.sha256,engine:id,diagnostics:diagnosticsOut,truncated:items.length>maxResults};
167
+ return {status:'ok',...stable,result_sha256:digest({schema:'deadbyte.semantic-diagnostics.v1',...stable})};
168
+ }
169
+ async function implementations({rootId,relativePath,line,column,maxResults=200}){
170
+ if(!Number.isInteger(maxResults)||maxResults<1||maxResults>500) throw new Error('max_results must be in [1, 500]');
171
+ const ctx=await rootContext(codingRuntime,rootId,relativePath);
172
+ let raw;
173
+ try { raw=await withClient(ctx,client=>requestRead(client,'textDocument/implementation',{textDocument:{uri:ctx.uri},position:{line,character:column}})); }
174
+ catch(error){ if(/-32601|method not found/i.test(String(error))) return {status:'unsupported',capability:'implementations',engine:id}; throw error; }
175
+ const normalized=normalizeLocations(raw,ctx,maxResults);
176
+ const stable={root_id:rootId,path:ctx.relativePath,line,column,file_sha256:ctx.file.sha256,engine:id,...normalized};
177
+ return {status:'ok',...stable,result_sha256:digest({schema:'deadbyte.semantic-implementations.v1',...stable})};
178
+ }
179
+ async function renameEdits({rootId,relativePath,line,column,newName}){
180
+ const ctx=await rootContext(codingRuntime,rootId,relativePath);
181
+ let raw;
182
+ try { raw=await withClient(ctx,client=>requestRead(client,'textDocument/rename',{textDocument:{uri:ctx.uri},position:{line,character:column},newName})); }
183
+ catch(error){ if(/-32601|method not found/i.test(String(error))) return {status:'unsupported',capability:'rename_preview',engine:id}; throw error; }
184
+ const byUri=[];
185
+ if(raw?.changes&&typeof raw.changes==='object') for(const [uri,edits] of Object.entries(raw.changes)) byUri.push({uri,edits});
186
+ for(const change of raw?.documentChanges??[]){ if(change?.textDocument?.uri&&Array.isArray(change.edits)) byUri.push({uri:change.textDocument.uri,edits:change.edits}); }
187
+ const normalized=[];
188
+ for(const group of byUri){
189
+ let absolute; try{absolute=path.resolve(fileURLToPath(group.uri));}catch{continue;}
190
+ if(!inside(ctx.root.real_path,absolute)||denied(ctx.root,absolute)) continue;
191
+ const rel=relNormalized(path.relative(ctx.root.real_path,absolute));
192
+ const file=await codingRuntime.fileRead({rootId,relativePath:rel,encoding:'utf8'});
193
+ for(const edit of group.edits??[]){
194
+ if(!validRange(edit?.range)||typeof edit?.newText!=='string') throw new Error('semantic LSP rename edit malformed');
195
+ const start=positionToOffset(file.content,edit.range.start); const end=positionToOffset(file.content,edit.range.end);
196
+ if(end<start) throw new Error('semantic LSP rename range invalid');
197
+ normalized.push({path:rel,start,length:end-start,new_text:edit.newText});
198
+ }
199
+ }
200
+ if(normalized.length<1) throw new Error('semantic LSP rename produced no allowed edits');
201
+ normalized.sort((a,b)=>a.path.localeCompare(b.path,'en')||a.start-b.start||a.length-b.length);
202
+ return {status:'ok',root_id:rootId,path:ctx.relativePath,engine:id,target_file_sha256:ctx.file.sha256,edits:normalized};
167
203
  }
168
204
  async function replaceSymbol({rootId,relativePath,symbolId,newBody,expectedSha256}){
169
205
  if(typeof newBody!=='string'||newBody.length>524288) throw new Error('new_body exceeds 524288 characters');
@@ -179,5 +215,5 @@ export function createSemanticLspBackend({id,extensions,codingRuntime,server}){
179
215
  const result=await codingRuntime.textReplace({rootId,relativePath:ctx.relativePath,oldString:oldBody,newString:newBody,expectedSha256,expectedReplacements:1});
180
216
  return {...result,symbol_id:symbolId,symbol_name:symbol.name,engine:id};
181
217
  }
182
- return Object.freeze({id,extensions:extensionSet,outline,definition,references,replaceSymbol,diagnostics});
218
+ return Object.freeze({id,extensions:extensionSet,outline,definition,references,replaceSymbol,diagnostics,implementations,renameEdits});
183
219
  }
package/src/version.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export const DEADBYTE_VERSION = '0.9.0';
1
+ export const DEADBYTE_VERSION = '0.11.0';
2
2
  export const MCP_PROTOCOL_VERSION = '2026-07-28';
3
3
  export const RECEIPT_SCHEMA_V1 = 'deadbyte.receipt.v1';
4
4
  export const RECEIPT_SCHEMA_V2 = 'deadbyte.receipt.v2';
@@ -0,0 +1,53 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { canonicalJson } from './canonical-json.mjs';
3
+
4
+ export const WORKER_SCHEDULER_SCHEMA='deadbyte.worker-scheduler.v1';
5
+ const sha=value=>createHash('sha256').update(Buffer.from(canonicalJson(value),'utf8')).digest('hex');
6
+
7
+ export function createWorkerScheduler({maxConcurrent=1,totalCpuUnits=1,totalMemoryMb=1024,leaseMs=60000,clock=()=>Date.now()}={}){
8
+ if(!Number.isInteger(maxConcurrent)||maxConcurrent<1) throw new Error('maxConcurrent invalid');
9
+ if(!Number.isInteger(totalCpuUnits)||totalCpuUnits<1) throw new Error('totalCpuUnits invalid');
10
+ if(!Number.isInteger(totalMemoryMb)||totalMemoryMb<1) throw new Error('totalMemoryMb invalid');
11
+ if(!Number.isInteger(leaseMs)||leaseMs<100) throw new Error('leaseMs invalid');
12
+ const active=new Map(),attempts=new Map(),history=[];
13
+ function reclaim(){
14
+ const now=clock();
15
+ for(const [id,lease] of active) if(lease.expires_at_ms<=now){
16
+ active.delete(id);history.push({...lease,status:'expired',released_at_ms:now});
17
+ }
18
+ }
19
+ function usage(){
20
+ return [...active.values()].reduce((x,l)=>({cpu:x.cpu+l.cpu_units,memory:x.memory+l.memory_mb}),{cpu:0,memory:0});
21
+ }
22
+ function snapshot(){
23
+ reclaim();
24
+ const used=usage();
25
+ return Object.freeze({schema:WORKER_SCHEDULER_SCHEMA,max_concurrent:maxConcurrent,total_cpu_units:totalCpuUnits,total_memory_mb:totalMemoryMb,
26
+ active:[...active.values()].sort((a,b)=>a.lease_id.localeCompare(b.lease_id,'en')),
27
+ history:[...history],used_cpu_units:used.cpu,used_memory_mb:used.memory});
28
+ }
29
+ function acquire({taskId,workerClass,cpuUnits=1,memoryMb=128}){
30
+ reclaim();
31
+ if(typeof taskId!=='string'||!taskId) throw new Error('taskId invalid');
32
+ if(typeof workerClass!=='string'||!workerClass) throw new Error('workerClass invalid');
33
+ if(!Number.isInteger(cpuUnits)||cpuUnits<1||!Number.isInteger(memoryMb)||memoryMb<1) throw new Error('worker resources invalid');
34
+ const used=usage();
35
+ if(active.size>=maxConcurrent||used.cpu+cpuUnits>totalCpuUnits||used.memory+memoryMb>totalMemoryMb) throw new Error('worker scheduler capacity exceeded');
36
+ const attempt=(attempts.get(taskId)??0)+1;attempts.set(taskId,attempt);
37
+ const issued=clock(),expires=issued+leaseMs;
38
+ const body={schema:'deadbyte.worker-lease.v1',task_id:taskId,worker_class:workerClass,attempt,cpu_units:cpuUnits,memory_mb:memoryMb,issued_at_ms:issued,expires_at_ms:expires};
39
+ const lease=Object.freeze({...body,lease_id:sha(body)});
40
+ active.set(lease.lease_id,lease);
41
+ return lease;
42
+ }
43
+ function heartbeat(leaseId){
44
+ reclaim();const current=active.get(leaseId);if(!current) throw new Error('worker lease unavailable');
45
+ const next=Object.freeze({...current,expires_at_ms:clock()+leaseMs});active.set(leaseId,next);return next;
46
+ }
47
+ function release(leaseId,{status='completed'}={}){
48
+ reclaim();const lease=active.get(leaseId);if(!lease) throw new Error('worker lease unavailable');
49
+ active.delete(leaseId);const item={...lease,status,released_at_ms:clock()};history.push(item);
50
+ return Object.freeze({status:'released',lease:item});
51
+ }
52
+ return Object.freeze({acquire,heartbeat,release,snapshot});
53
+ }
@@ -0,0 +1,151 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { parseR34PlannerDecision, buildPlannerPrompt } from '../src/autonomous-planner.mjs';
4
+ import { judgeProgress } from '../src/autonomous-progress.mjs';
5
+ import { createR34Fixture, sendPlannerDecision, planCreateDecision, inspectDecision } from './helpers/autonomous-r34-fixture.mjs';
6
+
7
+ const H='a'.repeat(64);
8
+ const policy={
9
+ profiles:{},
10
+ limits:{max_context_bytes:262144,max_files_per_diff:32,max_stalled_cycles:2,max_post_replan_stalls:2,max_replans:8}
11
+ };
12
+ const wrap=action=>JSON.stringify({schema:'deadbyte.autonomous-decision.v2',kind:'act',action});
13
+
14
+ const typedCases=[
15
+ ['search',{kind:'search',path:'.',target:'content',mode:'regex',pattern:'foo\\d+',case_sensitive:false,max_results:50,max_file_bytes:262144,max_scan_bytes:1048576,page_size:25,cursor:null}],
16
+ ['stat',{kind:'stat',path:'src/a.mjs',hash:true}],
17
+ ['multi_read',{kind:'multi_read',files:[{path:'src/a.mjs',encoding:'utf8'},{path:'src/b.mjs',encoding:'utf8'}],max_total_bytes:131072}],
18
+ ['semantic_references',{kind:'semantic_references',path:'src/a.mjs',line:1,column:2,max_results:100}],
19
+ ['semantic_rename_preview',{kind:'semantic_rename_preview',path:'src/a.mjs',line:1,column:2,new_name:'renamed'}],
20
+ ['native_diff_apply',{kind:'native_diff_apply',diff_id:H,expected_operation_count:1}],
21
+ ['native_diff_verify',{kind:'native_diff_verify',diff_id:H}],
22
+ ['process_start',{kind:'process_start',profile_id:'test',cwd:'.',args:[]}],
23
+ ['process_read',{kind:'process_read',session_id:H,offset:0,max_bytes:65536}],
24
+ ['process_status',{kind:'process_status',session_id:H}],
25
+ ['process_action',{kind:'process_action',session_id:H,action_id:'ping'}],
26
+ ['process_terminate',{kind:'process_terminate',session_id:H}],
27
+ ['machine_fs_stat',{kind:'machine_fs_stat',path:'src',hash:true}],
28
+ ['machine_fs_list',{kind:'machine_fs_list',path:'.',cursor:null,limit:100,hash_files:false}],
29
+ ['machine_fs_read',{kind:'machine_fs_read',path:'src/a.mjs',offset:0,max_bytes:65536,hash_file:true}],
30
+ ['machine_fs_mkdir',{kind:'machine_fs_mkdir',path:'generated'}],
31
+ ['machine_fs_move',{kind:'machine_fs_move',source_path:'a.txt',destination_path:'b.txt',expected_source_identity:H}],
32
+ ['machine_fs_delete',{kind:'machine_fs_delete',path:'empty',expected_source_identity:H}],
33
+ ['observation_search_start',{kind:'observation_search_start',path:'.',pattern:'FAIL',case_sensitive:false,max_results:100,max_files:1000,max_bytes:1048576,max_file_bytes:262144}],
34
+ ['observation_search_page',{kind:'observation_search_page',search_id:H,cursor:null,limit:50}],
35
+ ['observation_system_status',{kind:'observation_system_status'}]
36
+ ];
37
+
38
+ test('R36 planner parses first-class capability actions without delegate wrapper',()=>{
39
+ for(const [label,action] of typedCases){
40
+ const parsed=parseR34PlannerDecision(wrap(action),policy);
41
+ assert.equal(parsed.kind,'act',label);
42
+ assert.equal(parsed.action.kind,action.kind,label);
43
+ assert.notEqual(parsed.action.kind,'delegate',label);
44
+ }
45
+ });
46
+
47
+ test('R36 legacy delegate is accepted only for a known operation and normalized into typed action',()=>{
48
+ const parsed=parseR34PlannerDecision(wrap({kind:'delegate',operation:{kind:'process_status',session_id:H}}),policy);
49
+ assert.equal(parsed.action.kind,'process_status');
50
+ assert.equal(parsed.action.session_id,H);
51
+ assert.equal('operation' in parsed.action,false);
52
+ assert.throws(()=>parseR34PlannerDecision(wrap({kind:'delegate',operation:{kind:'arbitrary_tool',tool_name:'host_exec',args:{}}}),policy),/contract|delegated|unsupported|authority/i);
53
+ });
54
+
55
+ test('R36 planner prompt exposes configured capability manifest and never advertises Host',()=>{
56
+ const prompt=buildPlannerPrompt({goal:{title:'x',goal:'fix',acceptance:'tests pass'},policy,view:{mutation_epoch:0,planner_round:0,tree:[],contexts:[],observations:[],recent_decisions:[],active_plan:null,capabilities:{schema:'deadbyte.capability-manifest.v1',ledger_sha256:H,entries:[
57
+ {id:'coding.search',authority:'coding',mutating:false},
58
+ {id:'process.start',authority:'process',mutating:true}
59
+ ]}}});
60
+ assert.match(prompt,/coding\.search/);
61
+ assert.match(prompt,/process\.start/);
62
+ assert.doesNotMatch(prompt,/host\.exec|host_file|host authority/i);
63
+ });
64
+
65
+ test('R36 progress fingerprint ignores rationale but binds capability, evidence, session and cursor identity',()=>{
66
+ const base={before:{mutation_epoch:2},after:{mutation_epoch:2},decision:{kind:'process_read',rationale:'first'},evidence:{capability_id:'process.read',session_id:H,cursor:10,observation_sha256:'b'.repeat(64),receipt_sha256:'c'.repeat(64)}};
67
+ const a=judgeProgress(base);
68
+ const prose=judgeProgress({...base,decision:{...base.decision,rationale:'completely different prose'}});
69
+ assert.equal(a.fingerprint,prose.fingerprint);
70
+ const cap=judgeProgress({...base,evidence:{...base.evidence,capability_id:'process.status'}});
71
+ const cursor=judgeProgress({...base,evidence:{...base.evidence,cursor:11}});
72
+ const session=judgeProgress({...base,evidence:{...base.evidence,session_id:'d'.repeat(64)}});
73
+ const receipt=judgeProgress({...base,evidence:{...base.evidence,receipt_sha256:'e'.repeat(64)}});
74
+ assert.notEqual(a.fingerprint,cap.fingerprint);
75
+ assert.notEqual(a.fingerprint,cursor.fingerprint);
76
+ assert.notEqual(a.fingerprint,session.fingerprint);
77
+ assert.notEqual(a.fingerprint,receipt.fingerprint);
78
+ });
79
+
80
+ test('R36 typed stat executes through the autonomous loop and records capability-bound evidence',async()=>{
81
+ const f=await createR34Fixture();
82
+ try{
83
+ const goal=await f.runtime.submit({submissionId:'r36-typed-stat',rootId:'project',title:'typed stat',goal:'inspect x.txt identity',acceptance:'stat evidence is journaled'});
84
+ let result=await f.runtime.run({goalId:goal.goal_id,maxCycles:4});
85
+ result=await sendPlannerDecision(f.runtime,goal.goal_id,result,planCreateDecision());
86
+ result=await sendPlannerDecision(f.runtime,goal.goal_id,result,inspectDecision());
87
+ assert.equal(result.loop.phase,'ACTING');
88
+ result=await sendPlannerDecision(f.runtime,goal.goal_id,result,{schema:'deadbyte.autonomous-decision.v2',kind:'act',action:{kind:'stat',path:'x.txt',hash:true}});
89
+ assert.equal(result.status,'input_required');
90
+ assert.equal(result.loop.phase,'VERIFYING');
91
+ const journal=await f.runtime.events({goalId:goal.goal_id,fromSeq:1,limit:200});
92
+ const event=journal.events.find(item=>item.type==='delegated_action_completed'&&item.payload?.operation?.kind==='stat');
93
+ assert.ok(event);
94
+ assert.equal(event.payload.capability_id,'coding.stat');
95
+ assert.match(event.payload.result.observation_sha256,/^[0-9a-f]{64}$/);
96
+ } finally {await f.cleanup();}
97
+ });
98
+
99
+ test('R36 typed native_diff_apply binds expected operation count and advances mutation epoch only after verified apply',async()=>{
100
+ const f=await createR34Fixture();
101
+ try{
102
+ const preview=await f.nativeDiffRuntime.preview({rootId:'project',title:'typed apply',operations:[{
103
+ kind:'replace',path:'x.txt',expected_sha256:f.initial_sha256,old_string:'x',new_string:'y',expected_replacements:1
104
+ }]});
105
+ assert.equal(preview.operation_count,1);
106
+ const goal=await f.runtime.submit({submissionId:'r36-typed-apply',rootId:'project',title:'typed apply',goal:'apply the prepared native diff',acceptance:'mutation is verified and journaled'});
107
+ let result=await f.runtime.run({goalId:goal.goal_id,maxCycles:4});
108
+ result=await sendPlannerDecision(f.runtime,goal.goal_id,result,planCreateDecision());
109
+ result=await sendPlannerDecision(f.runtime,goal.goal_id,result,inspectDecision());
110
+ assert.equal(result.loop.phase,'ACTING');
111
+ result=await sendPlannerDecision(f.runtime,goal.goal_id,result,{schema:'deadbyte.autonomous-decision.v2',kind:'act',action:{kind:'native_diff_apply',diff_id:preview.diff_id,expected_operation_count:1}});
112
+ assert.equal(result.status,'input_required');
113
+ assert.equal(result.loop.phase,'VERIFYING');
114
+ const state=await f.runtime.status({goalId:goal.goal_id});
115
+ assert.equal(state.mutation_epoch,1);
116
+ assert.equal(state.mutation_count,1);
117
+ const read=await f.baseCodingRuntime.fileRead({rootId:'project',relativePath:'x.txt',encoding:'utf8'});
118
+ assert.equal(read.content,'y\n');
119
+ const verified=await f.nativeDiffRuntime.verify({diffId:preview.diff_id});
120
+ assert.equal(verified.ok,true);
121
+ assert.equal(verified.current_state_matches,true);
122
+ const journal=await f.runtime.events({goalId:goal.goal_id,fromSeq:1,limit:200});
123
+ const committed=journal.events.find(item=>item.type==='native_diff_committed'&&item.payload?.diff_id===preview.diff_id);
124
+ assert.ok(committed);
125
+ assert.equal(committed.payload.mutation_count,1);
126
+ assert.deepEqual(committed.payload.paths,['x.txt']);
127
+ } finally {await f.cleanup();}
128
+ });
129
+
130
+ test('R36 typed machine_fs_mkdir is promoted to Native Diff V2 and advances mutation epoch',async()=>{
131
+ const f=await createR34Fixture();
132
+ try{
133
+ const goal=await f.runtime.submit({submissionId:'r36-typed-mkdir',rootId:'project',title:'typed mkdir',goal:'create generated directory transactionally',acceptance:'directory creation is native-diff verified'});
134
+ let result=await f.runtime.run({goalId:goal.goal_id,maxCycles:4});
135
+ result=await sendPlannerDecision(f.runtime,goal.goal_id,result,planCreateDecision());
136
+ result=await sendPlannerDecision(f.runtime,goal.goal_id,result,inspectDecision());
137
+ result=await sendPlannerDecision(f.runtime,goal.goal_id,result,{schema:'deadbyte.autonomous-decision.v2',kind:'act',action:{kind:'machine_fs_mkdir',path:'generated'}});
138
+ assert.equal(result.status,'input_required');
139
+ assert.equal(result.loop.phase,'VERIFYING');
140
+ const state=await f.runtime.status({goalId:goal.goal_id});
141
+ assert.equal(state.mutation_epoch,1);
142
+ assert.equal(state.mutation_count,1);
143
+ const dir=await f.machineFsRuntime.state({rootId:'project',relativePath:'generated'});
144
+ assert.equal(dir.exists,true);
145
+ assert.equal(dir.kind,'directory');
146
+ const journal=await f.runtime.events({goalId:goal.goal_id,fromSeq:1,limit:200});
147
+ const committed=journal.events.find(item=>item.type==='native_diff_committed');
148
+ assert.ok(committed);
149
+ assert.deepEqual(committed.payload.paths,['generated']);
150
+ } finally {await f.cleanup();}
151
+ });
@@ -48,7 +48,7 @@ test('R34 run/status output contracts accept only the sanitized public loop proj
48
48
  assert.equal(run.structuredContent.loop.phase,'ACTING');
49
49
  const status = autonomousStructuredResult(autonomousGoalStatusOutputSchema,{
50
50
  status:'ok',goal_id:'1'.repeat(64),goal_sha256:'2'.repeat(64),title:'x',root_id:'project',journal_verified:true,
51
- ...baseDerived(),loop:publicLoop
51
+ run_busy:false,run_owner_pid:null,run_lock_created_at_utc:null,...baseDerived(),loop:publicLoop
52
52
  });
53
53
  assert.equal(status.structuredContent.loop.pending_action.kind,'patch');
54
54
  const approved = autonomousStructuredResult(autonomousGoalApproveOutputSchema,{
@@ -24,7 +24,7 @@ const r23Tools = [
24
24
  'agent_task_approve','agent_task_cancel','agent_task_events','agent_task_run',
25
25
  'agent_task_status','agent_task_submit','agent_task_verify',
26
26
  'coding_benchmark_run','coding_command_run','coding_file_read','coding_file_write','coding_files_read',
27
- 'coding_receipt_verify','coding_search','coding_session_status','coding_stat','coding_symbol_definition','coding_symbol_outline','coding_symbol_references','coding_symbol_replace',
27
+ 'coding_receipt_verify','coding_search','coding_session_status','coding_stat','coding_symbol_definition','coding_symbol_diagnostics','coding_symbol_implementations','coding_symbol_outline','coding_symbol_references','coding_symbol_rename_preview','coding_symbol_replace',
28
28
  'coding_task_approve','coding_task_cancel','coding_task_events','coding_task_run',
29
29
  'coding_task_status','coding_task_submit','coding_task_verify','coding_text_replace','coding_tree'
30
30
  ];
@@ -75,7 +75,7 @@ async function fixture() {
75
75
  return { root, client, transport };
76
76
  }
77
77
 
78
- test('R34 hermetic autonomous fixture exposes the exact 46-tool no-host catalog', async () => {
78
+ test('R36 hermetic autonomous fixture exposes the exact 49-tool no-host catalog', async () => {
79
79
  const f = await fixture();
80
80
  try {
81
81
  await f.client.connect(f.transport);
@@ -0,0 +1,107 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { readFile } from 'node:fs/promises';
4
+ import { fileURLToPath } from 'node:url';
5
+ import path from 'node:path';
6
+ import {
7
+ R36_CAPABILITY_BENCHMARK_SCHEMA,
8
+ normalizeR36BenchmarkCase,
9
+ buildR36CapabilityBenchmark
10
+ } from '../src/capability-benchmark.mjs';
11
+ import {
12
+ R36_BENCHMARK_CASE_IDS,
13
+ r36BenchmarkCaseDefinitions
14
+ } from '../src/capability-benchmark-runner.mjs';
15
+
16
+ const REQUIRED=Object.freeze([
17
+ 'repository_tree_exploration',
18
+ 'literal_content_search',
19
+ 'regex_content_search',
20
+ 'filename_path_search',
21
+ 'deterministic_search_paging_cancel',
22
+ 'bounded_multi_file_read',
23
+ 'rich_stat_reparse_handling',
24
+ 'stale_edit_race_rejection',
25
+ 'transactional_multi_file_native_diff',
26
+ 'topology_mkdir_move_delete_rollback',
27
+ 'semantic_typescript_navigation',
28
+ 'semantic_python_navigation',
29
+ 'semantic_rust_navigation',
30
+ 'semantic_cpp_navigation',
31
+ 'diagnostics_normalization',
32
+ 'implementation_lookup',
33
+ 'cross_file_rename_transaction',
34
+ 'long_process_lifecycle',
35
+ 'policy_defined_process_action',
36
+ 'process_crash_reconciliation',
37
+ 'autonomous_failing_test_repair',
38
+ 'autonomous_search_semantic_patch_test',
39
+ 'release_gate_finish_without_evidence_refusal',
40
+ 'provider_bridge_interruption_recovery',
41
+ 'remote_result_replay_deduplication',
42
+ 'compact_connector_capability_closure',
43
+ 'live_log_request_before_result',
44
+ 'live_log_redaction',
45
+ 'forged_stale_receipt_rejection',
46
+ 'rollback_r35_restore_r36'
47
+ ]);
48
+ const H=c=>c.repeat(64);
49
+ const base={
50
+ case_id:REQUIRED[0],fixture_sha256:H('a'),correct:true,round_trips:2,bytes_returned:128,elapsed_ms:12.5,
51
+ stale_rejected:false,recovery_success:true,duplicate_side_effects:0,capability_reachable:true,
52
+ evidence_verified:true,release_gate_result:'not_applicable',evidence_sha256:H('b')
53
+ };
54
+
55
+ test('R36 benchmark corpus exposes exactly the 30 approved production coding cases',async()=>{
56
+ assert.equal(R36_CAPABILITY_BENCHMARK_SCHEMA,'deadbyte.r36-capability-benchmark.v1');
57
+ assert.deepEqual([...R36_BENCHMARK_CASE_IDS],REQUIRED);
58
+ const defs=r36BenchmarkCaseDefinitions();
59
+ assert.equal(defs.length,30);
60
+ assert.deepEqual(defs.map(item=>item.case_id),REQUIRED);
61
+ assert.equal(new Set(defs.map(item=>item.case_id)).size,30);
62
+ for(const item of defs){
63
+ assert.ok(Array.isArray(item.test_files)&&item.test_files.length>=1,item.case_id);
64
+ assert.ok(Array.isArray(item.fixture_files)&&item.fixture_files.length>=1,item.case_id);
65
+ assert.ok(Number.isInteger(item.round_trips)&&item.round_trips>=1,item.case_id);
66
+ assert.equal(typeof item.capability_reachable,'boolean',item.case_id);
67
+ assert.equal(typeof item.evidence_verified,'boolean',item.case_id);
68
+ assert.ok(['passed','blocked','not_applicable'].includes(item.release_gate_result),item.case_id);
69
+ }
70
+ const root=path.resolve(fileURLToPath(new URL('../',import.meta.url)));
71
+ const corpus=JSON.parse(await readFile(path.join(root,'bench','fixtures','corpus.json'),'utf8'));
72
+ assert.equal(corpus.schema,'deadbyte.r36-capability-corpus.v1');
73
+ assert.equal(corpus.suite_id,'r36-production-coding-v1');
74
+ assert.deepEqual(corpus.cases.map(item=>item.case_id),REQUIRED);
75
+ });
76
+
77
+ test('R36 benchmark case requires reachability, evidence verification and typed release-gate result',()=>{
78
+ const value=normalizeR36BenchmarkCase(base);
79
+ assert.equal(value.capability_reachable,true);
80
+ assert.equal(value.evidence_verified,true);
81
+ assert.equal(value.release_gate_result,'not_applicable');
82
+ assert.throws(()=>normalizeR36BenchmarkCase({...base,capability_reachable:undefined}),/reachable/i);
83
+ assert.throws(()=>normalizeR36BenchmarkCase({...base,evidence_verified:undefined}),/evidence/i);
84
+ assert.throws(()=>normalizeR36BenchmarkCase({...base,release_gate_result:'maybe'}),/release/i);
85
+ });
86
+
87
+ test('R36 aggregate fails closed when correctness reachability or evidence proof is missing',()=>{
88
+ const ok=buildR36CapabilityBenchmark({suite_id:'r36-production-coding-v1',cases:[base]});
89
+ assert.equal(ok.overall_correct,true);
90
+ assert.equal(ok.capability_closure,true);
91
+ assert.equal(ok.evidence_closure,true);
92
+ assert.equal('score' in ok,false);
93
+ const unreachable=buildR36CapabilityBenchmark({suite_id:'r36-production-coding-v1',cases:[{...base,capability_reachable:false}]});
94
+ assert.equal(unreachable.overall_correct,false);
95
+ assert.equal(unreachable.capability_closure,false);
96
+ const unverified=buildR36CapabilityBenchmark({suite_id:'r36-production-coding-v1',cases:[{...base,evidence_verified:false}]});
97
+ assert.equal(unverified.overall_correct,false);
98
+ assert.equal(unverified.evidence_closure,false);
99
+ });
100
+
101
+ test('R36 verdict identity is independent of timing and byte-count noise while observation identity retains it',()=>{
102
+ const first=buildR36CapabilityBenchmark({suite_id:'r36-production-coding-v1',cases:[base]});
103
+ const noisy=buildR36CapabilityBenchmark({suite_id:'r36-production-coding-v1',cases:[{...base,elapsed_ms:999.25,bytes_returned:999999,evidence_sha256:H('c')}]});
104
+ assert.match(first.verdict_identity_sha256,/^[0-9a-f]{64}$/);
105
+ assert.equal(first.verdict_identity_sha256,noisy.verdict_identity_sha256);
106
+ assert.notEqual(first.observation_sha256,noisy.observation_sha256);
107
+ });
@@ -0,0 +1,52 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { createHash } from 'node:crypto';
4
+ import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
5
+ import os from 'node:os';
6
+ import path from 'node:path';
7
+ import { fileURLToPath } from 'node:url';
8
+ import { createSemanticLspBackend } from '../src/semantic-lsp-backend.mjs';
9
+
10
+ const here=path.dirname(fileURLToPath(import.meta.url));
11
+ const serverFixture=path.join(here,'fixtures','lsp-framed-server.mjs');
12
+ const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
13
+ const nodeSha=sha256(await readFile(process.execPath));
14
+ const fixtureSha=sha256(await readFile(serverFixture));
15
+
16
+ async function proveNavigation({extension,languageId,engineId}){
17
+ const root=await mkdtemp(path.join(os.tmpdir(),`deadbyte-r36-${engineId}-`));
18
+ const main=`main${extension}`; const peer=`peer${extension}`;
19
+ await writeFile(path.join(root,main),'export function main() { return alpha(); }\n','utf8');
20
+ await writeFile(path.join(root,peer),'export function alpha() { return 1; }\n','utf8');
21
+ const codingRuntime={
22
+ policy:{roots:{project:{real_path:root,read:true,write:true,exec:false,deny_paths:[]}}},
23
+ async sessionStatus(){return {armed:true,reason:'standing-grant',root_ids:['project']};},
24
+ async tree(){return {truncated:false,entries:[{type:'file',path:main},{type:'file',path:peer}]};},
25
+ async fileRead({relativePath}){const content=await readFile(path.join(root,relativePath),'utf8');return {status:'ok',content,sha256:sha256(Buffer.from(content,'utf8'))};},
26
+ async textReplace(){throw new Error('not used by navigation benchmark');}
27
+ };
28
+ try{
29
+ const backend=createSemanticLspBackend({id:engineId,extensions:[extension],codingRuntime,server:{
30
+ language_id:languageId,executable_path:process.execPath,executable_sha256:nodeSha,args:[serverFixture],
31
+ dependencies:[{path:serverFixture,expectedSha256:fixtureSha}],
32
+ initialization_options:{expectedLanguageId:languageId,requiredOpenCount:2},request_timeout_ms:1000,max_message_bytes:131072
33
+ }});
34
+ const definition=await backend.definition({rootId:'project',relativePath:main,line:0,column:18,maxResults:10});
35
+ const references=await backend.references({rootId:'project',relativePath:main,line:0,column:18,maxResults:10});
36
+ assert.equal(definition.engine,engineId);
37
+ assert.ok(definition.locations.some(item=>item.path===peer),JSON.stringify(definition.locations));
38
+ assert.ok(references.locations.some(item=>item.path===peer),JSON.stringify(references.locations));
39
+ } finally {await rm(root,{recursive:true,force:true});}
40
+ }
41
+
42
+ test('R36 benchmark Python symbol navigation',async()=>{
43
+ await proveNavigation({extension:'.py',languageId:'python',engineId:'pyright-fixture'});
44
+ });
45
+
46
+ test('R36 benchmark Rust symbol navigation',async()=>{
47
+ await proveNavigation({extension:'.rs',languageId:'rust',engineId:'rust-analyzer-fixture'});
48
+ });
49
+
50
+ test('R36 benchmark Cpp symbol navigation',async()=>{
51
+ await proveNavigation({extension:'.cpp',languageId:'cpp',engineId:'clangd-fixture'});
52
+ });
@@ -0,0 +1,23 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { readFile } from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ const root=path.resolve(fileURLToPath(new URL('../',import.meta.url)));
7
+
8
+ test('R36 capability evidence distinguishes documented competitor claims from direct observation and avoids blanket superiority',async()=>{
9
+ const file=await readFile(path.join(root,'docs','R36-CAPABILITY-EVIDENCE.md'),'utf8');
10
+ assert.match(file,/https:\/\/github\.com\/wonderwhy-er\/DesktopCommanderMCP/i);
11
+ assert.match(file,/https:\/\/github\.com\/desktop-commander\/remote-desktop-commander/i);
12
+ assert.match(file,/https:\/\/github\.com\/oraios\/serena/i);
13
+ assert.match(file,/documented/i);
14
+ assert.match(file,/direct_observation/i);
15
+ assert.match(file,/3a1d668fcc0c3c38362d0c642c5247357ed7ec6063d89b544c7a1c090521c66e/);
16
+ assert.doesNotMatch(file,/\b(?:best|superior|beats? all|winner|dominates?)\b/i);
17
+ });
18
+
19
+ test('R36 README points to reproducible capability evidence instead of a tool-count victory claim',async()=>{
20
+ const file=await readFile(path.join(root,'README.txt'),'utf8');
21
+ assert.match(file,/R36-CAPABILITY-EVIDENCE\.md/);
22
+ assert.doesNotMatch(file,/\b(?:most tools|tool-count victory|beats? all|best MCP)\b/i);
23
+ });