deadbyte-mcp 0.9.0 → 0.10.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 (121) hide show
  1. package/MANIFEST.SHA256 +119 -91
  2. package/README.txt +16 -11
  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-verify.mjs +88 -39
  43. package/scripts/final-closure.mjs +63 -56
  44. package/scripts/gate-windows.ps1 +3 -3
  45. package/scripts/release-parity-tests.ps1 +9 -0
  46. package/scripts/release-parity.mjs +149 -139
  47. package/scripts/windows-gate-evidence.mjs +5 -5
  48. package/src/autonomous-context-engine.mjs +2 -1
  49. package/src/autonomous-mcp-tools.mjs +5 -1
  50. package/src/autonomous-output-contracts.mjs +4 -4
  51. package/src/autonomous-planner-contracts.mjs +36 -1
  52. package/src/autonomous-planner.mjs +25 -3
  53. package/src/autonomous-runtime.mjs +191 -21
  54. package/src/capability-benchmark-runner.mjs +86 -1
  55. package/src/capability-benchmark.mjs +45 -0
  56. package/src/capability-ledger.mjs +158 -0
  57. package/src/coding-mcp-tools.mjs +31 -17
  58. package/src/coding-output-contracts.mjs +48 -10
  59. package/src/coding-plane.mjs +45 -9
  60. package/src/coding-search.mjs +130 -47
  61. package/src/compact-gateway-mcp-tools.mjs +128 -0
  62. package/src/compact-gateway-output-contracts.mjs +16 -0
  63. package/src/deadbyte-cli.mjs +51 -28
  64. package/src/machine-fs-smoke-client.mjs +1 -1
  65. package/src/machine-fs.mjs +51 -8
  66. package/src/mcp-server.mjs +32 -9
  67. package/src/native-diff-v2.mjs +337 -0
  68. package/src/native-diff.mjs +50 -2
  69. package/src/observation-smoke-client.mjs +1 -1
  70. package/src/operator-surface.mjs +7 -1
  71. package/src/process-runtime.mjs +98 -11
  72. package/src/process-smoke-client.mjs +11 -3
  73. package/src/r36-compact-disarmed-probe.mjs +50 -0
  74. package/src/r36-full-surface-probe.mjs +56 -0
  75. package/src/remote-live-log.mjs +76 -0
  76. package/src/remote-mcp-autonomous-smoke-client.mjs +7 -3
  77. package/src/remote-mcp-coding-smoke-client.mjs +1 -1
  78. package/src/remote-mcp-r36-parity-client.mjs +175 -0
  79. package/src/remote-mcp-smoke-client.mjs +112 -56
  80. package/src/runtime-update.mjs +51 -1
  81. package/src/search-cursor.mjs +45 -0
  82. package/src/semantic-code.mjs +72 -5
  83. package/src/semantic-lsp-backend.mjs +39 -3
  84. package/src/version.mjs +1 -1
  85. package/test/autonomous-capability-r36.test.mjs +151 -0
  86. package/test/autonomous-runtime.test.mjs +2 -2
  87. package/test/capability-benchmark-r36.test.mjs +107 -0
  88. package/test/capability-benchmark-semantic-r36.test.mjs +52 -0
  89. package/test/capability-claims-r36.test.mjs +23 -0
  90. package/test/capability-ledger-r36.test.mjs +102 -0
  91. package/test/coding-catalog-consistency.test.mjs +2 -2
  92. package/test/coding-plane.test.mjs +2 -2
  93. package/test/coding-runtime.test.mjs +16 -0
  94. package/test/coding-search-r36.test.mjs +90 -0
  95. package/test/compact-catalog-r36.test.mjs +37 -0
  96. package/test/compact-gateway-r36.test.mjs +66 -0
  97. package/test/contained.test.mjs +1 -1
  98. package/test/core.test.mjs +1 -1
  99. package/test/deferred-slot-operation.test.mjs +9 -0
  100. package/test/fixtures/lsp-framed-server.mjs +2 -0
  101. package/test/helpers/autonomous-r34-fixture.mjs +5 -3
  102. package/test/multi-file-read.test.mjs +3 -0
  103. package/test/native-diff-topology-r36.test.mjs +105 -0
  104. package/test/package-boundary.test.mjs +6 -0
  105. package/test/process-longrun-r36.test.mjs +82 -0
  106. package/test/process-release-gate.test.mjs +9 -0
  107. package/test/production-docs.test.mjs +3 -3
  108. package/test/prompts-resources.test.mjs +7 -1
  109. package/test/r33-closeout-regression.test.mjs +4 -3
  110. package/test/r33-finalization.test.mjs +14 -9
  111. package/test/r36-finalization.test.mjs +104 -0
  112. package/test/r36-release-identity.test.mjs +52 -0
  113. package/test/release-version.test.mjs +18 -15
  114. package/test/remote-live-log-r36.test.mjs +37 -0
  115. package/test/remote-live-log-recovery-r36.test.mjs +41 -0
  116. package/test/remote-r24-catalog.test.mjs +13 -0
  117. package/test/remote-session-cli.test.mjs +40 -30
  118. package/test/runtime-self-update.test.mjs +58 -1
  119. package/test/semantic-lsp-backend.test.mjs +9 -0
  120. package/test/semantic-r36-rename.test.mjs +82 -0
  121. package/deadbyte-mcp-0.8.9.tgz +0 -0
