deadbyte-mcp 0.11.2 → 0.12.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 (102) hide show
  1. package/MANIFEST.SHA256 +101 -39
  2. package/README.txt +10 -9
  3. package/acceptance/r40/desktop-live-drift.mjs +106 -0
  4. package/acceptance/r40/desktop-live-ground.mjs +110 -0
  5. package/acceptance/r40/desktop-live-input.mjs +128 -0
  6. package/acceptance/r40/desktop-live-observe.mjs +100 -0
  7. package/acceptance/r40/desktop-live-uia.mjs +121 -0
  8. package/bin/deadbyte-desktop-input-r40.exe +0 -0
  9. package/bin/deadbyte-desktop-input-r40.obj +0 -0
  10. package/bin/deadbyte-desktop-observer-r40.exe +0 -0
  11. package/bin/deadbyte-desktop-observer-r40.obj +0 -0
  12. package/bin/deadbyte-desktop-uia-r40.exe +0 -0
  13. package/bin/deadbyte-desktop-uia-r40.obj +0 -0
  14. package/controller/README.TXT +7 -5
  15. package/controller/deadbyte-controller.config.psd1.example +3 -0
  16. package/controller/deadbyte-controller.ps1 +149 -4
  17. package/controller/deadbyte-desktop-policy.json +41 -0
  18. package/docs/ARCHITECTURE.md +6 -1
  19. package/docs/superpowers/specs/2026-09-19-r40-desktop-computer-use-design.md +214 -0
  20. package/native/deadbyte-desktop-input.cpp +455 -0
  21. package/native/deadbyte-desktop-observer.cpp +253 -0
  22. package/native/deadbyte-desktop-uia.cpp +307 -0
  23. package/package.json +10 -8
  24. package/scripts/build-desktop-r40.ps1 +106 -0
  25. package/scripts/deferred-slot-operation-r39.mjs +124 -0
  26. package/scripts/deferred-slot-operation-r40.mjs +126 -0
  27. package/scripts/final-closure-r39.mjs +113 -0
  28. package/scripts/final-closure-r40.mjs +114 -0
  29. package/scripts/final-closure-verify-r39.mjs +208 -0
  30. package/scripts/final-closure-verify-r40.mjs +212 -0
  31. package/scripts/gate-windows-r39.ps1 +42 -0
  32. package/scripts/gate-windows-r40.ps1 +43 -0
  33. package/scripts/init-desktop-policy-r40.ps1 +79 -0
  34. package/scripts/r40-compact-ledger-probe.mjs +4 -0
  35. package/scripts/release-parity-r39.mjs +200 -0
  36. package/scripts/release-parity-r40.mjs +212 -0
  37. package/scripts/release-parity-tests-r39.ps1 +9 -0
  38. package/scripts/release-parity-tests-r40.ps1 +9 -0
  39. package/scripts/windows-gate-evidence-r39.mjs +52 -0
  40. package/scripts/windows-gate-evidence-r40.mjs +52 -0
  41. package/src/autonomous-context-engine.mjs +2 -1
  42. package/src/autonomous-planner-contracts.mjs +19 -1
  43. package/src/autonomous-planner.mjs +22 -0
  44. package/src/autonomous-runtime.mjs +144 -24
  45. package/src/capability-ledger.mjs +6 -1
  46. package/src/compact-gateway-mcp-tools.mjs +14 -2
  47. package/src/deadbyte-cli.mjs +79 -47
  48. package/src/desktop-contract.mjs +263 -0
  49. package/src/desktop-input-r40.mjs +148 -0
  50. package/src/desktop-mcp-tools-r40.mjs +126 -0
  51. package/src/desktop-memory-r40.mjs +272 -0
  52. package/src/desktop-observer-r40.mjs +231 -0
  53. package/src/desktop-policy-r40.mjs +110 -0
  54. package/src/desktop-runtime-r40.mjs +318 -0
  55. package/src/desktop-uia-r40.mjs +123 -0
  56. package/src/mcp-server.mjs +74 -19
  57. package/src/r40-compact-disarmed-probe.mjs +71 -0
  58. package/src/r40-full-surface-probe.mjs +34 -0
  59. package/src/release-generation.mjs +38 -5
  60. package/src/remote-console.mjs +41 -0
  61. package/src/remote-live-log.mjs +215 -45
  62. package/src/remote-mcp-desktop-r40-smoke-client.mjs +70 -0
  63. package/src/remote-mcp-r40-parity-client.mjs +200 -0
  64. package/src/remote-mcp-smoke-client.mjs +20 -6
  65. package/src/remote-result-journal.mjs +10 -2
  66. package/src/runtime-update.mjs +55 -17
  67. package/src/tool-audit.mjs +29 -2
  68. package/src/version.mjs +1 -1
  69. package/test/autonomous-capability-r36.test.mjs +43 -1
  70. package/test/autonomous-desktop-r40.test.mjs +188 -0
  71. package/test/capability-ledger-r36.test.mjs +1 -0
  72. package/test/cli-entrypoint.test.mjs +1 -1
  73. package/test/compact-catalog-r36.test.mjs +2 -2
  74. package/test/compact-gateway-r36.test.mjs +56 -4
  75. package/test/compact-max-catalog-r40.test.mjs +95 -0
  76. package/test/controller-desktop-r40.test.mjs +85 -0
  77. package/test/core.test.mjs +1 -1
  78. package/test/desktop-adversarial-r40.test.mjs +62 -0
  79. package/test/desktop-contract-r40.test.mjs +200 -0
  80. package/test/desktop-input-r40.test.mjs +63 -0
  81. package/test/desktop-mcp-tools-r40.test.mjs +61 -0
  82. package/test/desktop-memory-r40.test.mjs +141 -0
  83. package/test/desktop-observer-r40.test.mjs +119 -0
  84. package/test/desktop-policy-r40.test.mjs +111 -0
  85. package/test/desktop-runtime-r40.test.mjs +278 -0
  86. package/test/desktop-uia-r40.test.mjs +42 -0
  87. package/test/full-max-catalog-r40.test.mjs +91 -0
  88. package/test/helpers/autonomous-r34-fixture.mjs +3 -3
  89. package/test/production-docs.test.mjs +3 -3
  90. package/test/r33-closeout-regression.test.mjs +8 -8
  91. package/test/r33-finalization.test.mjs +14 -14
  92. package/test/r37-remote-tool-call-timeline.test.mjs +7 -6
  93. package/test/r39-finalization.test.mjs +74 -0
  94. package/test/r40-finalization.test.mjs +118 -0
  95. package/test/release-generation.test.mjs +41 -9
  96. package/test/release-version.test.mjs +19 -58
  97. package/test/remote-console-r40.test.mjs +38 -0
  98. package/test/remote-live-log-r37.test.mjs +89 -32
  99. package/test/remote-r24-catalog.test.mjs +12 -3
  100. package/test/remote-result-journal.test.mjs +15 -0
  101. package/test/remote-session-cli.test.mjs +112 -55
  102. package/test/runtime-self-update.test.mjs +44 -0
