deadbyte-mcp 0.11.1 → 0.11.3

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 (37) hide show
  1. package/MANIFEST.SHA256 +36 -20
  2. package/README.txt +7 -7
  3. package/controller/README.TXT +1 -1
  4. package/controller/deadbyte-controller.ps1 +4 -4
  5. package/docs/ARCHITECTURE.md +1 -1
  6. package/package.json +6 -6
  7. package/scripts/deferred-slot-operation-r38.mjs +124 -0
  8. package/scripts/deferred-slot-operation-r39.mjs +124 -0
  9. package/scripts/final-closure-r38.mjs +113 -0
  10. package/scripts/final-closure-r39.mjs +113 -0
  11. package/scripts/final-closure-verify-r38.mjs +208 -0
  12. package/scripts/final-closure-verify-r39.mjs +208 -0
  13. package/scripts/gate-windows-r38.ps1 +42 -0
  14. package/scripts/gate-windows-r39.ps1 +42 -0
  15. package/scripts/release-parity-r38.mjs +200 -0
  16. package/scripts/release-parity-r39.mjs +200 -0
  17. package/scripts/release-parity-tests-r38.ps1 +9 -0
  18. package/scripts/release-parity-tests-r39.ps1 +9 -0
  19. package/scripts/windows-gate-evidence-r38.mjs +52 -0
  20. package/scripts/windows-gate-evidence-r39.mjs +52 -0
  21. package/src/deadbyte-cli.mjs +7 -3
  22. package/src/release-generation.mjs +18 -1
  23. package/src/remote-live-log.mjs +9 -2
  24. package/src/version.mjs +1 -1
  25. package/test/cli-entrypoint.test.mjs +1 -1
  26. package/test/controller.test.mjs +11 -0
  27. package/test/core.test.mjs +1 -1
  28. package/test/production-docs.test.mjs +3 -3
  29. package/test/r33-closeout-regression.test.mjs +8 -8
  30. package/test/r33-finalization.test.mjs +14 -14
  31. package/test/r37-remote-tool-call-timeline.test.mjs +2 -2
  32. package/test/r38-finalization.test.mjs +74 -0
  33. package/test/r39-finalization.test.mjs +74 -0
  34. package/test/release-generation.test.mjs +13 -3
  35. package/test/release-version.test.mjs +47 -25
  36. package/test/remote-live-log-r37.test.mjs +1 -1
  37. package/test/remote-session-cli.test.mjs +46 -12
