deadbyte-mcp 0.15.25 → 0.15.27

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.
@@ -11,7 +11,7 @@ const POLICY=H('desktop-policy');
11
11
  const WIN={hwnd:'0x1234',pid:77,process_image_sha256:H('desktop-app'),title_sha256:H('desktop-title')};
12
12
 
13
13
  function fakeDesktopRuntime({armed=false,unknown=false}={}){
14
- const calls={status:0,observe:0,ground:0,action:0,verify:0};
14
+ const calls={status:0,observe:0,wait:0,ground:0,action:0,verify:0};
15
15
  const receipts=new Map();
16
16
  let seq=0;
17
17
  const issue=kind=>{
@@ -28,6 +28,9 @@ function fakeDesktopRuntime({armed=false,unknown=false}={}){
28
28
  async status(){calls.status++;return {status:'ok',configured:true,armed,reason:armed?'standing-grant':'disarmed',
29
29
  action_kinds:armed?['click_primary']:[],policy_sha256:POLICY,observer_backend:'fake'};},
30
30
  async observe(){calls.observe++;const r=issue('desktop_observation');return {status:'ok',frame:frame(FRAME),backend:'fake',byte_length:4,...r};},
31
+ async wait({baselineFrameId,until}){calls.wait++;assert.equal(baselineFrameId,FRAME);assert.equal(until,'frame_changed');
32
+ const r=issue('desktop_wait_observation');return {status:'ok',condition:until,satisfied:true,timed_out:false,attempts:2,elapsed_ms:100,
33
+ baseline_frame_id:FRAME,frame:frame(GROUNDED_FRAME),match:null,...r};},
31
34
  async ground({frameId,query}){calls.ground++;assert.equal(frameId,FRAME);assert.equal(query.kind,'root');
32
35
  const r=issue('desktop_grounding');return {status:'ok',frame:frame(GROUNDED_FRAME),
33
36
  target:{target_id:TARGET,frame_id:GROUNDED_FRAME,rect:{left:100,top:100,width:200,height:80},source:'uia'},
@@ -99,6 +102,29 @@ test('T7 read-only Desktop observe works while Desktop mutation authority is DIS
99
102
  }finally{await f.cleanup();}
100
103
  });
101
104
 
105
+ test('successor autonomous Desktop wait replaces fixed sleep and verifies signed observation evidence',async()=>{
106
+ const d=fakeDesktopRuntime({armed:false});
107
+ const f=await createR34Fixture({desktopRuntime:d});
108
+ try{
109
+ const goal=await f.runtime.submit({submissionId:'desktop-bounded-wait',rootId:'project',title:'desktop wait',goal:'wait for visual change',acceptance:'signed bounded wait'});
110
+ let result=await f.runtime.run({goalId:goal.goal_id,maxCycles:2});
111
+ result=await sendPlannerDecision(f.runtime,goal.goal_id,result,plan(['observe','wait']));
112
+ result=await toAct(f,goal,result);
113
+ result=await sendPlannerDecision(f.runtime,goal.goal_id,result,{schema:'deadbyte.autonomous-decision.v2',kind:'act',action:{kind:'desktop_observe'}});
114
+ result=await sendPlannerDecision(f.runtime,goal.goal_id,result,complete('observe','wait-observe-proof'));
115
+ result=await toAct(f,goal,result);
116
+ result=await sendPlannerDecision(f.runtime,goal.goal_id,result,{schema:'deadbyte.autonomous-decision.v2',kind:'act',action:{
117
+ kind:'desktop_wait',baseline_frame_id:FRAME,until:'frame_changed',uia_query:null,timeout_ms:1000,poll_ms:100
118
+ }});
119
+ assert.equal(result.loop.phase,'VERIFYING');
120
+ assert.equal(d.calls.wait,1);assert.equal(d.calls.action,0);assert.equal(d.calls.verify,2);
121
+ const journal=await f.runtime.events({goalId:goal.goal_id,fromSeq:1,limit:200});
122
+ const completed=journal.events.find(e=>e.type==='delegated_action_completed'&&e.payload?.operation?.kind==='desktop_wait');
123
+ assert.equal(completed.payload.capability_id,'desktop.wait');
124
+ assert.equal(completed.payload.evidence.receipts[0].kind,'desktop_wait_observation');
125
+ }finally{await f.cleanup();}
126
+ });
127
+
102
128
  test('T7 Autonomous authority cannot substitute for missing Desktop mutation grant',async()=>{
103
129
  const d=fakeDesktopRuntime({armed:false});
104
130
  const f=await createR34Fixture({desktopRuntime:d});
@@ -1,7 +1,7 @@
1
1
  import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import {
4
- desktopActionInputSchema,desktopControlInputSchema,desktopTargetInputSchema,registerDesktopTools
4
+ desktopActionInputSchema,desktopControlInputSchema,desktopTargetInputSchema,desktopWaitInputSchema,registerDesktopTools
5
5
  } from '../src/desktop-mcp-tools-r40.mjs';
6
6
 
7
7
  const H=c=>c.repeat(64);
@@ -30,11 +30,26 @@ test('R40 T5 target schema supports local UIA query without arbitrary dispatch',
30
30
  assert.equal(desktopControlInputSchema.safeParse({op:'target',frame_id:frame,uia_query:{kind:'control_type',value:'button',max_results:4,ordinal:0}}).success,true);
31
31
  });
32
32
 
33
- test('R40 full desktop surface registers four narrow typed tools',()=>{
33
+ test('successor desktop wait schema is bounded, semantic, and rejects action-shaped fields',()=>{
34
+ assert.equal(desktopWaitInputSchema.safeParse({
35
+ baseline_frame_id:frame,until:'frame_changed',timeout_ms:5000,poll_ms:100,preview:false
36
+ }).success,true);
37
+ assert.equal(desktopWaitInputSchema.safeParse({
38
+ baseline_frame_id:frame,until:'uia_present',uia_query:{kind:'name_exact',value:'Ready',max_results:8,ordinal:0},timeout_ms:5000,poll_ms:100,preview:false
39
+ }).success,true);
40
+ assert.equal(desktopWaitInputSchema.safeParse({
41
+ baseline_frame_id:frame,until:'uia_present',timeout_ms:5000,poll_ms:100,preview:false
42
+ }).success,false);
43
+ assert.equal(desktopControlInputSchema.safeParse({
44
+ op:'wait',baseline_frame_id:frame,until:'frame_changed',timeout_ms:5000,poll_ms:100,preview:false,point:{x:1,y:2}
45
+ }).success,false);
46
+ });
47
+
48
+ test('successor full desktop surface registers bounded semantic wait without mutation authority',()=>{
34
49
  const server=fakeServer();
35
- const runtime={status(){},observe(){},target(){},action(){}};
50
+ const runtime={status(){},observe(){},wait(){},target(){},action(){}};
36
51
  registerDesktopTools(server,{runtime});
37
- assert.deepEqual([...server.tools.keys()].sort(),['desktop_action','desktop_observe','desktop_status','desktop_target']);
52
+ assert.deepEqual([...server.tools.keys()].sort(),['desktop_action','desktop_observe','desktop_status','desktop_target','desktop_wait']);
38
53
  });
39
54
 
40
55
  test('R40 public desktop action output removes raw text while preserving content and action hashes',async()=>{
@@ -19,7 +19,7 @@ function F(at,image=H('same'),window=WIN){
19
19
  bounds:{left:0,top:0,width:1000,height:800},activeWindow:window,imageSha256:image
20
20
  });
21
21
  }
22
- async function fixture({grantActions=['click_primary','text_input'],captureFrames=null,times=null,inputProvider=null,grounderProvider=null}={}){
22
+ async function fixture({grantActions=['click_primary','text_input'],captureFrames=null,times=null,inputProvider=null,grounderProvider=null,clockMs=null,sleeper=null}={}){
23
23
  const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r40-desktop-runtime-'));
24
24
  const grant=path.join(root,'grant.json'),evidence=path.join(root,'evidence');
25
25
  const policy={
@@ -59,7 +59,7 @@ async function fixture({grantActions=['click_primary','text_input'],captureFrame
59
59
  '2026-09-19T02:00:01.000Z'
60
60
  ])];
61
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});
62
+ const runtime=createDesktopRuntime({policy,observerRuntime,inputProvider:provider,grounderProvider,privateKey,keyId:'test-key',evidenceDir:evidence,now,clockMs:clockMs??undefined,sleeper:sleeper??undefined});
63
63
  return {root,grant,evidence,policy,expected,runtime,calls,publicKey};
64
64
  }
65
65
 
@@ -242,6 +242,47 @@ test('read-only observe works independently of desktop mutation grant',async()=>
242
242
  assert.match(observed.receipt_sha256,/^[0-9a-f]{64}$/);
243
243
  });
244
244
 
245
+ test('successor desktop wait observes until a frame changes and publishes signed final evidence',async()=>{
246
+ let tick=0;
247
+ const same={frame:F('2026-09-19T02:00:00.600Z'),backend:'fake',byte_length:4};
248
+ const changed={frame:F('2026-09-19T02:00:00.900Z',H('changed')),backend:'fake',byte_length:4};
249
+ const fx=await fixture({
250
+ captureFrames:[same,changed],clockMs:()=>tick,sleeper:async ms=>{tick+=ms;},
251
+ times:['2026-09-19T02:00:01.000Z']
252
+ });
253
+ await writeFile(fx.grant,'{}');
254
+ const result=await fx.runtime.wait({baselineFrameId:fx.expected.frame_id,until:'frame_changed',timeoutMs:1000,pollMs:100});
255
+ assert.equal(result.satisfied,true);
256
+ assert.equal(result.timed_out,false);
257
+ assert.equal(result.attempts,2);
258
+ assert.equal(result.frame.frame_id,changed.frame.frame_id);
259
+ assert.match(result.receipt_sha256,/^[0-9a-f]{64}$/);
260
+ const receipt=JSON.parse(await readFile(path.join(fx.evidence,`${result.receipt_id}.json`),'utf8'));
261
+ assert.equal(receipt.kind,'desktop_wait_observation');
262
+ assert.equal(receipt.payload.condition,'frame_changed');
263
+ assert.equal(receipt.payload.satisfied,true);
264
+ assert.equal(fx.calls.length,0);
265
+ });
266
+
267
+ test('successor desktop wait uses local UIA matching without leaking query text or dispatching input',async()=>{
268
+ let tick=0,queries=0;
269
+ const first={frame:F('2026-09-19T02:00:00.600Z'),backend:'fake',byte_length:4};
270
+ const second={frame:F('2026-09-19T02:00:00.900Z'),backend:'fake',byte_length:4};
271
+ const grounderProvider=async({query})=>{
272
+ queries++;
273
+ return {status:'ok',query_sha256:H('wait-query'),query_kind:query.kind,ordinal:0,visited:4,truncated:false,
274
+ matches:queries===1?[]:[{rect:{left:1,top:2,width:3,height:4},control_type:50000,enabled:true,offscreen:false}],
275
+ provider_receipt_sha256:H('wait-provider')};
276
+ };
277
+ const fx=await fixture({captureFrames:[first,second],grounderProvider,clockMs:()=>tick,sleeper:async ms=>{tick+=ms;},times:['2026-09-19T02:00:01.000Z']});
278
+ const result=await fx.runtime.wait({baselineFrameId:fx.expected.frame_id,until:'uia_present',query:{kind:'name_exact',value:'SECRET READY',max_results:8,ordinal:0},timeoutMs:1000,pollMs:100});
279
+ assert.equal(result.satisfied,true);
280
+ assert.equal(result.match.actionable,true);
281
+ assert.equal(result.match.query_sha256,H('wait-query'));
282
+ assert.equal(JSON.stringify(result).includes('SECRET READY'),false);
283
+ assert.equal(fx.calls.length,0);
284
+ });
285
+
245
286
 
246
287
  test('desktop runtime enforces policy max_text_bytes before observation or input effect',async()=>{
247
288
  const fx=await fixture({grantActions:['text_input']});
@@ -7,6 +7,7 @@ import { fileURLToPath } from 'node:url';
7
7
  import { Client } from '@modelcontextprotocol/client';
8
8
  import { StdioClientTransport, getDefaultEnvironment } from '@modelcontextprotocol/client/stdio';
9
9
  import { createR34Fixture } from './helpers/autonomous-r34-fixture.mjs';
10
+ import { expectedFullCatalogForEnv } from '../src/runtime-catalog-expectation.mjs';
10
11
 
11
12
  const here=path.dirname(fileURLToPath(import.meta.url));
12
13
  const repoRoot=path.resolve(here,'..');
@@ -15,7 +16,7 @@ const desktopPolicyPath=path.join(repoRoot,'controller','deadbyte-desktop-policy
15
16
  const catalogPath=path.join(repoRoot,'docs','R48-FULL-TOOL-CATALOG.json');
16
17
  const absent=async p=>{try{await access(p);return false;}catch(e){if(e?.code==='ENOENT')return true;throw e;}};
17
18
 
18
- test('R48 runtime full stdio catalog exactly matches canonical registration surface',async()=>{
19
+ test('R49 runtime full stdio catalog exactly matches sealed R48 base plus reviewed overlay',async()=>{
19
20
  const canonical=JSON.parse(await readFile(catalogPath,'utf8'));
20
21
  assert.equal(canonical.schema,'deadbyte.r48-full-catalog.v1');
21
22
  assert.equal(canonical.train,'R48');
@@ -61,15 +62,16 @@ test('R48 runtime full stdio catalog exactly matches canonical registration surf
61
62
  DEADBYTE_AUTONOMOUS_RUNTIME:'1',DEADBYTE_AUTONOMOUS_POLICY:path.join(f.root,'autonomous-policy.json'),
62
63
  DEADBYTE_AUTONOMOUS_SUPERVISOR_MODE:'external'
63
64
  };
65
+ const expected=await expectedFullCatalogForEnv(env);
64
66
  const transport=new StdioClientTransport({command:process.execPath,args:[serverPath],cwd:repoRoot,env,stderr:'pipe'});
65
67
  try{
66
68
  await client.connect(transport);
67
69
  const listed=await client.listTools();
68
70
  const names=listed.tools.map(t=>t.name).sort();
69
- assert.deepEqual(names,canonical.tools);
71
+ assert.deepEqual(names,expected);
70
72
  assert.equal(new Set(names).size,names.length,'runtime duplicate tool names');
71
73
  for(const tool of listed.tools) if(tool.outputSchema!==undefined) assert.equal(tool.outputSchema?.additionalProperties,false,'non-strict output '+tool.name);
72
- for(const name of ['agent_task_submit','autonomous_goal_submit','coding_task_submit','process_session_start','machine_fs_write','machine_search_start','desktop_action','host_exec','native_diff_apply','skill_catalog']) assert.ok(names.includes(name),'missing R48 surface '+name);
74
+ for(const name of ['agent_task_submit','autonomous_goal_submit','coding_task_submit','process_session_start','machine_fs_write','machine_search_start','desktop_wait','desktop_action','host_exec','native_diff_apply','skill_catalog']) assert.ok(names.includes(name),'missing R49 surface '+name);
73
75
  } finally {
74
76
  await client.close().catch(()=>{});
75
77
  for(const q of [processGrant,hostArm,desktopGrant,codingLease,autonomousLease]) assert.equal(await absent(q),true,'authority file appeared during catalog probe: '+q);
@@ -42,3 +42,9 @@ test('publish boundary excludes live state, private keys, grants and non-example
42
42
  const forbidden=files.filter(rel=>rel.startsWith('tmp/')||rel.startsWith('.deadbyte-machine-fs-recovery/')||/(^|\/)(active-release\.json|runtime\/|audit\/|evidence\/)|\.pem$|(^|\/)deadbyte-controller\.config\.psd1$|(^|\/)deadbyte-host-policy\.json$|(^|\/)[^/]*(?:grant|arm)\.json$/i.test(rel));
43
43
  assert.deepEqual(forbidden,[]);
44
44
  });
45
+
46
+ test('publish boundary includes only the canonical top-level Windows launcher',()=>{
47
+ const files=packFiles();
48
+ const launchers=files.filter(rel=>/^DEADBYTE-MCP.*\.cmd$/i.test(rel));
49
+ assert.deepEqual(launchers,['DEADBYTE-MCP.cmd']);
50
+ });
@@ -3,46 +3,55 @@ import assert from 'node:assert/strict';
3
3
  import { readFile } from 'node:fs/promises';
4
4
  import { DEADBYTE_VERSION } from '../src/version.mjs';
5
5
 
6
- const root=new URL('../',import.meta.url);
7
- const read=rel=>readFile(new URL(rel,root),'utf8');
6
+ const root = new URL('../', import.meta.url);
7
+ const read = rel => readFile(new URL(rel, root), 'utf8');
8
8
 
9
- test('R48 0.15.25 successor binds exact active immutable 0.15.24 parent',async()=>{
10
- const [pkg,lock,release,provenance,matrix]=await Promise.all([
9
+ test('R50 0.15.27 successor binds exact published immutable 0.15.26 parent', async () => {
10
+ const [pkg, lock, release, provenance, matrix] = await Promise.all([
11
11
  read('package.json').then(JSON.parse),
12
12
  read('package-lock.json').then(JSON.parse),
13
13
  read('RELEASE.json').then(JSON.parse),
14
14
  read('PROVENANCE.json').then(JSON.parse),
15
15
  read('TEST-MATRIX.json').then(JSON.parse)
16
16
  ]);
17
- assert.equal(pkg.version,'0.15.25');
18
- assert.equal(lock.version,'0.15.25');
19
- assert.equal(lock.packages[''].version,'0.15.25');
20
- assert.equal(DEADBYTE_VERSION,'0.15.25');
21
- assert.equal(release.version,'0.15.25');
22
- assert.equal(provenance.version,'0.15.25');
23
- assert.equal(matrix.version,'0.15.25');
24
- assert.equal(release.train,'R48');
25
- assert.equal(release.label,'COMMANDER DIFFERENTIAL + PROTOCOL HARDENING BASELINE');
26
- assert.equal(release.parent.release_id,'v0.15.24-c33fcbc449562285');
27
- assert.equal(release.parent.manifest_sha256,'c33fcbc449562285b4a03e95a6d282d359859f266773043b34db35723dfad54e');
28
- assert.equal(release.parent.generation_manifest_sha256,'6b81c4a5b940a6ef525b7d0ce8e7ff5e6b9fc9b8048d9522ea8852fa29b85395');
29
- assert.equal(release.source_predecessor.version,'0.15.24');
30
- assert.equal(release.source_predecessor.tarball_sha256,'23ea53fb4f331873c742c810f815d5ad18291f74c1bda1fd1d8c08475dbbd4ad');
31
- assert.equal(release.source_predecessor.manifest_file_sha256,'c33fcbc449562285b4a03e95a6d282d359859f266773043b34db35723dfad54e');
32
- assert.equal(release.source_predecessor.reference_server_sha256,'dfc303bb7dd2e8d01debac50fc43bb8644d00089bffdf2887e149497cff8b305');
33
- assert.equal(release.source_predecessor.reference_schemas_sha256,'f342345e34e48769dabaefe1b932f09d41e2e207b422f7794a15ee50ffa8f140');
34
- assert.equal(release.capabilities.full_tool_count,116);
35
- assert.equal(release.capabilities.commander_incremental_pdf_revisions,true);
36
- assert.equal(release.capabilities.commander_docx_header_footer_search,true);
37
- assert.equal(release.capabilities.commander_directory_read_fallback,true);
38
- assert.equal(release.capabilities.commander_binary_detection,true);
39
- assert.equal(release.capabilities.commander_protocol_adversarial,true);
40
- assert.equal(release.capabilities.atomic_mutation_unknown_effect,true);
41
- assert.equal(provenance.parent_release_id,release.parent.release_id);
42
- assert.equal(provenance.parent_manifest_sha256,release.parent.manifest_sha256);
43
- assert.equal(provenance.parent_generation_manifest_sha256,release.parent.generation_manifest_sha256);
44
- assert.equal(provenance.source_predecessor_tarball_sha256,release.source_predecessor.tarball_sha256);
45
- assert.equal(matrix.full_regression_partition_proof.files,211);
46
- assert.equal(matrix.full_regression_partition_proof.fail,0);
47
- assert.equal(matrix.full_regression_partition_proof.task_receipt_sha256,'7711039e4807f6c2af02bbda897d0032b067e0a6631f789fd3bf801258160d3f');
17
+
18
+ for (const value of [
19
+ pkg.version,
20
+ lock.version,
21
+ lock.packages[''].version,
22
+ DEADBYTE_VERSION,
23
+ release.version,
24
+ provenance.version,
25
+ matrix.version
26
+ ]) assert.equal(value, '0.15.27');
27
+
28
+ assert.equal(release.train, 'R50');
29
+ assert.equal(release.label, 'PUBLIC PACKAGE BOUNDARY HOTFIX');
30
+ assert.equal(release.parent.release_id, 'v0.15.26-669ea65d2307ee2c');
31
+ assert.equal(release.parent.manifest_sha256, '669ea65d2307ee2cce06be960e0a8c7243dc6135f7f129a88d99f53096433cc8');
32
+ assert.equal(release.parent.generation_manifest_sha256, '08364adaf1dab9730c314e29121632c6371ed76fc677e83cb7f6aa6b244eab94');
33
+
34
+ assert.equal(release.source_predecessor.version, '0.15.26');
35
+ assert.equal(release.source_predecessor.tarball_sha256, '3272679e3a18610d47e83dc8d3161e949d75a57da145a43c2ab50c865a83bb86');
36
+ assert.equal(release.source_predecessor.manifest_file_sha256, '669ea65d2307ee2cce06be960e0a8c7243dc6135f7f129a88d99f53096433cc8');
37
+ assert.equal(release.source_predecessor.reference_server_sha256, 'dfc303bb7dd2e8d01debac50fc43bb8644d00089bffdf2887e149497cff8b305');
38
+ assert.equal(release.source_predecessor.reference_schemas_sha256, 'f342345e34e48769dabaefe1b932f09d41e2e207b422f7794a15ee50ffa8f140');
39
+
40
+ assert.equal(release.capabilities.full_tool_count, 117);
41
+ assert.equal(release.capabilities.desktop_bounded_semantic_wait, true);
42
+ assert.equal(release.capabilities.commander_incremental_pdf_revisions, true);
43
+ assert.equal(release.capabilities.commander_docx_header_footer_search, true);
44
+ assert.equal(release.capabilities.commander_directory_read_fallback, true);
45
+ assert.equal(release.capabilities.commander_binary_detection, true);
46
+ assert.equal(release.capabilities.commander_protocol_adversarial, true);
47
+ assert.equal(release.capabilities.atomic_mutation_unknown_effect, true);
48
+
49
+ assert.equal(provenance.parent_release_id, release.parent.release_id);
50
+ assert.equal(provenance.parent_manifest_sha256, release.parent.manifest_sha256);
51
+ assert.equal(provenance.parent_generation_manifest_sha256, release.parent.generation_manifest_sha256);
52
+ assert.equal(provenance.source_predecessor_tarball_sha256, release.source_predecessor.tarball_sha256);
53
+
54
+ assert.equal(matrix.train, 'R50');
55
+ assert.equal(matrix.predecessor_r48_full_regression_partition_proof.files, 211);
56
+ assert.equal(matrix.predecessor_r48_full_regression_partition_proof.not_valid_as_r50_proof, true);
48
57
  });
@@ -0,0 +1,24 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { readFile } from 'node:fs/promises';
4
+
5
+ const artifact=new URL('../docs/R49-REMOTE-CONTROL-DONORS.json',import.meta.url);
6
+
7
+ test('R49 remote-control donor evidence pins all requested sources and records bounded native adoption',async()=>{
8
+ const value=JSON.parse(await readFile(artifact,'utf8'));
9
+ assert.equal(value.schema,'deadbyte.r49-remote-control-donors.v1');
10
+ assert.equal(value.donors.length,6);
11
+ assert.deepEqual(value.donors.map(item=>item.repository),[
12
+ 'https://github.com/shahidx0x/better-remote-commander',
13
+ 'https://github.com/Jennifer9911/open-remote-mcp',
14
+ 'https://github.com/Razewang/secure-host-mcp',
15
+ 'https://github.com/dddabtc/winremote-mcp',
16
+ 'https://github.com/getremcp/remcp',
17
+ 'https://github.com/trycua/cua'
18
+ ]);
19
+ for(const donor of value.donors)assert.match(donor.commit,/^[0-9a-f]{40}$/);
20
+ assert.equal(value.adopted_checkpoint.capability,'desktop.wait');
21
+ assert.equal(value.adopted_checkpoint.authority,'none');
22
+ assert.ok(value.adopted_checkpoint.properties.includes('no input dispatch and no action retry'));
23
+ assert.ok(value.explicit_non_adoptions.includes('generic shell or caller-selected executable authority'));
24
+ });
@@ -0,0 +1,36 @@
1
+ import assert from 'node:assert/strict';
2
+ import { readFile } from 'node:fs/promises';
3
+ import test from 'node:test';
4
+
5
+ const read = path => readFile(new URL(`../${path}`, import.meta.url), 'utf8');
6
+
7
+ test('R50 canonical Windows gate is successor-bound and preserves R49/R48 historical gates', async () => {
8
+ const [pkgText, gate, evidence, historicalR49, historicalR48, deferred] = await Promise.all([
9
+ read('package.json'),
10
+ read('scripts/gate-windows-r50.ps1'),
11
+ read('scripts/windows-gate-evidence-r50.mjs'),
12
+ read('scripts/gate-windows-r49.ps1'),
13
+ read('scripts/gate-windows-r48.ps1'),
14
+ read('scripts/deferred-slot-operation-r46.mjs')
15
+ ]);
16
+ const pkg = JSON.parse(pkgText);
17
+ assert.match(pkg.scripts['gate:windows'], /gate-windows-r50\.ps1$/);
18
+ assert.match(gate, /DEADBYTE 0\.15\.27 \/ R50 WINDOWS GATE: PASS/);
19
+ assert.match(gate, /r50-package-boundary/);
20
+ assert.match(gate, /r49-remote-control-donors\.test\.mjs/);
21
+ assert.match(gate, /desktop-runtime-r40\.test\.mjs/);
22
+ assert.match(gate, /manifest-final-verify/);
23
+ assert.match(evidence, /deadbyte\.r50-windows-gate\.v1/);
24
+ assert.match(evidence, /pkg\.version === '0\.15\.27'/);
25
+ assert.match(evidence, /release\.train === 'R50'/);
26
+ assert.match(historicalR49, /DEADBYTE 0\.15\.26 \/ R49 WINDOWS GATE: PASS/);
27
+ assert.match(historicalR48, /DEADBYTE 0\.15\.25 \/ R48 WINDOWS GATE: PASS/);
28
+ assert.match(deferred, /const expectedVersion=packageIdentity\.version/);
29
+ assert.match(deferred, /'--expected-version',expectedVersion/);
30
+ assert.match(deferred, /async function awaitHandoffCompletion/);
31
+ assert.match(deferred, /verifySlotUpdateEnvelope\(envelope,publicKey\)/);
32
+ assert.match(deferred, /active pointer does not match signed activation receipt/);
33
+ assert.match(deferred, /failure-receipt\.json/);
34
+ assert.match(deferred, /await awaitHandoffCompletion\(await runSlotUpdateCli/);
35
+ assert.doesNotMatch(deferred, /'--expected-version','0\.15\.5'/);
36
+ });
@@ -32,6 +32,15 @@ test('R29 remote gate accepts machine plane as an exact optional catalog dimensi
32
32
  assert.match(source, /if \(machine\) items\.push\(\.\.\.machineTools\)/);
33
33
  assert.match(source, /machine_runtime: machineRuntime/);
34
34
  });
35
+
36
+ test('R49 compact remote gate independently verifies signed machine ping', async () => {
37
+ const source = await readFile(sourcePath, 'utf8');
38
+ assert.match(source, /verifyMachinePingPublic/);
39
+ assert.match(source, /public_key_spki_base64/);
40
+ assert.match(source, /machine ping public Ed25519 verification failed/);
41
+ assert.match(source, /ping_signature_valid: true/);
42
+ assert.doesNotMatch(source, /ping_signature_valid: ping\.signature_valid === true/);
43
+ });
35
44
  test('R46 remote gate accepts seven-tool process supervision as one exact optional catalog dimension', async () => {
36
45
  const source = await readFile(sourcePath, 'utf8');
37
46
  assert.match(source, /const processTools = \[/);