@@ -0,0 +1,278 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { createHash,generateKeyPairSync } from 'node:crypto';
4
+ import { mkdtemp,readFile,writeFile } from 'node:fs/promises';
5
+ import os from 'node:os';
6
+ import path from 'node:path';
7
+ import { createDesktopFrame } from '../src/desktop-contract.mjs';
8
+ import { DESKTOP_POLICY_SCHEMA,DESKTOP_GRANT_SCHEMA } from '../src/desktop-policy-r40.mjs';
9
+ import { createDesktopRuntime,verifyDesktopReceiptObject } from '../src/desktop-runtime-r40.mjs';
10
+
11
+ const H=value=>createHash('sha256').update(String(value)).digest('hex');
12
+ const EPOCH=H('epoch');
13
+ const TOPO=H('topology');
14
+ const WIN={hwnd:'0x1234',pid:55,process_image_sha256:H('app'),title_sha256:H('title')};
15
+
16
+ function F(at,image=H('same'),window=WIN){
17
+ return createDesktopFrame({
18
+ desktopEpoch:EPOCH,topologySha256:TOPO,observedAtUtc:at,
19
+ bounds:{left:0,top:0,width:1000,height:800},activeWindow:window,imageSha256:image
20
+ });
21
+ }
22
+ async function fixture({grantActions=['click_primary','text_input'],captureFrames=null,times=null,inputProvider=null,grounderProvider=null}={}){
23
+ const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r40-desktop-runtime-'));
24
+ const grant=path.join(root,'grant.json'),evidence=path.join(root,'evidence');
25
+ const policy={
26
+ schema:DESKTOP_POLICY_SCHEMA,enabled:true,policy_path:path.join(root,'policy.json'),
27
+ policy_sha256:H('policy'),grant_file:grant,evidence_dir:evidence,
28
+ observer:{executable:path.join(root,'observer.exe'),sha256:H('observer'),backend:'fake'},
29
+ input:{executable:path.join(root,'input.exe'),sha256:H('input')},
30
+ allowed_input_desktops:['Default'],
31
+ allowed_actions:['pointer_move','click_primary','click_secondary','double_click_primary','scroll','key_chord','text_input'],
32
+ limits:{max_frame_age_ms:2000,max_frame_bytes:8*1024*1024,capture_timeout_ms:5000,input_timeout_ms:2000,post_observe_timeout_ms:5000,max_preview_bytes:512*1024,max_text_bytes:4096}
33
+ };
34
+ await writeFile(grant,JSON.stringify({
35
+ schema:DESKTOP_GRANT_SCHEMA,policy_sha256:policy.policy_sha256,instance_nonce:H('grant-nonce'),action_kinds:grantActions
36
+ }));
37
+ const expected=F('2026-09-19T02:00:00.000Z');
38
+ const frames=captureFrames??[
39
+ {frame:F('2026-09-19T02:00:00.700Z'),backend:'fake',byte_length:4},
40
+ {frame:F('2026-09-19T02:00:01.000Z',H('after')),backend:'fake',byte_length:4}
41
+ ];
42
+ const records=new Map([[expected.frame_id,{frame:expected}]]);
43
+ let captureIndex=0;
44
+ const observerRuntime={
45
+ frameStatus(id){const r=records.get(id);if(!r)throw new Error('frame missing');return r;},
46
+ async capture(){
47
+ const item=frames[captureIndex++];
48
+ if(!item)throw new Error('capture exhausted');
49
+ records.set(item.frame.frame_id,item);return item;
50
+ }
51
+ };
52
+ const calls=[];
53
+ const provider=inputProvider??(async(action)=>{calls.push(action);return {injected:true,provider_receipt_sha256:H('provider')};});
54
+ const {privateKey,publicKey}=generateKeyPairSync('ed25519');
55
+ const clock=[...(times??[
56
+ '2026-09-19T02:00:00.500Z',
57
+ '2026-09-19T02:00:00.800Z',
58
+ '2026-09-19T02:00:00.810Z',
59
+ '2026-09-19T02:00:01.000Z'
60
+ ])];
61
+ const now=()=>clock.length?clock.shift():'2026-09-19T02:00:01.000Z';
62
+ const runtime=createDesktopRuntime({policy,observerRuntime,inputProvider:provider,grounderProvider,privateKey,keyId:'test-key',evidenceDir:evidence,now});
63
+ return {root,grant,evidence,policy,expected,runtime,calls,publicKey};
64
+ }
65
+
66
+ test('desktop runtime performs observe-target-fresh-guard-effect-post chain',async()=>{
67
+ const fx=await fixture();
68
+ const target=await fx.runtime.target({
69
+ frameId:fx.expected.frame_id,rect:{left:100,top:100,width:200,height:100},source:'uia',confidence:0.99
70
+ });
71
+ const result=await fx.runtime.action({
72
+ intentId:H('intent'),kind:'click_primary',expectedFrameId:fx.expected.frame_id,targetId:target.target.target_id
73
+ });
74
+ assert.equal(fx.calls.length,1);
75
+ assert.deepEqual(fx.calls[0].point,{x:200,y:150});
76
+ assert.equal(result.injected,true);
77
+ assert.equal(result.task_success,null);
78
+ assert.equal(result.post_observation.change_observed,true);
79
+ assert.equal(result.post_observation.success,null);
80
+ assert.equal(result.side_effect_state,'confirmed_injected');
81
+ assert.match(result.started_receipt_sha256,/^[0-9a-f]{64}$/);
82
+ assert.match(result.post_receipt_sha256,/^[0-9a-f]{64}$/);
83
+ assert.match(result.receipt_sha256,/^[0-9a-f]{64}$/);
84
+ assert.match(result.action_chain.chain_sha256,/^[0-9a-f]{64}$/);
85
+ assert.match(result.effect_id,/^[0-9a-f]{64}$/);
86
+ assert.match(result.effect_fingerprint,/^[0-9a-f]{64}$/);
87
+ assert.equal(result.effect_completion.schema,'deadbyte.effect-completion.v1');
88
+
89
+ const postReceipt=JSON.parse(await readFile(path.join(fx.evidence,`${result.post_receipt_id}.json`),'utf8'));
90
+ assert.equal(postReceipt.kind,'desktop_post_observation');
91
+ assert.equal(postReceipt.payload.post_observation_sha256,result.post_observation.post_observation_sha256);
92
+ const receipt=JSON.parse(await readFile(path.join(fx.evidence,`${result.receipt_id}.json`),'utf8'));
93
+ assert.deepEqual(verifyDesktopReceiptObject(receipt,{
94
+ policySha256:fx.policy.policy_sha256,publicKey:fx.publicKey,keyId:'test-key'
95
+ }),{ok:true,receipt_sha256:result.receipt_sha256,kind:'desktop_action_completed',receipt_id:result.receipt_id});
96
+ });
97
+
98
+ test('desktop runtime refuses effect when expected frame is stale',async()=>{
99
+ const fx=await fixture({times:['2026-09-19T02:00:03.500Z']});
100
+ await assert.rejects(fx.runtime.action({
101
+ intentId:H('stale'),kind:'click_primary',expectedFrameId:fx.expected.frame_id,point:{x:10,y:10}
102
+ }),/expected frame is stale/);
103
+ assert.equal(fx.calls.length,0);
104
+ });
105
+
106
+ test('desktop runtime re-observes and blocks pixels changed before effect',async()=>{
107
+ const changed={frame:F('2026-09-19T02:00:00.700Z',H('changed-before')),backend:'fake',byte_length:4};
108
+ const fx=await fixture({captureFrames:[changed]});
109
+ await assert.rejects(fx.runtime.action({
110
+ intentId:H('changed'),kind:'click_primary',expectedFrameId:fx.expected.frame_id,point:{x:10,y:10}
111
+ }),/pixels changed before action/);
112
+ assert.equal(fx.calls.length,0);
113
+ });
114
+
115
+ test('desktop runtime key_chord is window-scoped and tolerates unrelated pixel drift',async()=>{
116
+ const changedPre={frame:F('2026-09-19T02:00:00.700Z',H('dynamic-before')),backend:'fake',byte_length:4};
117
+ const changedPost={frame:F('2026-09-19T02:00:01.000Z',H('dynamic-after')),backend:'fake',byte_length:4};
118
+ const fx=await fixture({grantActions:['key_chord'],captureFrames:[changedPre,changedPost]});
119
+ const result=await fx.runtime.action({
120
+ intentId:H('window-key'),kind:'key_chord',expectedFrameId:fx.expected.frame_id,keyChord:['SHIFT']
121
+ });
122
+ assert.equal(fx.calls.length,1);
123
+ assert.equal(result.injected,true);
124
+ assert.deepEqual(fx.calls[0].key_chord,['SHIFT']);
125
+ });
126
+
127
+ test('desktop runtime text_input remains pixel-stable because keyboard focus is control-sensitive',async()=>{
128
+ const changed={frame:F('2026-09-19T02:00:00.700Z',H('changed-text')),backend:'fake',byte_length:4};
129
+ const fx=await fixture({grantActions:['text_input'],captureFrames:[changed]});
130
+ await assert.rejects(fx.runtime.action({
131
+ intentId:H('changed-text'),kind:'text_input',expectedFrameId:fx.expected.frame_id,text:'x'
132
+ }),/pixels changed before action/);
133
+ assert.equal(fx.calls.length,0);
134
+ });
135
+
136
+ test('desktop runtime re-observes and blocks foreground-window drift',async()=>{
137
+ const changed={frame:F('2026-09-19T02:00:00.700Z',H('same'),{...WIN,hwnd:'0x9999'}),backend:'fake',byte_length:4};
138
+ const fx=await fixture({captureFrames:[changed]});
139
+ await assert.rejects(fx.runtime.action({
140
+ intentId:H('window'),kind:'click_primary',expectedFrameId:fx.expected.frame_id,point:{x:10,y:10}
141
+ }),/foreground window changed before action/);
142
+ assert.equal(fx.calls.length,0);
143
+ });
144
+
145
+ test('T9 capture failure blocks input before any side effect dispatch',async()=>{
146
+ const fx=await fixture({captureFrames:[]});
147
+ await assert.rejects(fx.runtime.action({
148
+ intentId:H('capture-fail'),kind:'click_primary',expectedFrameId:fx.expected.frame_id,point:{x:20,y:20}
149
+ }),/capture exhausted/);
150
+ assert.equal(fx.calls.length,0);
151
+ });
152
+
153
+ test('T9 Desktop receipt substitution is detected by runtime verifier',async()=>{
154
+ const fx=await fixture();
155
+ const result=await fx.runtime.action({
156
+ intentId:H('receipt-substitution'),kind:'click_primary',expectedFrameId:fx.expected.frame_id,point:{x:20,y:20}
157
+ });
158
+ const clean=await fx.runtime.verifyReceipt({receiptId:result.receipt_id});
159
+ assert.equal(clean.ok,true);
160
+ assert.equal(clean.receipt_sha256,result.receipt_sha256);
161
+ const receiptPath=path.join(fx.evidence,result.receipt_id+'.json');
162
+ const tampered=JSON.parse(await readFile(receiptPath,'utf8'));
163
+ tampered.payload.action_sha256=H('forged-action');
164
+ await writeFile(receiptPath,JSON.stringify(tampered));
165
+ await assert.rejects(fx.runtime.verifyReceipt({receiptId:result.receipt_id}),/receipt verification failed/);
166
+ });
167
+
168
+ test('desktop runtime enforces standing-grant action scope',async()=>{
169
+ const fx=await fixture({grantActions:['click_primary']});
170
+ await assert.rejects(fx.runtime.action({
171
+ intentId:H('text'),kind:'text_input',expectedFrameId:fx.expected.frame_id,text:'hello'
172
+ }),/outside active grant/);
173
+ assert.equal(fx.calls.length,0);
174
+ });
175
+
176
+ test('desktop runtime denies mutation when grant is revoked',async()=>{
177
+ const fx=await fixture();
178
+ await writeFile(fx.grant,'{}');
179
+ await assert.rejects(fx.runtime.action({
180
+ intentId:H('revoked'),kind:'click_primary',expectedFrameId:fx.expected.frame_id,point:{x:20,y:20}
181
+ }),/desktop plane is disarmed/);
182
+ assert.equal(fx.calls.length,0);
183
+ });
184
+
185
+ test('provider failure after dispatch is signed OUTCOME_UNKNOWN and never blind-retried',async()=>{
186
+ let calls=0;
187
+ const fx=await fixture({inputProvider:async()=>{calls++;throw new Error('transport lost after dispatch');}});
188
+ let error;
189
+ try{
190
+ await fx.runtime.action({
191
+ intentId:H('fail-unknown'),kind:'click_primary',expectedFrameId:fx.expected.frame_id,point:{x:20,y:20}
192
+ });
193
+ }catch(e){error=e;}
194
+ assert.equal(calls,1);
195
+ assert.equal(error.side_effect_state,'unknown');
196
+ assert.match(error.message,/outcome unknown/);
197
+ assert.match(error.receipt_id,/^[0-9a-f]{24}$/);
198
+ const receipt=JSON.parse(await readFile(path.join(fx.evidence,`${error.receipt_id}.json`),'utf8'));
199
+ assert.equal(receipt.kind,'desktop_action_outcome_unknown');
200
+ assert.equal(receipt.payload.side_effect_state,'unknown');
201
+ });
202
+
203
+ test('definite pre-dispatch provider denial is signed as not_started',async()=>{
204
+ const provider=async()=>{const e=new Error('binary pin mismatch');e.side_effect_state='not_started';throw e;};
205
+ const fx=await fixture({inputProvider:provider});
206
+ let error;
207
+ try{
208
+ await fx.runtime.action({
209
+ intentId:H('fail-not-started'),kind:'click_primary',expectedFrameId:fx.expected.frame_id,point:{x:20,y:20}
210
+ });
211
+ }catch(e){error=e;}
212
+ assert.equal(error.side_effect_state,'not_started');
213
+ assert.match(error.message,/did not start/);
214
+ const receipt=JSON.parse(await readFile(path.join(fx.evidence,`${error.receipt_id}.json`),'utf8'));
215
+ assert.equal(receipt.kind,'desktop_action_effect_failed');
216
+ assert.equal(receipt.payload.side_effect_state,'not_started');
217
+ });
218
+
219
+ test('post-observation failure after confirmed injection is OUTCOME_UNKNOWN',async()=>{
220
+ const preOnly={frame:F('2026-09-19T02:00:00.700Z'),backend:'fake',byte_length:4};
221
+ const fx=await fixture({captureFrames:[preOnly]});
222
+ let error;
223
+ try{
224
+ await fx.runtime.action({
225
+ intentId:H('post-fail'),kind:'click_primary',expectedFrameId:fx.expected.frame_id,point:{x:20,y:20}
226
+ });
227
+ }catch(e){error=e;}
228
+ assert.equal(fx.calls.length,1);
229
+ assert.equal(error.side_effect_state,'unknown');
230
+ assert.match(error.message,/post-observation\/evidence incomplete/);
231
+ const receipt=JSON.parse(await readFile(path.join(fx.evidence,`${error.receipt_id}.json`),'utf8'));
232
+ assert.equal(receipt.kind,'desktop_action_outcome_unknown');
233
+ assert.equal(receipt.payload.injection_confirmed,true);
234
+ });
235
+
236
+ test('read-only observe works independently of desktop mutation grant',async()=>{
237
+ const fx=await fixture();
238
+ await writeFile(fx.grant,'{}');
239
+ const observed=await fx.runtime.observe();
240
+ assert.equal(observed.status,undefined);
241
+ assert.match(observed.frame.frame_id,/^[0-9a-f]{64}$/);
242
+ assert.match(observed.receipt_sha256,/^[0-9a-f]{64}$/);
243
+ });
244
+
245
+
246
+ test('desktop runtime enforces policy max_text_bytes before observation or input effect',async()=>{
247
+ const fx=await fixture({grantActions:['text_input']});
248
+ const multibyte='ก'.repeat(2000);
249
+ assert.ok(multibyte.length<=4096);
250
+ assert.ok(Buffer.byteLength(multibyte,'utf8')>fx.policy.limits.max_text_bytes);
251
+ await assert.rejects(fx.runtime.action({
252
+ intentId:H('oversize-text'),kind:'text_input',expectedFrameId:fx.expected.frame_id,text:multibyte
253
+ }),/exceeds policy byte limit/);
254
+ assert.equal(fx.calls.length,0);
255
+ });
256
+
257
+ test('T5 UIA grounding re-observes and binds candidate to fresh frame without mutation authority',async()=>{
258
+ const groundedFrame={frame:F('2026-09-19T02:00:00.700Z'),backend:'fake',byte_length:4};
259
+ const grounderProvider=async({frame,query})=>{
260
+ assert.equal(frame.frame_id,groundedFrame.frame.frame_id);
261
+ assert.equal(query.value,'Save');
262
+ return {
263
+ status:'ok',query_sha256:H('query-save'),query_kind:'name_exact',ordinal:0,visited:9,truncated:false,
264
+ matches:[{rect:{left:100,top:120,width:80,height:30},control_type:50000,enabled:true,offscreen:false}],
265
+ provider_receipt_sha256:H('uia-provider')
266
+ };
267
+ };
268
+ const fx=await fixture({captureFrames:[groundedFrame],grounderProvider});
269
+ await writeFile(fx.grant,'{}');
270
+ const result=await fx.runtime.ground({frameId:fx.expected.frame_id,query:{kind:'name_exact',value:'Save',max_results:8,ordinal:0}});
271
+ assert.equal(result.target.source,'uia');
272
+ assert.equal(result.target.frame_id,groundedFrame.frame.frame_id);
273
+ assert.deepEqual(result.target.rect,{left:100,top:120,width:80,height:30});
274
+ assert.equal(result.grounding.query_sha256,H('query-save'));
275
+ assert.match(result.grounding.receipt_sha256,/^[0-9a-f]{64}$/);
276
+ assert.equal(JSON.stringify(result).includes('Save'),false);
277
+ assert.equal(fx.calls.length,0);
278
+ });
@@ -0,0 +1,42 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { createHash } from 'node:crypto';
4
+ import { parseDesktopUiaResponse,serializeDesktopUiaRequest } from '../src/desktop-uia-r40.mjs';
5
+
6
+ const H=v=>createHash('sha256').update(String(v)).digest('hex');
7
+ const win={hwnd:'0x1234',pid:42};
8
+ const bounds={left:-100,top:0,width:2020,height:1080};
9
+
10
+ test('T5 UIA request is fixed bounded and keeps semantic query in stdin only',()=>{
11
+ const out=serializeDesktopUiaRequest({expectedWindow:win,query:{kind:'name_exact',value:'Save',max_results:4,ordinal:1}});
12
+ assert.ok(out.request.length<8192);
13
+ assert.equal(out.query.kind,'name_exact');
14
+ assert.equal(out.query.ordinal,1);
15
+ assert.match(out.query.querySha256,/^[0-9a-f]{64}$/);
16
+ assert.equal(out.request.toString('utf8').endsWith('Save'),true);
17
+ });
18
+
19
+ test('T5 UIA response is foreground-bound and filters off-desktop rectangles',()=>{
20
+ const raw=Buffer.from(JSON.stringify({
21
+ schema:'deadbyte.desktop-uia-ground.v1',foreground_hwnd:'0x1234',foreground_pid:42,
22
+ query_kind:'control_type',visited:12,truncated:false,matches:[
23
+ {left:10,top:20,width:100,height:30,control_type:50000,enabled:true,offscreen:false},
24
+ {left:5000,top:20,width:100,height:30,control_type:50000,enabled:true,offscreen:false}
25
+ ]
26
+ }));
27
+ const parsed=parseDesktopUiaResponse(raw,{expectedWindow:win,expectedBounds:bounds,query:{kind:'control_type',value:'button',max_results:8,ordinal:0}});
28
+ assert.equal(parsed.matches.length,1);
29
+ assert.deepEqual(parsed.matches[0].rect,{left:10,top:20,width:100,height:30});
30
+ assert.equal(parsed.matches[0].control_type,50000);
31
+ assert.match(parsed.provider_receipt_sha256,/^[0-9a-f]{64}$/);
32
+ assert.match(parsed.query_sha256,/^[0-9a-f]{64}$/);
33
+ });
34
+
35
+ test('T5 UIA response rejects foreground substitution and oversized query',()=>{
36
+ const raw=Buffer.from(JSON.stringify({
37
+ schema:'deadbyte.desktop-uia-ground.v1',foreground_hwnd:'0x9999',foreground_pid:42,
38
+ query_kind:'root',visited:1,truncated:false,matches:[]
39
+ }));
40
+ assert.throws(()=>parseDesktopUiaResponse(raw,{expectedWindow:win,expectedBounds:bounds,query:{kind:'root',value:'',max_results:1,ordinal:0}}),/hwnd mismatch/);
41
+ assert.throws(()=>serializeDesktopUiaRequest({expectedWindow:win,query:{kind:'name_exact',value:'x'.repeat(513)}}),/bytes invalid/);
42
+ });
@@ -0,0 +1,91 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { createHash } from 'node:crypto';
4
+ import { access, mkdir, readFile, writeFile } from 'node:fs/promises';
5
+ import path from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { Client } from '@modelcontextprotocol/client';
8
+ import { StdioClientTransport, getDefaultEnvironment } from '@modelcontextprotocol/client/stdio';
9
+ import { createR34Fixture } from './helpers/autonomous-r34-fixture.mjs';
10
+
11
+ const here=path.dirname(fileURLToPath(import.meta.url));
12
+ const repoRoot=path.resolve(here,'..');
13
+ const serverPath=path.join(repoRoot,'src','mcp-server.mjs');
14
+ const desktopPolicyPath=path.join(repoRoot,'controller','deadbyte-desktop-policy.json');
15
+ const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
16
+ const absent=async p=>{try{await access(p);return false;}catch(e){if(e?.code==='ENOENT')return true;throw e;}};
17
+
18
+ test('R40 real max-runtime full stdio catalog is exactly 80 with four Desktop primitives while authority remains disarmed',async()=>{
19
+ const f=await createR34Fixture({authority:'disarmed'});
20
+ const processPolicyPath=path.join(f.root,'process-policy.json');
21
+ const processGrant=path.join(f.root,'process-grant.json');
22
+ const processState=path.join(f.root,'process-state');
23
+ const hostPolicyPath=path.join(f.root,'host-policy.json');
24
+ const hostArm=path.join(f.root,'host-arm.json');
25
+ const nodeSha=sha(await readFile(process.execPath));
26
+ await mkdir(processState,{recursive:true});
27
+ await writeFile(processPolicyPath,JSON.stringify({
28
+ schema:'deadbyte.process-policy.v1',enabled:true,grant_file:processGrant,state_dir:processState,
29
+ native_host:{path:process.execPath,sha256:nodeSha},
30
+ roots:{core:{path:f.project,deny_paths:[]}},
31
+ profiles:{node:{executable:process.execPath,executable_sha256:nodeSha,root_ids:['core'],
32
+ prefix_args:[],transport:'pipe',max_args:8,max_arg_bytes:1024,max_sessions:2,
33
+ max_input_bytes:65536,max_retained_output_bytes:262144,env_allow:['PATH','TEMP','TMP'],
34
+ input_actions:{ping:'PING\r\n'}}}
35
+ },null,2));
36
+ await writeFile(hostPolicyPath,JSON.stringify({
37
+ schema:'deadbyte.host-policy.v1',enabled:true,arm_file:hostArm,max_read_bytes:262144,max_write_bytes:1048576,
38
+ roots:{core:{path:f.project,read:true,write:true,exec:true}},
39
+ commands:{node_script:{kind:'script',executable:process.execPath,executable_sha256:nodeSha,
40
+ root_ids:['core'],prefix_args:[],extensions:['.mjs'],timeout_ms:5000,max_output_bytes:65536}}
41
+ },null,2));
42
+
43
+ const desktopRaw=JSON.parse(await readFile(desktopPolicyPath,'utf8'));
44
+ const desktopGrant=desktopRaw.grant_file;
45
+ const codingLease=f.codingPolicy.lease_file;
46
+ const autonomousLease=f.policy.lease_file;
47
+ for(const q of [processGrant,hostArm,desktopGrant,codingLease,autonomousLease]) assert.equal(await absent(q),true,'authority unexpectedly armed before start: '+q);
48
+
49
+ const client=new Client({name:'deadbyte-r40-full-catalog',version:'0.12.0'},{versionNegotiation:{mode:{pin:'2026-07-28'}}});
50
+ const env={
51
+ ...getDefaultEnvironment(),
52
+ DEADBYTE_CAPABILITY_PROFILE:'full',
53
+ DEADBYTE_AUDIT_RUNTIME:'0',
54
+ DEADBYTE_STATE_ROOT:path.join(f.root,'state'),
55
+ DEADBYTE_WORKSPACE_ROOT:f.root,
56
+ DEADBYTE_SIGNING_KEY:f.keys.privateKeyPath,
57
+ DEADBYTE_VERIFY_KEY:f.keys.publicKeyPath,
58
+ DEADBYTE_PRIVILEGED_POLICY:hostPolicyPath,
59
+ DEADBYTE_MACHINE_RUNTIME:'1',
60
+ DEADBYTE_AGENT_RUNTIME:'1',
61
+ DEADBYTE_PROCESS_RUNTIME:'1',
62
+ DEADBYTE_PROCESS_POLICY:processPolicyPath,
63
+ DEADBYTE_CODING_RUNTIME:'1',
64
+ DEADBYTE_CODING_POLICY:path.join(f.root,'coding-policy.json'),
65
+ DEADBYTE_MACHINE_FS_RUNTIME:'1',
66
+ DEADBYTE_OBSERVATION_RUNTIME:'1',
67
+ DEADBYTE_DESKTOP_RUNTIME:'1',
68
+ DEADBYTE_DESKTOP_POLICY:desktopPolicyPath,
69
+ DEADBYTE_AUTONOMOUS_RUNTIME:'1',
70
+ DEADBYTE_AUTONOMOUS_POLICY:path.join(f.root,'autonomous-policy.json'),
71
+ DEADBYTE_AUTONOMOUS_SUPERVISOR_MODE:'external'
72
+ };
73
+ const transport=new StdioClientTransport({command:process.execPath,args:[serverPath],cwd:repoRoot,env,stderr:'pipe'});
74
+ try{
75
+ await client.connect(transport);
76
+ const listed=await client.listTools();
77
+ const names=listed.tools.map(t=>t.name).sort();
78
+ const {R40_EXPECTED_TOOLS}=await import('../src/remote-mcp-r40-parity-client.mjs');
79
+ assert.equal(names.length,80,'expected exact full R40 catalog 80, got '+names.length+': '+names.join(','));
80
+ assert.deepEqual(names,R40_EXPECTED_TOOLS);
81
+ for(const name of ['desktop_status','desktop_observe','desktop_target','desktop_action',
82
+ 'host_file_read','host_file_write','host_exec']) assert.ok(names.includes(name),'missing '+name);
83
+ for(const tool of listed.tools) assert.equal(tool.outputSchema?.additionalProperties,false,'non-strict output '+tool.name);
84
+ const catalog_sha256=sha(Buffer.from(JSON.stringify(names),'utf8'));
85
+ console.log(JSON.stringify({tool_count:names.length,catalog_sha256,desktop_tools:4,authority:'DISARMED'}));
86
+ } finally {
87
+ await client.close().catch(()=>{});
88
+ for(const q of [processGrant,hostArm,desktopGrant,codingLease,autonomousLease]) assert.equal(await absent(q),true,'authority file appeared during catalog probe: '+q);
89
+ await f.cleanup();
90
+ }
91
+ });
@@ -12,7 +12,7 @@ import { createAutonomousRuntime } from '../../src/autonomous-runtime.mjs';
12
12
  const sha = bytes => createHash('sha256').update(bytes).digest('hex');