@@ -0,0 +1,74 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { readFile } from 'node:fs/promises';
4
+ import { validateParityEvidence, R38_PREDECESSOR_RELEASE_ID, R38_PREDECESSOR_MANIFEST } from '../scripts/release-parity-r38.mjs';
5
+ import { verifyFinalClosureObject } from '../scripts/final-closure-verify-r38.mjs';
6
+
7
+ const root=new URL('../',import.meta.url);
8
+ const text=rel=>readFile(new URL(rel,root),'utf8');
9
+
10
+ function parityFixture(){
11
+ const manifest='a'.repeat(64);
12
+ return {
13
+ schema:'deadbyte.r38-parity.v1',status:'passed',execution_provider:'deadbyte_mcp',rdc_operation_count:0,
14
+ candidate:{release_id:`v0.11.2-${manifest.slice(0,16)}`,version:'0.11.2',manifest_sha256:manifest},
15
+ immutable_slot:{protected:true,release_root:'C:/immutable/r38',development_root:'D:/Projects/deadbyte-mcp-r36-dev'},
16
+ local_full:{status:'passed',tool_count:76,strict_output_schemas:true},
17
+ public_compact:{status:'passed',tool_count:41,capability_closure:true,gateway_count:5},
18
+ autonomous:{status:'passed',signed_release_verified:true,observed_failure_before_replan:true},
19
+ before_rollback_disarmed:{status:'passed',capability_closure:true,coding_armed:false,autonomous_armed:false},
20
+ rollback:{state:'completed'},stage_restore:{status:'restored',manifest_sha256:manifest},restore:{state:'completed'},
21
+ predecessor:{release_id:R38_PREDECESSOR_RELEASE_ID,version:'0.11.1',manifest_sha256:R38_PREDECESSOR_MANIFEST},
22
+ predecessor_disarmed:{status:'passed',tool_count:41,capability_closure:true},
23
+ successor:{release_id:`v0.11.2-${manifest.slice(0,16)}`,version:'0.11.2',manifest_sha256:manifest},
24
+ successor_disarmed:{status:'passed',capability_closure:true,coding_armed:false,autonomous_armed:false},
25
+ requirements:Object.fromEntries(['tree_read','precondition_mutation','search','owned_process','observation','coding_loop','autonomy','interrupted_recovery','evidence_verification','compact_closure','full_surface'].map(key=>[key,true]))
26
+ };
27
+ }
28
+
29
+ test('R38 parity validator requires full-76, compact closure, exact public 0.11.1 predecessor and immutable-slot separation',()=>{
30
+ const good=parityFixture();
31
+ assert.equal(validateParityEvidence(good),true);
32
+ assert.throws(()=>validateParityEvidence({...good,local_full:{...good.local_full,tool_count:75}}),/full 76/i);
33
+ assert.throws(()=>validateParityEvidence({...good,public_compact:{...good.public_compact,capability_closure:false}}),/compact closure/i);
34
+ assert.throws(()=>validateParityEvidence({...good,predecessor:{...good.predecessor,manifest_sha256:'b'.repeat(64)}}),/predecessor/i);
35
+ assert.throws(()=>validateParityEvidence({...good,immutable_slot:{...good.immutable_slot,development_root:good.immutable_slot.release_root}}),/immutable-slot/i);
36
+ assert.throws(()=>validateParityEvidence({...good,stage_restore:{status:'missing',manifest_sha256:good.candidate.manifest_sha256}}),/stage restore/i);
37
+ });
38
+
39
+ test('R38 parity captures R38 bridge, exact public 0.11.1 predecessor, stage reseed and successor restore',async()=>{
40
+ const parity=await text('scripts/release-parity-r38.mjs');
41
+ assert.match(parity,/R38_PREDECESSOR_RELEASE_ID='v0\.11\.1-220fac89dd82cdcd'/);
42
+ assert.match(parity,/220fac89dd82cdcdddb82cd7d0b71b768f84a5c87d57ebaca0f5383f33d97a76/);
43
+ assert.match(parity,/const stageRestore=await restoreFrozenStage/);
44
+ assert.match(parity,/publicR38Disarmed/);
45
+ assert.match(parity,/scheduleDeferred\('activate',candidateManifest,\{bridgeRoot:successorBridge\.root,bridgeScriptSha256:successorBridge\.sha256\}\)/);
46
+ });
47
+
48
+ test('R38 current final closure writer and independent verifier bind R38 domains and public 0.11.1 predecessor',async()=>{
49
+ const [writer,verifier]=await Promise.all([text('scripts/final-closure-r38.mjs'),text('scripts/final-closure-verify-r38.mjs')]);
50
+ assert.equal(typeof verifyFinalClosureObject,'function');
51
+ assert.match(writer,/DEADBYTE-R38-FINAL-CLOSURE-V1/);
52
+ assert.match(writer,/deadbyte\.r38-final-closure\.v1/);
53
+ assert.match(writer,/pointer\.version==='0\.11\.2'/);
54
+ assert.match(writer,/R38 FINAL MACHINE BASELINE/);
55
+ assert.match(writer,/deadbyte\.r38-parity\.v1/);
56
+ assert.match(writer,/deadbyte\.r38-windows-gate\.v1/);
57
+ assert.match(writer,/R38_PREDECESSOR_RELEASE_ID/);
58
+ assert.doesNotMatch(verifier,/from ['"]\.\.\/src\//);
59
+ assert.match(verifier,/DEADBYTE-R38-FINAL-CLOSURE-V1/);
60
+ assert.match(verifier,/deadbyte\.r38-final-closure\.v1/);
61
+ assert.match(verifier,/envelope\.body\.version==='0\.11\.2'/);
62
+ assert.match(verifier,/R38 FINAL MACHINE BASELINE/);
63
+ assert.match(verifier,/deadbyte\.r38-parity\.v1/);
64
+ assert.match(verifier,/deadbyte\.r38-windows-gate\.v1/);
65
+ assert.match(verifier,/220fac89dd82cdcdddb82cd7d0b71b768f84a5c87d57ebaca0f5383f33d97a76/);
66
+ });
67
+
68
+ test('R38 bounded public parity suite covers current release identity and agent fabric',async()=>{
69
+ const script=await text('scripts/release-parity-tests-r38.ps1');
70
+ assert.match(script,/r38-finalization\.test\.mjs/);
71
+ assert.match(script,/release-version\.test\.mjs/);
72
+ assert.match(script,/r37-agent-fabric\.test\.mjs/);
73
+ assert.match(script,/remote-live-log-r37\.test\.mjs/);
74
+ });
@@ -0,0 +1,74 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { readFile } from 'node:fs/promises';
4
+ import { validateParityEvidence, R39_PREDECESSOR_RELEASE_ID, R39_PREDECESSOR_MANIFEST } from '../scripts/release-parity-r39.mjs';
5
+ import { verifyFinalClosureObject } from '../scripts/final-closure-verify-r39.mjs';
6
+
7
+ const root=new URL('../',import.meta.url);
8
+ const text=rel=>readFile(new URL(rel,root),'utf8');
9
+
10
+ function parityFixture(){
11
+ const manifest='a'.repeat(64);
12
+ return {
13
+ schema:'deadbyte.r39-parity.v1',status:'passed',execution_provider:'deadbyte_mcp',rdc_operation_count:0,
14
+ candidate:{release_id:`v0.11.3-${manifest.slice(0,16)}`,version:'0.11.3',manifest_sha256:manifest},
15
+ immutable_slot:{protected:true,release_root:'C:/immutable/r39',development_root:'D:/Projects/deadbyte-mcp-r36-dev'},
16
+ local_full:{status:'passed',tool_count:76,strict_output_schemas:true},
17
+ public_compact:{status:'passed',tool_count:41,capability_closure:true,gateway_count:5},
18
+ autonomous:{status:'passed',signed_release_verified:true,observed_failure_before_replan:true},
19
+ before_rollback_disarmed:{status:'passed',capability_closure:true,coding_armed:false,autonomous_armed:false},
20
+ rollback:{state:'completed'},stage_restore:{status:'restored',manifest_sha256:manifest},restore:{state:'completed'},
21
+ predecessor:{release_id:R39_PREDECESSOR_RELEASE_ID,version:'0.11.2',manifest_sha256:R39_PREDECESSOR_MANIFEST},
22
+ predecessor_disarmed:{status:'passed',tool_count:41,capability_closure:true},
23
+ successor:{release_id:`v0.11.3-${manifest.slice(0,16)}`,version:'0.11.3',manifest_sha256:manifest},
24
+ successor_disarmed:{status:'passed',capability_closure:true,coding_armed:false,autonomous_armed:false},
25
+ requirements:Object.fromEntries(['tree_read','precondition_mutation','search','owned_process','observation','coding_loop','autonomy','interrupted_recovery','evidence_verification','compact_closure','full_surface'].map(key=>[key,true]))
26
+ };
27
+ }
28
+
29
+ test('R39 parity validator requires full-76, compact closure, exact public 0.11.2 predecessor and immutable-slot separation',()=>{
30
+ const good=parityFixture();
31
+ assert.equal(validateParityEvidence(good),true);
32
+ assert.throws(()=>validateParityEvidence({...good,local_full:{...good.local_full,tool_count:75}}),/full 76/i);
33
+ assert.throws(()=>validateParityEvidence({...good,public_compact:{...good.public_compact,capability_closure:false}}),/compact closure/i);
34
+ assert.throws(()=>validateParityEvidence({...good,predecessor:{...good.predecessor,manifest_sha256:'b'.repeat(64)}}),/predecessor/i);
35
+ assert.throws(()=>validateParityEvidence({...good,immutable_slot:{...good.immutable_slot,development_root:good.immutable_slot.release_root}}),/immutable-slot/i);
36
+ assert.throws(()=>validateParityEvidence({...good,stage_restore:{status:'missing',manifest_sha256:good.candidate.manifest_sha256}}),/stage restore/i);
37
+ });
38
+
39
+ test('R39 parity captures R39 bridge, exact public 0.11.2 predecessor, stage reseed and successor restore',async()=>{
40
+ const parity=await text('scripts/release-parity-r39.mjs');
41
+ assert.match(parity,/R39_PREDECESSOR_RELEASE_ID='v0\.11\.2-058605dfccaa3035'/);
42
+ assert.match(parity,/058605dfccaa3035a57c6393d53f2421c14e5a92bd145c2334477ba24d7cab8b/);
43
+ assert.match(parity,/const stageRestore=await restoreFrozenStage/);
44
+ assert.match(parity,/publicR39Disarmed/);
45
+ assert.match(parity,/scheduleDeferred\('activate',candidateManifest,\{bridgeRoot:successorBridge\.root,bridgeScriptSha256:successorBridge\.sha256\}\)/);
46
+ });
47
+
48
+ test('R39 current final closure writer and independent verifier bind R39 domains and public 0.11.2 predecessor',async()=>{
49
+ const [writer,verifier]=await Promise.all([text('scripts/final-closure-r39.mjs'),text('scripts/final-closure-verify-r39.mjs')]);
50
+ assert.equal(typeof verifyFinalClosureObject,'function');
51
+ assert.match(writer,/DEADBYTE-R39-FINAL-CLOSURE-V1/);
52
+ assert.match(writer,/deadbyte\.r39-final-closure\.v1/);
53
+ assert.match(writer,/pointer\.version==='0\.11\.3'/);
54
+ assert.match(writer,/R39 FINAL MACHINE BASELINE/);
55
+ assert.match(writer,/deadbyte\.r39-parity\.v1/);
56
+ assert.match(writer,/deadbyte\.r39-windows-gate\.v1/);
57
+ assert.match(writer,/R39_PREDECESSOR_RELEASE_ID/);
58
+ assert.doesNotMatch(verifier,/from ['"]\.\.\/src\//);
59
+ assert.match(verifier,/DEADBYTE-R39-FINAL-CLOSURE-V1/);
60
+ assert.match(verifier,/deadbyte\.r39-final-closure\.v1/);
61
+ assert.match(verifier,/envelope\.body\.version==='0\.11\.3'/);
62
+ assert.match(verifier,/R39 FINAL MACHINE BASELINE/);
63
+ assert.match(verifier,/deadbyte\.r39-parity\.v1/);
64
+ assert.match(verifier,/deadbyte\.r39-windows-gate\.v1/);
65
+ assert.match(verifier,/058605dfccaa3035a57c6393d53f2421c14e5a92bd145c2334477ba24d7cab8b/);
66
+ });
67
+
68
+ test('R39 bounded public parity suite covers current release identity and agent fabric',async()=>{
69
+ const script=await text('scripts/release-parity-tests-r39.ps1');
70
+ assert.match(script,/r39-finalization\.test\.mjs/);
71
+ assert.match(script,/release-version\.test\.mjs/);
72
+ assert.match(script,/r37-agent-fabric\.test\.mjs/);
73
+ assert.match(script,/remote-live-log-r37\.test\.mjs/);
74
+ });
@@ -30,16 +30,23 @@ test('R27 generation bundle rebinds authority and mutable state outside the rele
30
30
  ]},
31
31
  LocalReadyUri:'http://127.0.0.1:8787/healthz',UrlRegex:'https://x',McpUrlFile:'C:/mcp-url.txt',McpUrlFileSha256:EXE,McpPathFile:'C:/token.txt',StartTimeoutSeconds:30,ProbeTimeoutSeconds:3};
32
32
  const coding={schema:'deadbyte.coding-policy.v1',enabled:true,lease_file:'C:/old/coding.json',evidence_dir:'C:/old/evidence',
33
- roots:{core:{path:'C:/old/core',read:true,write:true,exec:true,deny_paths:['node_modules']}},commands:{tests:command()},max_read_bytes:524288,max_write_bytes:2097152};
33
+ roots:{core:{path:'C:/old/core',read:true,write:true,exec:true,deny_paths:['node_modules']}},commands:{tests:command(),powershell_script:command()},max_read_bytes:524288,max_write_bytes:2097152};
34
34
  const autonomous={schema:'deadbyte.autonomous-policy.v1',enabled:true,lease_file:'C:/old/auto.json',evidence_dir:'C:/old/auto-evidence',coding_policy_sha256:'0'.repeat(64),root_ids:['core'],planner:{backend:'client_sampling',max_tokens:4096},
35
- profiles:{gate:{kind:'command',root_id:'core',command_id:'tests',script_path:'scripts/gate.ps1',script_sha256:'0'.repeat(64),args:[],cwd:'.',timeout_ms:120000,expect_exit_code:0,required_for_release:true,run_after_mutation:true,description:'gate'}},
35
+ profiles:{
36
+ gate:{kind:'command',root_id:'core',command_id:'tests',script_path:'scripts/gate.ps1',script_sha256:'0'.repeat(64),args:[],cwd:'.',timeout_ms:120000,expect_exit_code:0,required_for_release:true,run_after_mutation:true,description:'gate'},
37
+ 'windows-release':{kind:'command',root_id:'core',command_id:'powershell_script',script_path:'scripts/gate-windows-old.ps1',script_sha256:'0'.repeat(64),args:[],cwd:'.',timeout_ms:300000,expect_exit_code:0,required_for_release:true,run_after_mutation:false,description:'historical Windows release gate'}
38
+ },
36
39
  limits:{max_iterations:12,max_mutations:24,max_wall_ms:1800000,max_context_bytes:1048576,max_diff_bytes:1048576,max_files_per_diff:8}};
37
40
  const host={schema:'deadbyte.host-policy.v1',enabled:true,arm_file:'C:/old/host.json',roots:{core:{path:'C:/old/core',read:true,write:true,exec:true}},commands:{tests:command()},max_read_bytes:262144,max_write_bytes:1048576};
38
41
  const processPolicy={schema:'deadbyte.process-policy.v1',enabled:true,grant_file:'C:/old/process-grant.json',state_dir:'C:/old/process-state',
39
42
  native_host:{path:'C:/old/deadbyte-process-host.exe',sha256:'0'.repeat(64)},
40
43
  roots:{core:{path:'C:/old/core',deny_paths:['node_modules']}},
41
44
  profiles:{probe:{executable:'C:/Windows/System32/ping.exe',executable_sha256:EXE,root_ids:['core'],prefix_args:['127.0.0.1','-n','2'],max_args:0,max_arg_bytes:256,max_sessions:1,max_input_bytes:4096,max_retained_output_bytes:65536,env_allow:['PATH','TEMP','TMP'],input_actions:{}}}};
42
- const development=path.join(base,'development'); await mkdir(development,{recursive:true}); await mkdir(path.join(development,'scripts'),{recursive:true}); await writeFile(path.join(development,'scripts','gate.ps1'),'Write-Output gate\n');
45
+ const development=path.join(base,'development'); await mkdir(development,{recursive:true}); await mkdir(path.join(development,'scripts'),{recursive:true});
46
+ await writeFile(path.join(development,'scripts','gate.ps1'),'Write-Output gate\n');
47
+ await writeFile(path.join(development,'scripts','gate-windows-old.ps1'),'Write-Output old-gate\n');
48
+ await writeFile(path.join(development,'scripts','gate-windows-current.ps1'),'Write-Output current-gate\n');
49
+ await writeFile(path.join(development,'package.json'),JSON.stringify({scripts:{'gate:windows':'powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-current.ps1'}}));
43
50
  const result=await createGenerationBundle({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy});
44
51
  const verified=await verifyGenerationBundle(result.generation_root,result.generation_manifest_sha256);
45
52
  assert.equal(verified.files,6);
@@ -62,6 +69,9 @@ test('R27 generation bundle rebinds authority and mutable state outside the rele
62
69
  assert.equal(generatedAuto.coding_policy_sha256,sha(codingBytes));
63
70
  assert.equal(generatedAuto.lease_file,path.join(path.resolve(state),'runtime','autonomous-grant.json'));
64
71
  assert.equal(generatedAuto.profiles.gate.script_sha256,sha(Buffer.from('Write-Output gate\n')));
72
+ assert.equal(generatedAuto.profiles['windows-release'].script_path,'scripts/gate-windows-current.ps1');
73
+ assert.equal(generatedAuto.profiles['windows-release'].script_sha256,sha(Buffer.from('Write-Output current-gate\n')));
74
+ assert.equal(generatedAuto.profiles['windows-release'].description,'Full Windows target release gate; runs only when finish is requested.');
65
75
  const generatedHost=JSON.parse(await readFile(result.host_policy_path,'utf8'));
66
76
  assert.equal(generatedHost.roots.core.path,path.resolve(development));
67
77
  assert.notEqual(generatedHost.roots.core.path,path.resolve(release));
@@ -5,40 +5,62 @@ import { createHash } from 'node:crypto';
5
5
 
6
6
  const root=new URL('../',import.meta.url);
7
7
  const text=rel=>readFile(new URL(rel,root),'utf8');
8
- const R37_PREDECESSOR_RELEASE_ID='v0.11.0-08c2a0008b1f84c9';
9
- const R37_PREDECESSOR_MANIFEST='08c2a0008b1f84c90f7ce7faa1e3decbd03f33612bc0fdc7d1ba591b548798e8';
8
+ const R39_PREDECESSOR_RELEASE_ID='v0.11.2-058605dfccaa3035';
9
+ const R39_PREDECESSOR_MANIFEST='058605dfccaa3035a57c6393d53f2421c14e5a92bd145c2334477ba24d7cab8b';
10
10
 
11
- test('R37 patch release authority agrees on V0.11.1 and preserves exact public 0.11.0 predecessor',async()=>{
11
+ test('R39 hotfix authority agrees on V0.11.3 and preserves exact public 0.11.2 predecessor',async()=>{
12
12
  const pkg=JSON.parse(await text('package.json'));
13
13
  const [version,controller,gate,readme,architecture,controllerReadme,deferred,parity,closure,closureVerify,windowsGate,semanticConfig]=await Promise.all([
14
- text('src/version.mjs'),text('controller/deadbyte-controller.ps1'),text('scripts/gate-windows.ps1'),
14
+ text('src/version.mjs'),text('controller/deadbyte-controller.ps1'),text('scripts/gate-windows-r39.ps1'),
15
15
  text('README.txt'),text('docs/ARCHITECTURE.md'),text('controller/README.TXT'),
16
- text('scripts/deferred-slot-operation.mjs'),text('scripts/release-parity.mjs'),text('scripts/final-closure.mjs'),
17
- text('scripts/final-closure-verify.mjs'),text('scripts/windows-gate-evidence.mjs'),
16
+ text('scripts/deferred-slot-operation-r39.mjs'),text('scripts/release-parity-r39.mjs'),text('scripts/final-closure-r39.mjs'),
17
+ text('scripts/final-closure-verify-r39.mjs'),text('scripts/windows-gate-evidence-r39.mjs'),
18
18
  text('controller/deadbyte-semantic-lsp-config.json')
19
19
  ]);
20
- assert.equal(pkg.version,'0.11.1');
21
- assert.match(version,/DEADBYTE_VERSION = '0\.11\.1'/);
22
- assert.match(controller,/CONTROLLER V0\.11\.1 \/ R37/);
23
- assert.match(gate,/DEADBYTE V0\.11\.1 \/ R37 WINDOWS BATCH GATE: PASS/);
24
- assert.match(readme,/^DEADBYTE MCP V0\.11\.1 \/ R37 PRODUCTION BASELINE$/m);
25
- assert.match(architecture,/^# DEADBYTE MCP V0\.11\.1 \/ R37 ARCHITECTURE$/m);
26
- assert.match(controllerReadme,/^DEADBYTE MCP V0\.11\.1 \/ R37 CONTROLLER$/m);
27
- assert.match(deferred,/--expected-version','0\.11\.1'/);
28
- assert.match(parity,/R37_PREDECESSOR_RELEASE_ID='v0\.11\.0-08c2a0008b1f84c9'/);
29
- assert.match(parity,new RegExp(R37_PREDECESSOR_MANIFEST));
30
- assert.match(parity,/version==='0\.11\.1'|version:'0\.11\.1'/);
31
- assert.match(closure,/version:'0\.11\.1'/);
32
- assert.match(closureVerify,/DEADBYTE V0\.11\.1 \/ R37 WINDOWS BATCH GATE: PASS/);
33
- assert.match(windowsGate,/version:'0\.11\.1'/);
20
+ assert.equal(pkg.version,'0.11.3');
21
+ assert.equal(pkg.scripts['gate:windows'],'powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-r39.ps1');
22
+ assert.equal(pkg.scripts['self-update:deferred'],'node scripts/deferred-slot-operation-r39.mjs');
23
+ assert.equal(pkg.scripts['release:parity'],'node scripts/release-parity-r39.mjs');
24
+ assert.equal(pkg.scripts['release:final:write'],'node scripts/final-closure-r39.mjs');
25
+ assert.equal(pkg.scripts['release:final:verify'],'node scripts/final-closure-verify-r39.mjs');
26
+ assert.match(version,/DEADBYTE_VERSION = '0\.11\.3'/);
27
+ assert.match(controller,/CONTROLLER V0\.11\.3 \/ R39/);
28
+ assert.match(gate,/DEADBYTE V0\.11\.3 \/ R39 WINDOWS BATCH GATE: PASS/);
29
+ assert.match(readme,/^DEADBYTE MCP V0\.11\.3 \/ R39 HOTFIX BASELINE$/m);
30
+ assert.match(architecture,/^# DEADBYTE MCP V0\.11\.3 \/ R39 ARCHITECTURE$/m);
31
+ assert.match(controllerReadme,/^DEADBYTE MCP V0\.11\.3 \/ R39 CONTROLLER$/m);
32
+ assert.match(deferred,/--expected-version','0\.11\.3'/);
33
+ assert.match(parity,/R39_PREDECESSOR_RELEASE_ID='v0\.11\.2-058605dfccaa3035'/);
34
+ assert.match(parity,new RegExp(R39_PREDECESSOR_MANIFEST));
35
+ assert.match(parity,/version==='0\.11\.3'|version:'0\.11\.3'/);
36
+ assert.match(closure,/version:'0\.11\.3'/);
37
+ assert.match(closureVerify,/DEADBYTE V0\.11\.3 \/ R39 WINDOWS BATCH GATE: PASS/);
38
+ assert.match(windowsGate,/version:'0\.11\.3'/);
34
39
  assert.equal(createHash('sha256').update(Buffer.from(semanticConfig,'utf8')).digest('hex'),'d274b099a298c1033fea8f1e8849751693bbc0448778d619400acb82d4f53a3b');
40
+ assert.equal(R39_PREDECESSOR_RELEASE_ID,'v0.11.2-058605dfccaa3035');
35
41
  });
36
42
 
37
- test('R37 patch keeps capability surface and fixes ONLINE remote startup without restoring verbose mode',async()=>{
38
- const [parity,cli]=await Promise.all([text('src/remote-mcp-r36-parity-client.mjs'),text('src/deadbyte-cli.mjs')]);
39
- assert.match(parity,/R36_EXPECTED_TOOLS\.length !== 76/);
40
- assert.match(parity,/R36_COMPACT_TOOL_LIMIT=42/);
43
+ test('R39 hotfix keeps ONLINE reuse and fixes PowerShell $Host recovery collision',async()=>{
44
+ const [cli,controller]=await Promise.all([text('src/deadbyte-cli.mjs'),text('controller/deadbyte-controller.ps1')]);
41
45
  assert.match(cli,/controllerRuntimeReady/);
42
46
  assert.match(cli,/Runtime already ONLINE; reusing verified bridge\/cloud\/supervisor/);
43
- assert.doesNotMatch(cli,/remote --verbose/);
47
+ assert.match(cli,/invokeController\(ctx,'start',\{discardOutput:true,timeoutMs:REMOTE_START_TIMEOUT_MS\}\)/);
48
+ assert.match(cli,/remote controller start returned without a verified ONLINE runtime/);
49
+ assert.match(cli,/discardOutput\?\['ignore','ignore','ignore'\]/);
50
+ const start=controller.indexOf('function Recover-AutonomousSupervisor');
51
+ const end=controller.indexOf('function Show-State',start);
52
+ assert.ok(start>=0&&end>start,'supervisor recovery block missing');
53
+ const block=controller.slice(start,end);
54
+ assert.doesNotMatch(block,/\$host\s*=/i);
55
+ assert.match(block,/\$hostStatus\s*=\s*Get-HostArmStatus/);
56
+ });
57
+
58
+ test('sealed R37 tooling remains historical 0.11.1 authority',async()=>{
59
+ const [parity,gate,closure]=await Promise.all([
60
+ text('scripts/release-parity.mjs'),text('scripts/gate-windows.ps1'),text('scripts/final-closure.mjs')
61
+ ]);
62
+ assert.match(parity,/R37_PREDECESSOR_RELEASE_ID='v0\.11\.0-08c2a0008b1f84c9'/);
63
+ assert.match(parity,/version==='0\.11\.1'|version:'0\.11\.1'/);
64
+ assert.match(gate,/DEADBYTE V0\.11\.1 \/ R37 WINDOWS BATCH GATE: PASS/);
65
+ assert.match(closure,/version:'0\.11\.1'/);
44
66
  });
@@ -7,7 +7,7 @@ test('R37 live timeline renders sanitized tool-call detail and correlates termin
7
7
  const tracker=createLiveTimelineTracker({clock:()=>now});
8
8
  const run=tracker.observe({event_type:'tool.request',tool:'coding_file_read',request_id:'abcdef1234567890',
9
9
  args:{root_id:'projects',path:'src/a.mjs',content:'SECRET',token:'SECRET'}});
10
- assert.match(run,/^1970-01-01T00:00:01\.000Z \| coding_file_read\s+\| Arguments: \{/);
10
+ assert.match(run,/^1970-01-01T07:00:01\.000\+07:00 \| coding_file_read\s+\| Arguments: \{/);
11
11
  assert.match(run,/\"path\":\"src\/a\.mjs\"/);
12
12
  assert.match(run,/\"reason\":\"payload\"/);
13
13
  assert.match(run,/\"reason\":\"secret\"/);
@@ -16,11 +16,15 @@ async function fixture({failCommand='',statusOnline=false}={}){
16
16
  const state=path.join(dir,'state');
17
17
  const bin=path.join(state,'bin');
18
18
  const trace=path.join(dir,'trace.txt');
19
+ const startedMarker=path.join(dir,'started.txt');
20
+ const spawnedStdout=path.join(dir,'spawned.stdout.log');
21
+ const spawnedStderr=path.join(dir,'spawned.stderr.log');
22
+ const spawnedPid=path.join(dir,'spawned.pid');
19
23
  await mkdir(bin,{recursive:true});
20
24
  const launcher=path.join(bin,'DEADBYTE-MCP.ps1');
21
- const ps1=`param([string]$Command)\n$ErrorActionPreference='Stop'\nfor($i=0;$i -lt 20;$i++){ try { [IO.File]::AppendAllText($env:DEADBYTE_REMOTE_TEST_TRACE,(\"$Command\" + [Environment]::NewLine),[Text.Encoding]::UTF8); break } catch { if($i -eq 19){ throw }; Start-Sleep -Milliseconds 10 } }\nif ($env:DEADBYTE_REMOTE_TEST_FAIL -and $Command -eq $env:DEADBYTE_REMOTE_TEST_FAIL) { Write-Error \"forced $Command failure\"; exit 9 }\nswitch ($Command) {\n 'start' { Write-Host 'DEADBYTE MCP = ONLINE' }\n 'status' { if ($env:DEADBYTE_REMOTE_TEST_STATUS_ONLINE -eq '1') { Write-Host 'DEADBYTE MCP = ONLINE'; Write-Host 'Bridge PID : 1001 [verified]'; Write-Host 'Cloud PID : 1002 [verified]'; Write-Host 'Local ready : True'; Write-Host 'Loop supervisor: RUNNING [verified]' } else { Write-Host 'DEADBYTE MCP = OFFLINE' } }\n 'processstatus' { Write-Host 'Process plane : ARMED [standing-grant]' }\n 'codingstatus' { Write-Host 'Coding plane : ARMED [standing-grant]' }\n 'autonomousstatus' { Write-Host 'Autonomous : ARMED [standing-grant]' }\n 'hoststatus' { Write-Host 'Host plane : DISARMED [disarmed]' }\n 'park' { Write-Host 'DEADBYTE MCP = PARKED' }\n default { Write-Host \"$Command OK\" }\n}\nexit 0\n`;
25
+ const ps1=`param([string]$Command)\n$ErrorActionPreference='Stop'\nfor($i=0;$i -lt 20;$i++){ try { [IO.File]::AppendAllText($env:DEADBYTE_REMOTE_TEST_TRACE,(\"$Command\" + [Environment]::NewLine),[Text.Encoding]::UTF8); break } catch { if($i -eq 19){ throw }; Start-Sleep -Milliseconds 10 } }\nif ($env:DEADBYTE_REMOTE_TEST_FAIL -and $Command -eq $env:DEADBYTE_REMOTE_TEST_FAIL) { Write-Error \"forced $Command failure\"; exit 9 }\nswitch ($Command) {\n 'start' { if ($env:DEADBYTE_REMOTE_TEST_SPAWN_CHILD -eq '1') { $node=(Get-Command node.exe).Source; $spawned=Start-Process -FilePath $node -ArgumentList @('-e','setTimeout(()=>process.exit(0),10000)') -PassThru -WindowStyle Hidden -RedirectStandardOutput $env:DEADBYTE_REMOTE_TEST_SPAWN_STDOUT -RedirectStandardError $env:DEADBYTE_REMOTE_TEST_SPAWN_STDERR; if ($env:DEADBYTE_REMOTE_TEST_SPAWN_PID) { [IO.File]::WriteAllText($env:DEADBYTE_REMOTE_TEST_SPAWN_PID,[string]$spawned.Id,[Text.Encoding]::UTF8) } }; if ($env:DEADBYTE_REMOTE_TEST_STARTED) { [IO.File]::WriteAllText($env:DEADBYTE_REMOTE_TEST_STARTED,'1',[Text.Encoding]::UTF8) }; Write-Host 'DEADBYTE MCP = ONLINE' }\n 'status' { if ($env:DEADBYTE_REMOTE_TEST_STATUS_ONLINE -eq '1' -or ($env:DEADBYTE_REMOTE_TEST_STARTED -and (Test-Path -LiteralPath $env:DEADBYTE_REMOTE_TEST_STARTED))) { Write-Host 'DEADBYTE MCP = ONLINE'; Write-Host 'Bridge PID : 1001 [verified]'; Write-Host 'Cloud PID : 1002 [verified]'; Write-Host 'Local ready : True'; Write-Host 'Loop supervisor: RUNNING [verified]' } else { Write-Host 'DEADBYTE MCP = OFFLINE' } }\n 'processstatus' { Write-Host 'Process plane : ARMED [standing-grant]' }\n 'codingstatus' { Write-Host 'Coding plane : ARMED [standing-grant]' }\n 'autonomousstatus' { Write-Host 'Autonomous : ARMED [standing-grant]' }\n 'hoststatus' { Write-Host 'Host plane : DISARMED [disarmed]' }\n 'park' { if ($env:DEADBYTE_REMOTE_TEST_STARTED) { Remove-Item -LiteralPath $env:DEADBYTE_REMOTE_TEST_STARTED -Force -ErrorAction SilentlyContinue }; Write-Host 'DEADBYTE MCP = PARKED' }\n default { Write-Host \"$Command OK\" }\n}\nexit 0\n`;
22
26
  await writeFile(launcher,ps1,'utf8');
23
- return {dir,state,trace,env:{...process.env,DEADBYTE_STATE_ROOT:state,DEADBYTE_REMOTE_TEST_TRACE:trace,DEADBYTE_REMOTE_TEST_FAIL:failCommand,DEADBYTE_REMOTE_TEST_STATUS_ONLINE:statusOnline?'1':'0'}};
27
+ return {dir,state,trace,env:{...process.env,DEADBYTE_STATE_ROOT:state,DEADBYTE_REMOTE_TEST_TRACE:trace,DEADBYTE_REMOTE_TEST_FAIL:failCommand,DEADBYTE_REMOTE_TEST_STATUS_ONLINE:statusOnline?'1':'0',DEADBYTE_REMOTE_TEST_STARTED:startedMarker,DEADBYTE_REMOTE_TEST_SPAWN_STDOUT:spawnedStdout,DEADBYTE_REMOTE_TEST_SPAWN_STDERR:spawnedStderr,DEADBYTE_REMOTE_TEST_SPAWN_PID:spawnedPid},spawnedPid};
24
28
  }
25
29
 
26
30
  async function traceCommands(file,{read=readFile,retryDelayMs=10,maxAttempts=20}={}){
@@ -90,15 +94,45 @@ winTest('bare remote reuses a fully verified ONLINE runtime without invoking blo
90
94
  }
91
95
  });
92
96
 
97
+ winTest('bare remote PARKED startup does not wait for a long-lived child holding inherited pipe handles',async()=>{
98
+ const fx=await fixture();
99
+ fx.env.DEADBYTE_REMOTE_TEST_SPAWN_CHILD='1';
100
+ let child=null;
101
+ try{
102
+ const startedAt=Date.now();
103
+ child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
104
+ const output=await collect(child);
105
+ const ready=await waitFor(fx.trace,commands=>commands.includes('hoststatus'),{timeoutMs:8000});
106
+ const elapsed=Date.now()-startedAt;
107
+ assert.deepEqual(ready.slice(0,10),[
108
+ 'status','start','status','armprocess','armcoding','armautonomous',
109
+ 'processstatus','codingstatus','autonomousstatus','hoststatus'
110
+ ]);
111
+ assert.ok(elapsed<7000,`PARKED startup waited on inherited child pipe handles: ${elapsed}ms`);
112
+ assert.equal(child.exitCode,null,'remote session must remain foreground after PARKED startup');
113
+ assert.match(output.stdout,/\[BOOT\] Starting bridge\/runtime\.\.\./);
114
+ assert.match(output.stdout,/\[OK\] ONLINE/);
115
+ child.stdin.end();
116
+ const ended=await Promise.race([output.closed,sleep(6000).then(()=>({timeout:true}))]);
117
+ assert.equal(ended.timeout,undefined,'remote session did not exit after PARKED startup proof');
118
+ assert.equal(ended.code,0,output.stderr);
119
+ }finally{
120
+ if(child?.exitCode===null) child.kill('SIGKILL');
121
+ try{const pid=Number((await readFile(fx.spawnedPid,'utf8')).trim());if(Number.isInteger(pid)&&pid>0) process.kill(pid,'SIGKILL');}catch{}
122
+ await sleep(100);
123
+ await rm(fx.dir,{recursive:true,force:true});
124
+ }
125
+ });
126
+
93
127
  winTest('bare remote uses one unified live timeline, keeps authority semantics, then disarms and parks when the foreground session ends',async()=>{
94
128
  const fx=await fixture();
95
129
  let child=null;
96
130
  try{
97
131
  child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
98
132
  const output=await collect(child);
99
- const ready=await waitFor(fx.trace,commands=>commands.slice(0,9).join(',')==='status,start,armprocess,armcoding,armautonomous,processstatus,codingstatus,autonomousstatus,hoststatus');
100
- assert.deepEqual(ready.slice(0,9),[
101
- 'status','start','armprocess','armcoding','armautonomous',
133
+ const ready=await waitFor(fx.trace,commands=>commands.slice(0,10).join(',')==='status,start,status,armprocess,armcoding,armautonomous,processstatus,codingstatus,autonomousstatus,hoststatus');
134
+ assert.deepEqual(ready.slice(0,10),[
135
+ 'status','start','status','armprocess','armcoding','armautonomous',
102
136
  'processstatus','codingstatus','autonomousstatus','hoststatus'
103
137
  ]);
104
138
  assert.equal(child.exitCode,null,'remote session must remain foreground after becoming ready');
@@ -136,9 +170,9 @@ winTest('bare remote uses one unified live timeline, keeps authority semantics,
136
170
  ].join('\n')+'\n','utf8');
137
171
  const logDeadline=Date.now()+3000;
138
172
  while(Date.now()<logDeadline&&!/✗ \[fedcba98\] ERR coding_file_read 1\.73s/.test(output.stdout)) await sleep(50);
139
- assert.match(output.stdout,/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}Z \| coding_tree\s+\| Arguments: .*\"path\":\"src\".*\"root_id\":\"projects\".*\[cursor r1:[0-9a-f]{24}:1\]$/m);
173
+ assert.match(output.stdout,/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}\+07:00 \| coding_tree\s+\| Arguments: .*\"path\":\"src\".*\"root_id\":\"projects\".*\[cursor r1:[0-9a-f]{24}:1\]$/m);
140
174
  assert.match(output.stdout,/✓ \[abcdef12\] OK coding_tree 42ms \[cursor r1:[0-9a-f]{24}:2\]/);
141
- assert.match(output.stdout,/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}Z \| coding_file_read\s+\| Arguments: \{\"path\":\"src\/deadbyte-cli\.mjs\",\"root_id\":\"projects\"\} \[cursor r1:[0-9a-f]{24}:3\]$/m);
175
+ assert.match(output.stdout,/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}\+07:00 \| coding_file_read\s+\| Arguments: \{\"path\":\"src\/deadbyte-cli\.mjs\",\"root_id\":\"projects\"\} \[cursor r1:[0-9a-f]{24}:3\]$/m);
142
176
  assert.match(output.stdout,/✗ \[fedcba98\] ERR coding_file_read 1\.73s \[cursor r1:[0-9a-f]{24}:4\]/);
143
177
  assert.equal((output.stdout.match(/✓ \[abcdef12\] OK coding_tree 42ms/g)||[]).length,1,'duplicate terminal result must print once');
144
178
  const resultJournal=JSON.parse(await readFile(path.join(fx.state,'runtime','remote-results',`${marker.result_session_id}.json`),'utf8'));
@@ -209,7 +243,7 @@ winTest('remote --resume replays sanitized tool-call and terminal result events
209
243
  while(Date.now()<deadline&&(!/coding_file_read\s+\| Arguments: .*REPLAY cursor r1:[0-9a-f]{24}:3/.test(secondOutput.stdout)||
210
244
  !/\[REPLAY\] \[OK\] coding_file_read \[cursor r1:[0-9a-f]{24}:4\]/.test(secondOutput.stdout)||
211
245
  !/\[LOG\] Unified live timeline/.test(secondOutput.stdout))) await sleep(50);
212
- assert.match(secondOutput.stdout,/^2026-09-18T16:30:01\.000Z \| coding_file_read\s+\| Arguments: .*\"path\":\"src\/deadbyte-cli\.mjs\".*REPLAY cursor r1:[0-9a-f]{24}:3$/m);
246
+ assert.match(secondOutput.stdout,/^2026-09-18T23:30:01\.000\+07:00 \| coding_file_read\s+\| Arguments: .*\"path\":\"src\/deadbyte-cli\.mjs\".*REPLAY cursor r1:[0-9a-f]{24}:3$/m);
213
247
  assert.match(secondOutput.stdout,/\[REPLAY\] \[OK\] coding_file_read \[cursor r1:[0-9a-f]{24}:4\]/);
214
248
  assert.match(secondOutput.stdout,/♻️ \[SESSION\] Previous result stream replayed/);
215
249
  assert.doesNotMatch(secondOutput.stdout,/DO_NOT_REPLAY_SECRET/);
@@ -249,9 +283,9 @@ winTest('detached guardian revokes authority, parks, and removes the session mar
249
283
  try{
250
284
  child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
251
285
  const output=await collect(child);
252
- const ready=await waitFor(fx.trace,commands=>commands.slice(0,8).join(',')==='start,armprocess,armcoding,armautonomous,processstatus,codingstatus,autonomousstatus,hoststatus');
253
- assert.deepEqual(ready.slice(0,9),[
254
- 'status','start','armprocess','armcoding','armautonomous',
286
+ const ready=await waitFor(fx.trace,commands=>commands.slice(0,10).join(',')==='status,start,status,armprocess,armcoding,armautonomous,processstatus,codingstatus,autonomousstatus,hoststatus');
287
+ assert.deepEqual(ready.slice(0,10),[
288
+ 'status','start','status','armprocess','armcoding','armautonomous',
255
289
  'processstatus','codingstatus','autonomousstatus','hoststatus'
256
290
  ]);
257
291
  const markerPath=path.join(fx.state,'runtime','remote-session.json');
@@ -294,7 +328,7 @@ winTest('bare remote rolls back authority and parks if one plane fails to arm',a
294
328
  assert.equal(ended.timeout,undefined,'failed startup did not terminate');
295
329
  assert.notEqual(ended.code,0);
296
330
  const commands=await traceCommands(fx.trace);
297
- assert.deepEqual(commands.slice(0,4),['status','start','armprocess','armcoding']);
331
+ assert.deepEqual(commands.slice(0,5),['status','start','status','armprocess','armcoding']);
298
332
  assert.deepEqual(commands.slice(-5),['disarmautonomous','disarmcoding','disarmprocess','disarmhost','park']);
299
333
  assert.doesNotMatch(output.stdout,/Live logs/i);
300
334
  }finally{await rm(fx.dir,{recursive:true,force:true});}