@@ -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
+ });
@@ -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
+ });
@@ -0,0 +1,102 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {
4
+ CAPABILITY_LEDGER_SCHEMA,
5
+ capabilityProfileFromEnv,
6
+ createCapabilityLedger,
7
+ assertCapabilityClosure
8
+ } from '../src/capability-ledger.mjs';
9
+
10
+ const entry = overrides => ({
11
+ id:'coding.search',
12
+ full_tool:'coding_search',
13
+ compact_tool:'coding_inspect',
14
+ compact_op:'search',
15
+ runtime_flag:'DEADBYTE_CODING_RUNTIME',
16
+ authority:'coding',
17
+ mutating:false,
18
+ receipt_class:'observation',
19
+ production:true,
20
+ host_only:false,
21
+ ...overrides
22
+ });
23
+
24
+ const snapshot = names => ({
25
+ schema:'deadbyte.tool-surface.v1',
26
+ tools:names.map(name=>({name,input_sha256:'0'.repeat(64),output_sha256:'1'.repeat(64)})),
27
+ surface_sha256:'2'.repeat(64)
28
+ });
29
+
30
+ test('R36 capability ledger rejects duplicate ids', () => {
31
+ assert.throws(() => createCapabilityLedger([
32
+ entry({}),
33
+ entry({full_tool:'other_tool'})
34
+ ]), /duplicate capability id/i);
35
+ });
36
+
37
+ test('R36 capability ledger validates authority and canonicalizes identity', () => {
38
+ assert.throws(() => createCapabilityLedger([entry({authority:'root'})]), /authority/i);
39
+ const a=createCapabilityLedger([
40
+ entry({id:'process.read',full_tool:'process_session_read',compact_tool:'process_session',compact_op:'read',runtime_flag:'DEADBYTE_PROCESS_RUNTIME',authority:'process'}),
41
+ entry({})
42
+ ]);
43
+ const b=createCapabilityLedger([
44
+ entry({}),
45
+ entry({id:'process.read',full_tool:'process_session_read',compact_tool:'process_session',compact_op:'read',runtime_flag:'DEADBYTE_PROCESS_RUNTIME',authority:'process'})
46
+ ]);
47
+ assert.equal(a.schema,CAPABILITY_LEDGER_SCHEMA);
48
+ assert.equal(a.ledger_sha256,b.ledger_sha256);
49
+ assert.deepEqual(a.entries.map(x=>x.id),['coding.search','process.read']);
50
+ assert.ok(Object.isFrozen(a));
51
+ assert.ok(Object.isFrozen(a.entries));
52
+ });
53
+
54
+ test('R36 surface profile defaults full and accepts only full or compact', () => {
55
+ assert.equal(capabilityProfileFromEnv({}),'full');
56
+ assert.equal(capabilityProfileFromEnv({DEADBYTE_CAPABILITY_PROFILE:'full'}),'full');
57
+ assert.equal(capabilityProfileFromEnv({DEADBYTE_CAPABILITY_PROFILE:'compact'}),'compact');
58
+ assert.throws(() => capabilityProfileFromEnv({DEADBYTE_CAPABILITY_PROFILE:'wide'}), /full or compact/i);
59
+ });
60
+
61
+ test('R36 compact closure covers every production non-host capability', () => {
62
+ const ledger=createCapabilityLedger([
63
+ entry({}),
64
+ entry({id:'host.exec',full_tool:'host_exec',compact_tool:null,compact_op:null,runtime_flag:'DEADBYTE_PRIVILEGED_POLICY',authority:'host',mutating:true,receipt_class:'host',production:false,host_only:true})
65
+ ]);
66
+ assert.equal(assertCapabilityClosure({
67
+ ledger,
68
+ fullToolSnapshot:snapshot(['coding_search','host_exec']),
69
+ compactToolSnapshot:snapshot(['coding_inspect'])
70
+ }),true);
71
+ });
72
+
73
+ test('R36 closure fails when a production route is lost or advertised tool is absent', () => {
74
+ const missingCompact=createCapabilityLedger([entry({compact_tool:null,compact_op:null})]);
75
+ assert.throws(() => assertCapabilityClosure({
76
+ ledger:missingCompact,
77
+ fullToolSnapshot:snapshot(['coding_search']),
78
+ compactToolSnapshot:snapshot([])
79
+ }), /compact route/i);
80
+
81
+ const ledger=createCapabilityLedger([entry({})]);
82
+ assert.throws(() => assertCapabilityClosure({
83
+ ledger,
84
+ fullToolSnapshot:snapshot([]),
85
+ compactToolSnapshot:snapshot(['coding_inspect'])
86
+ }), /full tool/i);
87
+ assert.throws(() => assertCapabilityClosure({
88
+ ledger,
89
+ fullToolSnapshot:snapshot(['coding_search']),
90
+ compactToolSnapshot:snapshot([])
91
+ }), /compact tool/i);
92
+ });
93
+
94
+ test('R36 compact surface hard-fails above the observed 42-tool ceiling', () => {
95
+ const ledger=createCapabilityLedger([entry({})]);
96
+ const tooMany=Array.from({length:43},(_,i)=>i===0?'coding_inspect':`extra_${i}`);
97
+ assert.throws(() => assertCapabilityClosure({
98
+ ledger,
99
+ fullToolSnapshot:snapshot(['coding_search']),
100
+ compactToolSnapshot:snapshot(tooMany)
101
+ }), /42/i);
102
+ });
@@ -8,7 +8,7 @@ const root=path.resolve(fileURLToPath(new URL('..',import.meta.url)));
8
8
  const expected=[
9
9
  'coding_benchmark_run','coding_command_run','coding_file_read','coding_file_write','coding_files_read',
10
10
  'coding_receipt_verify','coding_search','coding_session_status','coding_stat','coding_symbol_definition',
11
- 'coding_symbol_outline','coding_symbol_references','coding_symbol_replace','coding_task_approve','coding_task_cancel',
11
+ 'coding_symbol_diagnostics','coding_symbol_implementations','coding_symbol_outline','coding_symbol_references','coding_symbol_rename_preview','coding_symbol_replace','coding_task_approve','coding_task_cancel',
12
12
  'coding_task_events','coding_task_run','coding_task_status','coding_task_submit','coding_task_verify','coding_text_replace','coding_tree'
13
13
  ].sort();