13
13
  const nonce = () => randomBytes(32).toString('hex');
14
14
 
15
- export async function createR34Fixture({authority='armed',withFailingProfile=false,withStatefulProfile=false,codingRuntimeFactory=null,nativeDiffRuntimeFactory=null}={}) {
15
+ export async function createR34Fixture({authority='armed',withFailingProfile=false,withStatefulProfile=false,codingRuntimeFactory=null,nativeDiffRuntimeFactory=null,desktopMemoryProvider=null,desktopRuntime=null}={}) {
16
16
  const root = await mkdtemp(path.join(os.tmpdir(),'deadbyte-r34-e2e-'));
17
17
  const project = path.join(root,'project');
18
18
  const trust = path.join(root,'trust');
@@ -73,8 +73,8 @@ export async function createR34Fixture({authority='armed',withFailingProfile=fal
73
73
  const machineFsRuntime = createMachineFsRuntime({policy:codingPolicy,signingKeyPath:keys.privateKeyPath,verifyKeyPath:keys.publicKeyPath});
74
74
  const baseNativeDiffRuntime = createNativeDiffRuntime({policy,codingRuntime,machineFsRuntime,signingKeyPath:keys.privateKeyPath,verifyKeyPath:keys.publicKeyPath});
75
75
  const nativeDiffRuntime = nativeDiffRuntimeFactory ? nativeDiffRuntimeFactory(baseNativeDiffRuntime) : baseNativeDiffRuntime;
76
- const createRuntime = ({codingRuntimeOverride=codingRuntime,nativeDiffRuntimeOverride=nativeDiffRuntime}={}) => createAutonomousRuntime({policy,codingRuntime:codingRuntimeOverride,nativeDiffRuntime:nativeDiffRuntimeOverride,machineFsRuntime,
77
- signingKeyPath:keys.privateKeyPath,verifyKeyPath:keys.publicKeyPath});
76
+ const createRuntime = ({codingRuntimeOverride=codingRuntime,nativeDiffRuntimeOverride=nativeDiffRuntime,desktopMemoryProviderOverride=desktopMemoryProvider,desktopRuntimeOverride=desktopRuntime}={}) => createAutonomousRuntime({policy,codingRuntime:codingRuntimeOverride,nativeDiffRuntime:nativeDiffRuntimeOverride,machineFsRuntime,
77
+ desktopRuntime:desktopRuntimeOverride,desktopMemoryProvider:desktopMemoryProviderOverride,signingKeyPath:keys.privateKeyPath,verifyKeyPath:keys.publicKeyPath});
78
78
  return {
79
79
  root,project,target,keys,codingPolicy,policy,baseCodingRuntime,codingRuntime,machineFsRuntime,nativeDiffRuntime,createRuntime,runtime:createRuntime(),
80
80
  initial_sha256:sha(await readFile(target)),arm,disarm,
@@ -9,9 +9,9 @@ const readme=()=>readFile(path.join(root,'README.txt'),'utf8');
9
9
 
10
10
  test('production README documents one-command stdio configs for major MCP clients',async()=>{
11
11
  const text=await readme();
12
- assert.match(text,/npx -y deadbyte-mcp@0\.11\.2 mcp/);
12
+ assert.match(text,/npx -y deadbyte-mcp@0\.11\.3 mcp/);
13
13
  assert.match(text,/CLAUDE DESKTOP/);
14
- assert.match(text,/"mcpServers"[\s\S]*?"command"\s*:\s*"npx"[\s\S]*?"-y"[\s\S]*?"deadbyte-mcp@0\.11\.2"[\s\S]*?"mcp"/);
14
+ assert.match(text,/"mcpServers"[\s\S]*?"command"\s*:\s*"npx"[\s\S]*?"-y"[\s\S]*?"deadbyte-mcp@0\.11\.3"[\s\S]*?"mcp"/);
15
15
  assert.match(text,/CURSOR/);
16
16
  assert.match(text,/\.cursor\/mcp\.json/);
17
17
  assert.match(text,/VS CODE/);
@@ -20,7 +20,7 @@ test('production README documents one-command stdio configs for major MCP client
20
20
  assert.match(text,/CODEX/);
21
21
  assert.match(text,/\[mcp_servers\.deadbyte\]/);
22
22
  assert.match(text,/command\s*=\s*"npx"/);
23
- assert.match(text,/args\s*=\s*\["-y",\s*"deadbyte-mcp@0\.11\.2",\s*"mcp"\]/);
23
+ assert.match(text,/args\s*=\s*\["-y",\s*"deadbyte-mcp@0\.11\.3",\s*"mcp"\]/);
24
24
  });
25
25
 
26
26
  test('production README records tracer bullet, semantic scope, remote UX, safety and document extension',async()=>{
@@ -5,7 +5,7 @@ import { mkdtemp, mkdir, readFile, rm, writeFile, readdir } from 'node:fs/promis
5
5
  import os from 'node:os';
6
6
  import path from 'node:path';
7
7
  import { spawn } from 'node:child_process';
8
- import * as parity from '../scripts/release-parity-r38.mjs';
8
+ import * as parity from '../scripts/release-parity-r39.mjs';
9
9
  import { createToolAudit } from '../src/tool-audit.mjs';
10
10
  import { verifyAuditChain } from '../src/audit-verify.mjs';
11
11
  import { generateTrustKeypair } from '../src/trust.mjs';
@@ -86,12 +86,12 @@ test('audit restart reconciles an orphan request with an explicit interrupted re
86
86
  }finally{await rm(stateRoot,{recursive:true,force:true});}
87
87
  });
88
88
 
89
- test('Windows R38 gate emits manifest-bound machine-readable evidence outside the candidate tree', async()=>{
89
+ test('Windows current R40 gate emits manifest-bound machine-readable evidence outside the candidate tree', async()=>{
90
90
  const stateRoot=await temp('deadbyte-r33-windows-evidence-');
91
91
  try{
92
- const gate=await readFile(path.join(root,'scripts','gate-windows-r38.ps1'),'utf8');
93
- assert.match(gate,/windows-gate-evidence-r38\.mjs/,'gate-windows-r38.ps1 must invoke the evidence writer');
94
- const result=await run(process.execPath,[path.join(root,'scripts','windows-gate-evidence-r38.mjs')],{
92
+ const gate=await readFile(path.join(root,'scripts','gate-windows-r40.ps1'),'utf8');
93
+ assert.match(gate,/windows-gate-evidence-r40\.mjs/,'gate-windows-r40.ps1 must invoke the evidence writer');
94
+ const result=await run(process.execPath,[path.join(root,'scripts','windows-gate-evidence-r40.mjs')],{
95
95
  cwd:root,env:{...process.env,DEADBYTE_STATE_ROOT:stateRoot}
96
96
  });
97
97
  assert.equal(result.code,0,result.stderr||result.stdout);
@@ -99,12 +99,12 @@ test('Windows R38 gate emits manifest-bound machine-readable evidence outside th
99
99
  assert.equal(summary.status,'written');
100
100
  const evidence=JSON.parse(await readFile(summary.path,'utf8'));
101
101
  const manifestSha=sha256(await readFile(path.join(root,'MANIFEST.SHA256')));
102
- assert.equal(evidence.schema,'deadbyte.r38-windows-gate.v1');
102
+ assert.equal(evidence.schema,'deadbyte.r40-windows-gate.v1');
103
103
  assert.equal(evidence.status,'passed');
104
104
  assert.equal(evidence.exit_code,0);
105
- assert.equal(evidence.version,'0.11.2');
105
+ assert.equal(evidence.version,'0.12.0');
106
106
  assert.equal(evidence.manifest_sha256,manifestSha);
107
- assert.equal(evidence.marker,'DEADBYTE V0.11.2 / R38 WINDOWS BATCH GATE: PASS');
107
+ assert.equal(evidence.marker,'DEADBYTE V0.12.0 / R40 WINDOWS BATCH GATE: PASS');
108
108
  assert.ok(summary.path.startsWith(path.join(stateRoot,'evidence','release')));
109
109
  }finally{await rm(stateRoot,{recursive:true,force:true});}
110
110
  });
@@ -2,8 +2,8 @@ import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import { readFile } from 'node:fs/promises';
4
4
  import { R34_EXPECTED_TOOLS } from '../src/remote-mcp-r34-parity-client.mjs';
5
- import { validateParityEvidence } from '../scripts/release-parity-r38.mjs';
6
- import { verifyFinalClosureObject } from '../scripts/final-closure-verify-r38.mjs';
5
+ import { validateParityEvidence } from '../scripts/release-parity-r40.mjs';
6
+ import { verifyFinalClosureObject } from '../scripts/final-closure-verify-r40.mjs';
7
7
 
8
8
  const root = new URL('../', import.meta.url);
9
9
  const text = rel => readFile(new URL(rel, root), 'utf8');
@@ -19,28 +19,28 @@ test('R34 public parity catalog is exact, unique, and includes production coding
19
19
 
20
20
  test('release parity and final verifier are package entry points', async () => {
21
21
  const pkg = JSON.parse(await text('package.json'));
22
- assert.equal(pkg.scripts['release:parity'], 'node scripts/release-parity-r38.mjs');
23
- assert.equal(pkg.scripts['release:final:write'], 'node scripts/final-closure-r38.mjs');
24
- assert.equal(pkg.scripts['release:final:verify'], 'node scripts/final-closure-verify-r38.mjs');
22
+ assert.equal(pkg.scripts['release:parity'], 'node scripts/release-parity-r40.mjs');
23
+ assert.equal(pkg.scripts['release:final:write'], 'node scripts/final-closure-r40.mjs');
24
+ assert.equal(pkg.scripts['release:final:verify'], 'node scripts/final-closure-verify-r40.mjs');
25
25
  assert.equal(typeof validateParityEvidence, 'function');
26
26
  assert.equal(typeof verifyFinalClosureObject, 'function');
27
27
  });
28
28
 
29
- test('R38 final closure verifier is implementation-independent from production helpers', async () => {
30
- const verifier = await text('scripts/final-closure-verify-r38.mjs');
31
- const writer = await text('scripts/final-closure-r38.mjs');
29
+ test('R40 final closure verifier is implementation-independent from production helpers', async () => {
30
+ const verifier = await text('scripts/final-closure-verify-r40.mjs');
31
+ const writer = await text('scripts/final-closure-r40.mjs');
32
32
  assert.doesNotMatch(verifier, /from ['"]\.\.\/src\//);
33
33
  assert.match(verifier, /DEADBYTE-R27-SLOT-UPDATE-V1/);
34
34
  assert.match(verifier, /DEADBYTE-MACHINE-PING-V1/);
35
- assert.match(verifier, /DEADBYTE-R38-FINAL-CLOSURE-V1/);
36
- assert.match(writer, /pointer\.version==='0\.11\.2'/);
37
- assert.match(verifier, /envelope\.body\.version==='0\.11\.2'/);
38
- assert.match(verifier, /release_label==='R38 FINAL MACHINE BASELINE'/);
39
- assert.match(verifier, /220fac89dd82cdcdddb82cd7d0b71b768f84a5c87d57ebaca0f5383f33d97a76/);
35
+ assert.match(verifier, /DEADBYTE-R40-FINAL-CLOSURE-V1/);
36
+ assert.match(writer, /pointer\.version==='0\.12\.0'/);
37
+ assert.match(verifier, /envelope\.body\.version==='0\.12\.0'/);
38
+ assert.match(verifier, /release_label==='R40 FINAL MACHINE BASELINE'/);
39
+ assert.match(verifier, /ce761dd6e014d42eddb635855038e0ce049c63c6e3af7e63c3005bbe198bcf7b/);
40
40
  });
41
41
 
42
42
  test('final closure verifier canonicalizes traversal order before exact-tree comparison', async () => {
43
- const verifier = await text('scripts/final-closure-verify-r38.mjs');
43
+ const verifier = await text('scripts/final-closure-verify-r40.mjs');
44
44
  assert.match(verifier, /const actual=\(await walk\(root\)\)\.filter\(rel=>rel!==manifestName\)\.sort\(\(a,b\)=>a\.localeCompare\(b,'en'\)\);/);
45
45
  assert.match(verifier, /const expected=\[\.\.\.entries\.keys\(\)\]\.sort\(\(a,b\)=>a\.localeCompare\(b,'en'\)\);/);
46
46
  });
@@ -24,7 +24,7 @@ test('R37 unified timeline renders one sanitized tool-call line with ISO timesta
24
24
  }
25
25
  };
26
26
  const line=formatRemoteToolCall(event);
27
- assert.match(line,/^2026-09-18T16:24:30\.125Z \| coding_file_write\s+\| Arguments: \{/);
27
+ assert.match(line,/^2026-09-18T23:24:30\.125\+07:00 \| coding_file_write\s+\| Arguments: \{/);
28
28
  assert.match(line,/"root_id":"projects"/);
29
29
  assert.match(line,/"path":"src\/example\.mjs"/);
30
30
  assert.match(line,/"reason":"payload"/);
@@ -32,15 +32,16 @@ test('R37 unified timeline renders one sanitized tool-call line with ISO timesta
32
32
  assert.doesNotMatch(line,/TOP_SECRET_PAYLOAD|TOP_SECRET_TOKEN|Bearer abc\.def\.ghi/);
33
33
  });
34
34
 
35
- test('R37 live tracker uses the tool-call line for request and keeps correlated terminal result',()=>{
35
+ test('R40 default live tracker keeps legacy formatter separate and emits one compact result line',()=>{
36
36
  let now=Date.parse('2026-09-18T16:24:30.125Z');
37
37
  const tracker=createLiveTimelineTracker({clock:()=>now});
38
38
  const call=tracker.observe({event_type:'tool.request',request_id:'abcdef1234567890',tool:'coding_tree',
39
- created_at_utc:'2026-09-18T16:24:30.125Z',args:{root_id:'projects',path:'src'}});
40
- assert.match(call,/^2026-09-18T16:24:30\.125Z \| coding_tree\s+\| Arguments: \{"path":"src","root_id":"projects"\}$/);
39
+ created_at_utc:'2026-09-18T16:24:30.125Z',args:{root_id:'projects',path:'src'}},{sequence:1});
40
+ assert.equal(call,null);
41
41
  now+=250;
42
- assert.equal(tracker.observe({event_type:'tool.result',request_id:'abcdef1234567890',tool:'coding_tree',
43
- outcome:{is_error:false,duration_ms:250}}),'✓ [abcdef12] OK coding_tree 250ms');
42
+ const done=tracker.observe({event_type:'tool.result',request_id:'abcdef1234567890',tool:'coding_tree',
43
+ observed_at_utc:'2026-09-18T16:24:30.375Z',outcome:{is_error:false,duration_ms:250}},{sequence:2});
44
+ assert.match(done,/^🔍 23:24:30\.375 #2 \[abcdef12\] coding_tree projects:src 250ms ✓$/);
44
45
  });
45
46
 
46
47
  test('R37 remote result journal persists sanitized tool-call and result in one monotonic cursor stream',async()=>{