14
14
  function extract(source){
@@ -17,7 +17,7 @@ function extract(source){
17
17
  return [...m[1].matchAll(/'([^']+)'/g)].map(x=>x[1]).sort();
18
18
  }
19
19
  for(const rel of ['src/machine-fs-smoke-client.mjs','src/observation-smoke-client.mjs','src/remote-mcp-coding-smoke-client.mjs','src/remote-mcp-smoke-client.mjs']){
20
- test(`${rel} uses the exact R34 22-tool coding catalog`,async()=>{
20
+ test(`${rel} uses the exact R36 25-tool coding catalog`,async()=>{
21
21
  const source=await readFile(path.join(root,...rel.split('/')),'utf8');
22
22
  assert.deepEqual(extract(source),expected);
23
23
  });
@@ -15,7 +15,7 @@ const serverPath = path.join(repoRoot, 'src', 'mcp-server.mjs');
15
15
  const workspaceRoot = path.join(repoRoot, 'workspaces');
16
16
  const codingTools = [
17
17
  'coding_benchmark_run', 'coding_command_run', 'coding_file_read', 'coding_file_write', 'coding_files_read',
18
- 'coding_receipt_verify', 'coding_search', 'coding_session_status', 'coding_stat', 'coding_symbol_definition', 'coding_symbol_outline', 'coding_symbol_references', 'coding_symbol_replace', 'coding_task_approve', 'coding_task_cancel',
18
+ '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', 'coding_task_approve', 'coding_task_cancel',
19
19
  'coding_task_events', 'coding_task_run', 'coding_task_status', 'coding_task_submit',
20
20
  'coding_task_verify', 'coding_text_replace', 'coding_tree'
21
21
  ];
@@ -69,7 +69,7 @@ async function fixture() {
69
69
  return { root, client, transport };
70
70
  }
71
71
 
72
- test('R34 hermetic coding fixture exposes the exact 34-tool no-host catalog', async () => {
72
+ test('R36 hermetic coding fixture exposes the exact 37-tool no-host catalog', async () => {
73
73
  const f = await fixture();
74
74
  try {
75
75
  await f.client.connect(f.transport);
@@ -56,6 +56,22 @@ test('coding plane edits files under lease and verifies signed action receipts',
56
56
  } finally { await rm(f.root, { recursive: true, force: true }); }
57
57
  });
58
58
 
59
+ test('R36 coding stat exposes mutation-relevant observation identity', async () => {
60
+ const f = await fixture();
61
+ try {
62
+ await writeFile(path.join(f.project,'stat.txt'),'stat-body\n');
63
+ const value=await f.runtime.stat({rootId:'project',relativePath:'stat.txt',hash:true});
64
+ assert.equal(value.status,'ok');
65
+ assert.equal(value.normalized_path,'stat.txt');
66
+ assert.equal(value.type,'file');
67
+ assert.equal(value.reparse_state,'none');
68
+ assert.match(value.sha256,/^[0-9a-f]{64}$/);
69
+ assert.match(value.object_identity_sha256,/^[0-9a-f]{64}$/);
70
+ assert.match(value.observation_sha256,/^[0-9a-f]{64}$/);
71
+ assert.equal(value.policy_root_id,'project');
72
+ } finally { await rm(f.root, { recursive: true, force: true }); }
73
+ });
74
+
59
75
  test('coding plane rejects mutation when lease is absent or precondition is stale', async () => {
60
76
  const f = await fixture({ armed: false });
61
77
  try {
@@ -0,0 +1,90 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { mkdtemp, rm } from 'node:fs/promises';
4
+ import os from 'node:os';
5
+ import path from 'node:path';
6
+ import { generateTrustKeypair } from '../src/trust.mjs';
7
+ import { createSearchCursorCodec } from '../src/search-cursor.mjs';
8
+ import { createCodingSearch } from '../src/coding-search.mjs';
9
+
10
+ async function fixture(){
11
+ const temp=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r36-search-'));
12
+ const keys=await generateTrustKeypair({privateKeyPath:path.join(temp,'private.pem'),publicKeyPath:path.join(temp,'public.pem')});
13
+ const state=new Map([
14
+ ['src/a.txt',Buffer.from('foo1 foo2\nbar foo3\n','utf8')],
15
+ ['src/b.txt',Buffer.from('other FOO4 and foo5\n','utf8')],
16
+ ['src/foo-file.js',Buffer.from('nothing here\n','utf8')],
17
+ ['src/binary.bin',Buffer.from([0xff,0xfe,0x00,0x61])]
18
+ ]);
19
+ let reads=0;
20
+ const tree=async()=>({status:'ok',root_id:'core',path:'.',truncated:false,entries:[...state].map(([p,b])=>({path:p,type:'file',bytes:b.length}))});
21
+ const fileRead=async({relativePath,encoding})=>{
22
+ reads+=1;
23
+ const bytes=state.get(relativePath);
24
+ if(!bytes) throw new Error('missing');
25
+ return {status:'ok',root_id:'core',path:relativePath,encoding,bytes:bytes.length,sha256:(await import('node:crypto')).createHash('sha256').update(bytes).digest('hex'),content:encoding==='base64'?bytes.toString('base64'):bytes.toString('utf8')};
26
+ };
27
+ const cursorCodec=createSearchCursorCodec({signingKeyPath:keys.privateKeyPath,verifyKeyPath:keys.publicKeyPath});
28
+ const search=createCodingSearch({tree,fileRead,cursorCodec});
29
+ return {temp,state,search,get reads(){return reads;},cleanup:()=>rm(temp,{recursive:true,force:true})};
30
+ }
31
+
32
+ test('R36 regex search returns multiple matches per file with deterministic signed paging',async()=>{
33
+ const f=await fixture();
34
+ try{
35
+ const first=await f.search({rootId:'core',path:'.',target:'content',mode:'regex',pattern:'foo\\d',caseSensitive:false,pageSize:2,maxResults:20});
36
+ assert.equal(first.matches.length,2);
37
+ assert.deepEqual(first.matches.map(x=>[x.path,x.line,x.column]),[['src/a.txt',1,1],['src/a.txt',1,6]]);
38
+ assert.match(first.query_sha256,/^[0-9a-f]{64}$/);
39
+ assert.match(first.snapshot_sha256,/^[0-9a-f]{64}$/);
40
+ assert.match(first.page_sha256,/^[0-9a-f]{64}$/);
41
+ assert.ok(first.next_cursor);
42
+ const second=await f.search({rootId:'core',path:'.',target:'content',mode:'regex',pattern:'foo\\d',caseSensitive:false,pageSize:2,maxResults:20,cursor:first.next_cursor});
43
+ assert.equal(second.matches.length,2);
44
+ assert.deepEqual(second.matches.map(x=>x.path),['src/a.txt','src/b.txt']);
45
+ assert.notEqual(second.page_sha256,first.page_sha256);
46
+ } finally {await f.cleanup();}
47
+ });
48
+
49
+ test('R36 path search does not decode file content and is deterministic',async()=>{
50
+ const f=await fixture();
51
+ try{
52
+ const result=await f.search({rootId:'core',target:'path',mode:'literal',pattern:'foo-file',pageSize:10,maxResults:20});
53
+ assert.equal(result.matches.length,1);
54
+ assert.equal(result.matches[0].path,'src/foo-file.js');
55
+ assert.equal(result.matches[0].line,null);
56
+ assert.equal(result.bytes_scanned,0);
57
+ assert.equal(f.reads,0);
58
+ } finally {await f.cleanup();}
59
+ });
60
+
61
+ test('R36 search cursor is query-bound and stale snapshot fails closed',async()=>{
62
+ const f=await fixture();
63
+ try{
64
+ const first=await f.search({rootId:'core',target:'content',mode:'literal',pattern:'foo',pageSize:1,maxResults:20});
65
+ await assert.rejects(()=>f.search({rootId:'core',target:'content',mode:'literal',pattern:'bar',pageSize:1,maxResults:20,cursor:first.next_cursor}),/cursor.*query/i);
66
+ f.state.set('src/a.txt',Buffer.from('foo1 changed same workflow\n','utf8'));
67
+ await assert.rejects(()=>f.search({rootId:'core',target:'content',mode:'literal',pattern:'foo',pageSize:1,maxResults:20,cursor:first.next_cursor}),/cursor.*stale|snapshot/i);
68
+ } finally {await f.cleanup();}
69
+ });
70
+
71
+ test('R36 invalid regex fails before repository file reads and binary is classified',async()=>{
72
+ const f=await fixture();
73
+ try{
74
+ await assert.rejects(()=>f.search({rootId:'core',target:'content',mode:'regex',pattern:'[unterminated'}),/regex/i);
75
+ assert.equal(f.reads,0);
76
+ const result=await f.search({rootId:'core',target:'content',mode:'literal',pattern:'foo',pageSize:20,maxResults:20});
77
+ assert.equal(result.binary_files_skipped,1);
78
+ assert.ok(result.matches.length>=5);
79
+ } finally {await f.cleanup();}
80
+ });
81
+
82
+ test('R36 scan-byte bound truncates deterministically',async()=>{
83
+ const f=await fixture();
84
+ try{
85
+ const result=await f.search({rootId:'core',target:'content',mode:'literal',pattern:'foo',maxScanBytes:10,pageSize:20,maxResults:20});
86
+ assert.equal(result.truncated,true);
87
+ assert.equal(result.truncation_reason,'scan_byte_limit');
88
+ assert.ok(result.bytes_scanned<=10);
89
+ } finally {await f.cleanup();}
90
+ });