deadbyte-mcp 0.11.0 → 0.11.2

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 (76) hide show
  1. package/MANIFEST.SHA256 +75 -59
  2. package/README.txt +7 -7
  3. package/bin/WORKER-REGISTRY.txt +3 -3
  4. package/bin/appcontainer-stage.exe +0 -0
  5. package/bin/appcontainer-stage.obj +0 -0
  6. package/bin/bootstrap-advapi32.exe +0 -0
  7. package/bin/bootstrap-advapi32.obj +0 -0
  8. package/bin/bootstrap-exitcode.exe +0 -0
  9. package/bin/bootstrap-exitcode.obj +0 -0
  10. package/bin/bootstrap-kernel32.exe +0 -0
  11. package/bin/bootstrap-kernel32.obj +0 -0
  12. package/bin/child-control-probe.exe +0 -0
  13. package/bin/child-control-probe.obj +0 -0
  14. package/bin/child-control-stage.exe +0 -0
  15. package/bin/child-control-stage.obj +0 -0
  16. package/bin/contained-reverse-worker.exe +0 -0
  17. package/bin/contained-reverse-worker.obj +0 -0
  18. package/bin/contained-transform-worker.exe +0 -0
  19. package/bin/contained-transform-worker.obj +0 -0
  20. package/bin/containment-probe.exe +0 -0
  21. package/bin/containment-probe.obj +0 -0
  22. package/bin/deadbyte-contain.exe +0 -0
  23. package/bin/deadbyte-contain.obj +0 -0
  24. package/bin/deadbyte-exec.exe +0 -0
  25. package/bin/deadbyte-exec.obj +0 -0
  26. package/bin/deadbyte-process-host.exe +0 -0
  27. package/bin/deadbyte-process-host.obj +0 -0
  28. package/bin/deadbyte-tunnel-host.exe +0 -0
  29. package/bin/deadbyte-tunnel-host.obj +0 -0
  30. package/controller/README.TXT +1 -1
  31. package/controller/deadbyte-controller.ps1 +4 -4
  32. package/controller/deadbyte-process-policy.json +1 -1
  33. package/docs/ARCHITECTURE.md +1 -1
  34. package/package.json +6 -6
  35. package/scripts/build-containment.ps1 +15 -15
  36. package/scripts/deferred-slot-operation-r37-0110.mjs +124 -0
  37. package/scripts/deferred-slot-operation-r38.mjs +124 -0
  38. package/scripts/deferred-slot-operation.mjs +1 -1
  39. package/scripts/final-closure-r37-0110.mjs +113 -0
  40. package/scripts/final-closure-r38.mjs +113 -0
  41. package/scripts/final-closure-verify-r37-0110.mjs +208 -0
  42. package/scripts/final-closure-verify-r38.mjs +208 -0
  43. package/scripts/final-closure-verify.mjs +16 -16
  44. package/scripts/final-closure.mjs +8 -8
  45. package/scripts/gate-windows-r37-0110.ps1 +42 -0
  46. package/scripts/gate-windows-r38.ps1 +42 -0
  47. package/scripts/gate-windows.ps1 +3 -3
  48. package/scripts/release-parity-r37-0110.mjs +200 -0
  49. package/scripts/release-parity-r38.mjs +200 -0
  50. package/scripts/release-parity-tests-r38.ps1 +9 -0
  51. package/scripts/release-parity-tests.ps1 +1 -1
  52. package/scripts/release-parity.mjs +14 -14
  53. package/scripts/windows-gate-evidence-r37-0110.mjs +52 -0
  54. package/scripts/windows-gate-evidence-r38.mjs +52 -0
  55. package/scripts/windows-gate-evidence.mjs +4 -4
  56. package/src/deadbyte-cli.mjs +58 -23
  57. package/src/release-generation.mjs +18 -1
  58. package/src/remote-live-log.mjs +23 -1
  59. package/src/remote-result-journal.mjs +23 -4
  60. package/src/version.mjs +1 -1
  61. package/test/cli-entrypoint.test.mjs +9 -0
  62. package/test/containment.test.mjs +18 -0
  63. package/test/controller.test.mjs +11 -0
  64. package/test/core.test.mjs +1 -1
  65. package/test/production-docs.test.mjs +3 -3
  66. package/test/r33-closeout-regression.test.mjs +8 -8
  67. package/test/r33-finalization.test.mjs +14 -14
  68. package/test/r36-release-identity.test.mjs +4 -4
  69. package/test/r37-0110-history.test.mjs +20 -0
  70. package/test/r37-finalization.test.mjs +14 -14
  71. package/test/r37-remote-tool-call-timeline.test.mjs +94 -0
  72. package/test/r38-finalization.test.mjs +74 -0
  73. package/test/release-generation.test.mjs +13 -3
  74. package/test/release-version.test.mjs +45 -33
  75. package/test/remote-live-log-r37.test.mjs +5 -2
  76. package/test/remote-session-cli.test.mjs +66 -25
@@ -1,7 +1,7 @@
1
1
  import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import { readFile } from 'node:fs/promises';
4
- import { validateParityEvidence, R36_PREDECESSOR_RELEASE_ID, R36_PREDECESSOR_MANIFEST } from '../scripts/release-parity.mjs';
4
+ import { validateParityEvidence, R37_PREDECESSOR_RELEASE_ID, R37_PREDECESSOR_MANIFEST } from '../scripts/release-parity.mjs';
5
5
  import { verifyFinalClosureObject } from '../scripts/final-closure-verify.mjs';
6
6
 
7
7
  const root=new URL('../',import.meta.url);
@@ -11,22 +11,22 @@ function parityFixture(){
11
11
  const manifest='a'.repeat(64);
12
12
  return {
13
13
  schema:'deadbyte.r37-parity.v1',status:'passed',execution_provider:'deadbyte_mcp',rdc_operation_count:0,
14
- candidate:{release_id:`v0.11.0-${manifest.slice(0,16)}`,version:'0.11.0',manifest_sha256:manifest},
14
+ candidate:{release_id:`v0.11.1-${manifest.slice(0,16)}`,version:'0.11.1',manifest_sha256:manifest},
15
15
  immutable_slot:{protected:true,release_root:'C:/immutable/r37',development_root:'D:/Projects/deadbyte-mcp-r36-dev'},
16
16
  local_full:{status:'passed',tool_count:76,strict_output_schemas:true},
17
17
  public_compact:{status:'passed',tool_count:41,capability_closure:true,gateway_count:5},
18
18
  autonomous:{status:'passed',signed_release_verified:true,observed_failure_before_replan:true},
19
19
  before_rollback_disarmed:{status:'passed',capability_closure:true,coding_armed:false,autonomous_armed:false},
20
20
  rollback:{state:'completed'},stage_restore:{status:'restored',manifest_sha256:manifest},restore:{state:'completed'},
21
- predecessor:{release_id:R36_PREDECESSOR_RELEASE_ID,version:'0.10.0',manifest_sha256:R36_PREDECESSOR_MANIFEST},
21
+ predecessor:{release_id:R37_PREDECESSOR_RELEASE_ID,version:'0.11.0',manifest_sha256:R37_PREDECESSOR_MANIFEST},
22
22
  predecessor_disarmed:{status:'passed',tool_count:41,capability_closure:true},
23
- successor:{release_id:`v0.11.0-${manifest.slice(0,16)}`,version:'0.11.0',manifest_sha256:manifest},
23
+ successor:{release_id:`v0.11.1-${manifest.slice(0,16)}`,version:'0.11.1',manifest_sha256:manifest},
24
24
  successor_disarmed:{status:'passed',capability_closure:true,coding_armed:false,autonomous_armed:false},
25
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
26
  };
27
27
  }
28
28
 
29
- test('R37 parity validator requires full-76, compact closure, exact R36 predecessor and immutable-slot separation',()=>{
29
+ test('R37 parity validator requires full-76, compact closure, exact public 0.11.0 predecessor and immutable-slot separation',()=>{
30
30
  const good=parityFixture();
31
31
  assert.equal(validateParityEvidence(good),true);
32
32
  assert.throws(()=>validateParityEvidence({...good,local_full:{...good.local_full,tool_count:75}}),/full 76/i);
@@ -36,33 +36,33 @@ test('R37 parity validator requires full-76, compact closure, exact R36 predeces
36
36
  assert.throws(()=>validateParityEvidence({...good,stage_restore:{status:'missing',manifest_sha256:good.candidate.manifest_sha256}}),/stage restore/i);
37
37
  });
38
38
 
39
- test('R37 parity captures R37 bridge, exact R36 predecessor, stage reseed and successor restore',async()=>{
39
+ test('R37 parity captures R37 bridge, exact public 0.11.0 predecessor, stage reseed and successor restore',async()=>{
40
40
  const parity=await text('scripts/release-parity.mjs');
41
- assert.match(parity,/R36_PREDECESSOR_RELEASE_ID='v0\.10\.0-8d1e5f09745e7647'/);
42
- assert.match(parity,/8d1e5f09745e764796b60e0a8a0168be7334ed4bf834fad5974a80eba295b4e8/);
41
+ assert.match(parity,/R37_PREDECESSOR_RELEASE_ID='v0\.11\.0-08c2a0008b1f84c9'/);
42
+ assert.match(parity,/08c2a0008b1f84c90f7ce7faa1e3decbd03f33612bc0fdc7d1ba591b548798e8/);
43
43
  assert.match(parity,/const stageRestore=await restoreFrozenStage/);
44
- assert.match(parity,/publicR36Disarmed/);
44
+ assert.match(parity,/publicR37Disarmed/);
45
45
  assert.match(parity,/scheduleDeferred\('activate',candidateManifest,\{bridgeRoot:successorBridge\.root,bridgeScriptSha256:successorBridge\.sha256\}\)/);
46
46
  });
47
47
 
48
- test('R37 current final closure writer and independent verifier bind R37 domains and R36 predecessor',async()=>{
48
+ test('R37 current final closure writer and independent verifier bind R37 domains and public 0.11.0 predecessor',async()=>{
49
49
  const [writer,verifier]=await Promise.all([text('scripts/final-closure.mjs'),text('scripts/final-closure-verify.mjs')]);
50
50
  assert.equal(typeof verifyFinalClosureObject,'function');
51
51
  assert.match(writer,/DEADBYTE-R37-FINAL-CLOSURE-V1/);
52
52
  assert.match(writer,/deadbyte\.r37-final-closure\.v1/);
53
- assert.match(writer,/pointer\.version==='0\.11\.0'/);
53
+ assert.match(writer,/pointer\.version==='0\.11\.1'/);
54
54
  assert.match(writer,/R37 FINAL MACHINE BASELINE/);
55
55
  assert.match(writer,/deadbyte\.r37-parity\.v1/);
56
56
  assert.match(writer,/deadbyte\.r37-windows-gate\.v1/);
57
- assert.match(writer,/R36_PREDECESSOR_RELEASE_ID/);
57
+ assert.match(writer,/R37_PREDECESSOR_RELEASE_ID/);
58
58
  assert.doesNotMatch(verifier,/from ['"]\.\.\/src\//);
59
59
  assert.match(verifier,/DEADBYTE-R37-FINAL-CLOSURE-V1/);
60
60
  assert.match(verifier,/deadbyte\.r37-final-closure\.v1/);
61
- assert.match(verifier,/envelope\.body\.version==='0\.11\.0'/);
61
+ assert.match(verifier,/envelope\.body\.version==='0\.11\.1'/);
62
62
  assert.match(verifier,/R37 FINAL MACHINE BASELINE/);
63
63
  assert.match(verifier,/deadbyte\.r37-parity\.v1/);
64
64
  assert.match(verifier,/deadbyte\.r37-windows-gate\.v1/);
65
- assert.match(verifier,/8d1e5f09745e764796b60e0a8a0168be7334ed4bf834fad5974a80eba295b4e8/);
65
+ assert.match(verifier,/08c2a0008b1f84c90f7ce7faa1e3decbd03f33612bc0fdc7d1ba591b548798e8/);
66
66
  });
67
67
 
68
68
  test('R37 bounded public parity suite covers current release identity and agent fabric',async()=>{
@@ -0,0 +1,94 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { mkdtemp, readFile, rm } from 'node:fs/promises';
4
+ import os from 'node:os';
5
+ import path from 'node:path';
6
+ import { createLiveTimelineTracker, formatRemoteToolCall } from '../src/remote-live-log.mjs';
7
+ import { openRemoteResultJournal } from '../src/remote-result-journal.mjs';
8
+
9
+ const H=c=>c.repeat(64);
10
+ const session='c'.repeat(24);
11
+
12
+ test('R37 unified timeline renders one sanitized tool-call line with ISO timestamp, padded tool name, and JSON arguments',()=>{
13
+ const event={
14
+ event_type:'tool.request',
15
+ request_id:'abcdef1234567890',
16
+ tool:'coding_file_write',
17
+ created_at_utc:'2026-09-18T16:24:30.125Z',
18
+ args:{
19
+ root_id:'projects',
20
+ path:'src/example.mjs',
21
+ content:'TOP_SECRET_PAYLOAD',
22
+ token:'TOP_SECRET_TOKEN',
23
+ nested:{authorization:'Bearer abc.def.ghi',safe:true}
24
+ }
25
+ };
26
+ const line=formatRemoteToolCall(event);
27
+ assert.match(line,/^2026-09-18T16:24:30\.125Z \| coding_file_write\s+\| Arguments: \{/);
28
+ assert.match(line,/"root_id":"projects"/);
29
+ assert.match(line,/"path":"src\/example\.mjs"/);
30
+ assert.match(line,/"reason":"payload"/);
31
+ assert.match(line,/"reason":"secret"/);
32
+ assert.doesNotMatch(line,/TOP_SECRET_PAYLOAD|TOP_SECRET_TOKEN|Bearer abc\.def\.ghi/);
33
+ });
34
+
35
+ test('R37 live tracker uses the tool-call line for request and keeps correlated terminal result',()=>{
36
+ let now=Date.parse('2026-09-18T16:24:30.125Z');
37
+ const tracker=createLiveTimelineTracker({clock:()=>now});
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"\}$/);
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');
44
+ });
45
+
46
+ test('R37 remote result journal persists sanitized tool-call and result in one monotonic cursor stream',async()=>{
47
+ const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r37-toolcall-journal-'));
48
+ const file=path.join(root,'journal.json');
49
+ try{
50
+ const journal=await openRemoteResultJournal({filePath:file,sessionId:session,maxEntries:16});
51
+ const call=await journal.recordCall({
52
+ request_id:'req-1',tool:'coding_file_write',observed_at_utc:'2026-09-18T16:24:30.125Z',
53
+ arguments:{root_id:'projects',path:'x.txt',content:'DO_NOT_STORE_PAYLOAD',token:'DO_NOT_STORE_TOKEN'},
54
+ payload_sha256:H('1')
55
+ });
56
+ const duplicate=await journal.recordCall({
57
+ request_id:'req-1',tool:'coding_file_write',observed_at_utc:'2026-09-18T16:24:30.125Z',
58
+ arguments:{root_id:'projects',path:'x.txt',content:'DO_NOT_STORE_PAYLOAD',token:'DO_NOT_STORE_TOKEN'},
59
+ payload_sha256:H('1')
60
+ });
61
+ const result=await journal.recordTerminal({
62
+ request_id:'req-1',tool:'coding_file_write',status:'ok',observed_at_utc:'2026-09-18T16:24:30.500Z',
63
+ payload_sha256:H('2')
64
+ });
65
+ assert.equal(call.event.seq,1);
66
+ assert.equal(call.event.event_type,'tool.call');
67
+ assert.equal(duplicate.duplicate,true);
68
+ assert.equal(result.event.seq,2);
69
+ assert.equal(result.event.event_type,'tool.result');
70
+ assert.equal(journal.cursor(),'r1:'+session+':2');
71
+ const replay=await journal.replayAfter('r1:'+session+':0',{limit:8});
72
+ assert.deepEqual(replay.events.map(e=>[e.seq,e.event_type]),[[1,'tool.call'],[2,'tool.result']]);
73
+ const disk=await readFile(file,'utf8');
74
+ assert.doesNotMatch(disk,/DO_NOT_STORE_PAYLOAD|DO_NOT_STORE_TOKEN/);
75
+ assert.match(disk,/"reason":"payload"/);
76
+ assert.match(disk,/"reason":"secret"/);
77
+ }finally{await rm(root,{recursive:true,force:true});}
78
+ });
79
+
80
+ test('R37 journal remains backward-compatible with pre-tool-call result-only events',async()=>{
81
+ const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r37-old-result-journal-'));
82
+ const file=path.join(root,'journal.json');
83
+ try{
84
+ await import('node:fs/promises').then(({writeFile})=>writeFile(file,JSON.stringify({
85
+ schema:'deadbyte.remote-result-journal.v1',session_id:session,next_seq:2,
86
+ events:[{session_id:session,seq:1,request_id:'old-1',tool:'coding_tree',status:'ok',
87
+ observed_at_utc:'2026-09-17T00:00:00.000Z',payload_sha256:H('3')}]
88
+ })+'\n','utf8'));
89
+ const journal=await openRemoteResultJournal({filePath:file,sessionId:session,maxEntries:16});
90
+ const replay=await journal.replayAfter('r1:'+session+':0',{limit:8});
91
+ assert.equal(replay.events[0].event_type,'tool.result');
92
+ assert.equal(replay.events[0].status,'ok');
93
+ }finally{await rm(root,{recursive:true,force:true});}
94
+ });
@@ -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
+ });
@@ -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,47 +5,59 @@ 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 R36_RELEASE_ID='v0.10.0-8d1e5f09745e7647';
9
- const R36_MANIFEST='8d1e5f09745e764796b60e0a8a0168be7334ed4bf834fad5974a80eba295b4e8';
8
+ const R38_PREDECESSOR_RELEASE_ID='v0.11.1-220fac89dd82cdcd';
9
+ const R38_PREDECESSOR_MANIFEST='220fac89dd82cdcdddb82cd7d0b71b768f84a5c87d57ebaca0f5383f33d97a76';
10
10
 
11
- test('R37 successor release authority agrees on V0.11.0 / R37 and preserves exact public R36 predecessor',async()=>{
11
+ test('R38 hotfix authority agrees on V0.11.2 and preserves exact public 0.11.1 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-r38.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-r38.mjs'),text('scripts/release-parity-r38.mjs'),text('scripts/final-closure-r38.mjs'),
17
+ text('scripts/final-closure-verify-r38.mjs'),text('scripts/windows-gate-evidence-r38.mjs'),
18
18
  text('controller/deadbyte-semantic-lsp-config.json')
19
19
  ]);
20
- assert.equal(pkg.version,'0.11.0');
21
- assert.match(version,/DEADBYTE_VERSION = '0\.11\.0'/);
22
- assert.match(controller,/CONTROLLER V0\.11\.0 \/ R37/);
23
- assert.match(gate,/DEADBYTE V0\.11\.0 \/ R37 WINDOWS BATCH GATE: PASS/);
24
- assert.match(readme,/^DEADBYTE MCP V0\.11\.0 \/ R37 PRODUCTION BASELINE$/m);
25
- assert.match(architecture,/^# DEADBYTE MCP V0\.11\.0 \/ R37 ARCHITECTURE$/m);
26
- assert.match(controllerReadme,/^DEADBYTE MCP V0\.11\.0 \/ R37 CONTROLLER$/m);
27
- assert.match(controllerReadme,/full 76-tool (?:profile|catalog)/);
28
- assert.match(controllerReadme,/compact capability profile[^\n]*<=42 tools/);
29
- assert.match(deferred,/--expected-version','0\.11\.0'/);
30
- assert.match(parity,/deadbyte\.r37-parity\.v1/);
31
- assert.match(parity,/version==='0\.11\.0'|version:'0\.11\.0'/);
32
- assert.match(parity,new RegExp(R36_RELEASE_ID.replaceAll('.','\\.')));
33
- assert.match(parity,new RegExp(R36_MANIFEST));
34
- assert.match(closure,/DEADBYTE-R37-FINAL-CLOSURE-V1/);
35
- assert.match(closure,/version:'0\.11\.0'/);
36
- assert.match(closureVerify,/DEADBYTE V0\.11\.0 \/ R37 WINDOWS BATCH GATE: PASS/);
37
- assert.match(windowsGate,/schema:'deadbyte\.r37-windows-gate\.v1'/);
20
+ assert.equal(pkg.version,'0.11.2');
21
+ assert.equal(pkg.scripts['gate:windows'],'powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-r38.ps1');
22
+ assert.equal(pkg.scripts['self-update:deferred'],'node scripts/deferred-slot-operation-r38.mjs');
23
+ assert.equal(pkg.scripts['release:parity'],'node scripts/release-parity-r38.mjs');
24
+ assert.equal(pkg.scripts['release:final:write'],'node scripts/final-closure-r38.mjs');
25
+ assert.equal(pkg.scripts['release:final:verify'],'node scripts/final-closure-verify-r38.mjs');
26
+ assert.match(version,/DEADBYTE_VERSION = '0\.11\.2'/);
27
+ assert.match(controller,/CONTROLLER V0\.11\.2 \/ R38/);
28
+ assert.match(gate,/DEADBYTE V0\.11\.2 \/ R38 WINDOWS BATCH GATE: PASS/);
29
+ assert.match(readme,/^DEADBYTE MCP V0\.11\.2 \/ R38 HOTFIX BASELINE$/m);
30
+ assert.match(architecture,/^# DEADBYTE MCP V0\.11\.2 \/ R38 ARCHITECTURE$/m);
31
+ assert.match(controllerReadme,/^DEADBYTE MCP V0\.11\.2 \/ R38 CONTROLLER$/m);
32
+ assert.match(deferred,/--expected-version','0\.11\.2'/);
33
+ assert.match(parity,/R38_PREDECESSOR_RELEASE_ID='v0\.11\.1-220fac89dd82cdcd'/);
34
+ assert.match(parity,new RegExp(R38_PREDECESSOR_MANIFEST));
35
+ assert.match(parity,/version==='0\.11\.2'|version:'0\.11\.2'/);
36
+ assert.match(closure,/version:'0\.11\.2'/);
37
+ assert.match(closureVerify,/DEADBYTE V0\.11\.2 \/ R38 WINDOWS BATCH GATE: PASS/);
38
+ assert.match(windowsGate,/version:'0\.11\.2'/);
38
39
  assert.equal(createHash('sha256').update(Buffer.from(semanticConfig,'utf8')).digest('hex'),'d274b099a298c1033fea8f1e8849751693bbc0448778d619400acb82d4f53a3b');
40
+ assert.equal(R38_PREDECESSOR_RELEASE_ID,'v0.11.1-220fac89dd82cdcd');
39
41
  });
40
42
 
41
- test('R37 keeps the R36 capability surface contract while adding internal agent fabric',async()=>{
42
- const [parity,fabric,live]=await Promise.all([
43
- text('src/remote-mcp-r36-parity-client.mjs'),
44
- text('src/autonomous-runtime.mjs'),
45
- text('src/remote-live-log.mjs')
43
+ test('R38 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')]);
45
+ assert.match(cli,/controllerRuntimeReady/);
46
+ assert.match(cli,/Runtime already ONLINE; reusing verified bridge\/cloud\/supervisor/);
47
+ const start=controller.indexOf('function Recover-AutonomousSupervisor');
48
+ const end=controller.indexOf('function Show-State',start);
49
+ assert.ok(start>=0&&end>start,'supervisor recovery block missing');
50
+ const block=controller.slice(start,end);
51
+ assert.doesNotMatch(block,/\$host\s*=/i);
52
+ assert.match(block,/\$hostStatus\s*=\s*Get-HostArmStatus/);
53
+ });
54
+
55
+ test('sealed R37 tooling remains historical 0.11.1 authority',async()=>{
56
+ const [parity,gate,closure]=await Promise.all([
57
+ text('scripts/release-parity.mjs'),text('scripts/gate-windows.ps1'),text('scripts/final-closure.mjs')
46
58
  ]);
47
- assert.match(parity,/R36_EXPECTED_TOOLS\.length !== 76/);
48
- assert.match(parity,/R36_COMPACT_TOOL_LIMIT=42/);
49
- for(const name of ['deriveAgentMemory','effectIdentity','createWorkerScheduler','issueObservationLease']) assert.match(fabric,new RegExp(name));
50
- assert.match(live,/createLiveTimelineTracker/);
59
+ assert.match(parity,/R37_PREDECESSOR_RELEASE_ID='v0\.11\.0-08c2a0008b1f84c9'/);
60
+ assert.match(parity,/version==='0\.11\.1'|version:'0\.11\.1'/);
61
+ assert.match(gate,/DEADBYTE V0\.11\.1 \/ R37 WINDOWS BATCH GATE: PASS/);
62
+ assert.match(closure,/version:'0\.11\.1'/);
51
63
  });
@@ -2,12 +2,15 @@ import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import { createLiveTimelineTracker } from '../src/remote-live-log.mjs';
4
4
 
5
- test('R37 live timeline correlates RUN and result with stable short span id',()=>{
5
+ test('R37 live timeline renders sanitized tool-call detail and correlates terminal result with stable short span id',()=>{
6
6
  let now=1000;
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.equal(run,'▶ [abcdef12] RUN coding_file_read root=projects path=src/a.mjs');
10
+ assert.match(run,/^1970-01-01T00:00:01\.000Z \| coding_file_read\s+\| Arguments: \{/);
11
+ assert.match(run,/\"path\":\"src\/a\.mjs\"/);
12
+ assert.match(run,/\"reason\":\"payload\"/);
13
+ assert.match(run,/\"reason\":\"secret\"/);
11
14
  now=1250;
12
15
  const done=tracker.observe({event_type:'tool.result',tool:'coding_file_read',request_id:'abcdef1234567890',
13
16
  outcome:{is_error:false,duration_ms:250}});
@@ -11,16 +11,16 @@ const cliPath=path.join(root,'src','deadbyte-cli.mjs');
11
11
  const isWindows=process.platform==='win32';
12
12
  const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));
13
13
 
14
- async function fixture({failCommand=''}={}){
14
+ async function fixture({failCommand='',statusOnline=false}={}){
15
15
  const dir=await mkdtemp(path.join(os.tmpdir(),'deadbyte-remote-session-'));
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
19
  await mkdir(bin,{recursive:true});
20
20
  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 '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`;
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`;
22
22
  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}};
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'}};
24
24
  }
25
25
 
26
26
  async function traceCommands(file,{read=readFile,retryDelayMs=10,maxAttempts=20}={}){
@@ -65,15 +65,40 @@ async function collect(child){
65
65
 
66
66
  const winTest=isWindows?test:test.skip;
67
67
 
68
+ winTest('bare remote reuses a fully verified ONLINE runtime without invoking blocking start',async()=>{
69
+ const fx=await fixture({failCommand:'start',statusOnline:true});
70
+ let child=null;
71
+ try{
72
+ child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
73
+ const output=await collect(child);
74
+ const ready=await waitFor(fx.trace,commands=>commands.includes('hoststatus'),{timeoutMs:8000});
75
+ assert.deepEqual(ready.slice(0,8),[
76
+ 'status','armprocess','armcoding','armautonomous',
77
+ 'processstatus','codingstatus','autonomousstatus','hoststatus'
78
+ ]);
79
+ assert.doesNotMatch(ready.join(','),/(^|,)start(,|$)/);
80
+ assert.equal(child.exitCode,null,'remote session must remain foreground after reusing ONLINE runtime');
81
+ assert.match(output.stdout,/Runtime already ONLINE; reusing verified bridge\/cloud\/supervisor/);
82
+ const authDeadline=Date.now()+3000;
83
+ while(Date.now()<authDeadline&&!/🔐 \[AUTH\] ARMED: process, coding, autonomous \| host DISARMED/.test(output.stdout)) await sleep(50);
84
+ assert.match(output.stdout,/🔐 \[AUTH\] ARMED: process, coding, autonomous \| host DISARMED/);
85
+ child.kill('SIGINT');
86
+ await output.closed;
87
+ }finally{
88
+ if(child&&child.exitCode===null) child.kill('SIGKILL');
89
+ await rm(fx.dir,{recursive:true,force:true});
90
+ }
91
+ });
92
+
68
93
  winTest('bare remote uses one unified live timeline, keeps authority semantics, then disarms and parks when the foreground session ends',async()=>{
69
94
  const fx=await fixture();
70
95
  let child=null;
71
96
  try{
72
97
  child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
73
98
  const output=await collect(child);
74
- const ready=await waitFor(fx.trace,commands=>commands.slice(0,8).join(',')==='start,armprocess,armcoding,armautonomous,processstatus,codingstatus,autonomousstatus,hoststatus');
75
- assert.deepEqual(ready.slice(0,8),[
76
- 'start','armprocess','armcoding','armautonomous',
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',
77
102
  'processstatus','codingstatus','autonomousstatus','hoststatus'
78
103
  ]);
79
104
  assert.equal(child.exitCode,null,'remote session must remain foreground after becoming ready');
@@ -111,13 +136,14 @@ winTest('bare remote uses one unified live timeline, keeps authority semantics,
111
136
  ].join('\n')+'\n','utf8');
112
137
  const logDeadline=Date.now()+3000;
113
138
  while(Date.now()<logDeadline&&!/✗ \[fedcba98\] ERR coding_file_read 1\.73s/.test(output.stdout)) await sleep(50);
114
- assert.match(output.stdout,/▶ \[abcdef12\] RUN coding_tree root=projects path=src/);
115
- assert.match(output.stdout,/✓ \[abcdef12\] OK coding_tree 42ms \[cursor r1:[0-9a-f]{24}:1\]/);
116
- assert.match(output.stdout,/▶ \[fedcba98\] RUN coding_file_read root=projects path=src\/deadbyte-cli\.mjs/);
117
- assert.match(output.stdout,/✗ \[fedcba98\] ERR coding_file_read 1\.73s \[cursor r1:[0-9a-f]{24}:2\]/);
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);
140
+ 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);
142
+ assert.match(output.stdout,/✗ \[fedcba98\] ERR coding_file_read 1\.73s \[cursor r1:[0-9a-f]{24}:4\]/);
118
143
  assert.equal((output.stdout.match(/✓ \[abcdef12\] OK coding_tree 42ms/g)||[]).length,1,'duplicate terminal result must print once');
119
144
  const resultJournal=JSON.parse(await readFile(path.join(fx.state,'runtime','remote-results',`${marker.result_session_id}.json`),'utf8'));
120
- assert.deepEqual(resultJournal.events.map(event=>event.seq),[1,2]);
145
+ assert.deepEqual(resultJournal.events.map(event=>event.seq),[1,2,3,4]);
146
+ assert.deepEqual(resultJournal.events.map(event=>event.event_type),['tool.call','tool.result','tool.call','tool.result']);
121
147
  assert.equal(resultJournal.events[0].request_id,'abcdef1234567890');
122
148
  assert.ok(resultJournal.events.every(event=>/^[0-9a-f]{64}$/.test(event.payload_sha256)));
123
149
  assert.doesNotMatch(JSON.stringify(resultJournal),/TOOL IN|TOOL OUT|stdout_excerpt|stderr_excerpt/);
@@ -146,7 +172,7 @@ winTest('bare remote uses one unified live timeline, keeps authority semantics,
146
172
  }
147
173
  });
148
174
 
149
- winTest('remote --resume replays only terminal results after the cursor before starting a new live session',async()=>{
175
+ winTest('remote --resume replays sanitized tool-call and terminal result events after the cursor without duplicates or loss',async()=>{
150
176
  const fx=await fixture();
151
177
  let first=null,second=null;
152
178
  try{
@@ -157,14 +183,22 @@ winTest('remote --resume replays only terminal results after the cursor before s
157
183
  while(Date.now()<liveDeadline&&!/\[LOG\] Unified live timeline/.test(firstOutput.stdout)) await sleep(50);
158
184
  const auditDir=path.join(fx.state,'audit');await mkdir(auditDir,{recursive:true});
159
185
  const auditFile=path.join(auditDir,'segment-00000001.jsonl');
160
- await writeFile(auditFile,JSON.stringify({seq:1,event_type:'tool.result',tool:'coding_tree',request_id:'resume-request-1',outcome:{is_error:false}})+'\n','utf8');
186
+ const firstBatch=[
187
+ {seq:1,event_type:'tool.request',tool:'coding_tree',request_id:'resume-request-1',created_at_utc:'2026-09-18T16:30:00.000Z',args:{root_id:'projects',path:'src'}},
188
+ {seq:2,event_type:'tool.result',tool:'coding_tree',request_id:'resume-request-1',created_at_utc:'2026-09-18T16:30:00.100Z',outcome:{is_error:false}}
189
+ ];
190
+ await writeFile(auditFile,firstBatch.map(JSON.stringify).join('\n')+'\n','utf8');
161
191
  let deadline=Date.now()+3000;
162
- while(Date.now()<deadline&&!/coding_tree .*\[cursor r1:[0-9a-f]{24}:1\]/.test(firstOutput.stdout)) await sleep(50);
163
- const cursor1=firstOutput.stdout.match(/coding_tree .*\[cursor (r1:[0-9a-f]{24}:1)\]/)?.[1];
192
+ while(Date.now()<deadline&&!/coding_tree .*\[cursor r1:[0-9a-f]{24}:2\]/.test(firstOutput.stdout)) await sleep(50);
193
+ const cursor1=firstOutput.stdout.match(/coding_tree .*\[cursor (r1:[0-9a-f]{24}:2)\]/)?.[1];
164
194
  assert.ok(cursor1,'first result cursor missing');
165
- await writeFile(auditFile,JSON.stringify({seq:2,event_type:'tool.result',tool:'coding_file_read',request_id:'resume-request-2',outcome:{is_error:false}})+'\n',{encoding:'utf8',flag:'a'});
195
+ const secondBatch=[
196
+ {seq:3,event_type:'tool.request',tool:'coding_file_read',request_id:'resume-request-2',created_at_utc:'2026-09-18T16:30:01.000Z',args:{root_id:'projects',path:'src/deadbyte-cli.mjs',token:'DO_NOT_REPLAY_SECRET'}},
197
+ {seq:4,event_type:'tool.result',tool:'coding_file_read',request_id:'resume-request-2',created_at_utc:'2026-09-18T16:30:01.100Z',outcome:{is_error:false}}
198
+ ];
199
+ await writeFile(auditFile,secondBatch.map(JSON.stringify).join('\n')+'\n',{encoding:'utf8',flag:'a'});
166
200
  deadline=Date.now()+3000;
167
- while(Date.now()<deadline&&!/coding_file_read .*\[cursor r1:[0-9a-f]{24}:2\]/.test(firstOutput.stdout)) await sleep(50);
201
+ while(Date.now()<deadline&&!/coding_file_read .*\[cursor r1:[0-9a-f]{24}:4\]/.test(firstOutput.stdout)) await sleep(50);
168
202
  first.stdin.end();
169
203
  const firstEnded=await Promise.race([firstOutput.closed,sleep(6000).then(()=>({timeout:true}))]);
170
204
  assert.equal(firstEnded.timeout,undefined);
@@ -172,14 +206,20 @@ winTest('remote --resume replays only terminal results after the cursor before s
172
206
  second=spawn(process.execPath,[cliPath,'remote','--resume',cursor1],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
173
207
  const secondOutput=await collect(second);
174
208
  deadline=Date.now()+5000;
175
- while(Date.now()<deadline&&(!/\[REPLAY\] \[OK\] coding_file_read \[cursor r1:[0-9a-f]{24}:2\]/.test(secondOutput.stdout)||
209
+ while(Date.now()<deadline&&(!/coding_file_read\s+\| Arguments: .*REPLAY cursor r1:[0-9a-f]{24}:3/.test(secondOutput.stdout)||
210
+ !/\[REPLAY\] \[OK\] coding_file_read \[cursor r1:[0-9a-f]{24}:4\]/.test(secondOutput.stdout)||
176
211
  !/\[LOG\] Unified live timeline/.test(secondOutput.stdout))) await sleep(50);
177
- assert.match(secondOutput.stdout,/\[REPLAY\] \[OK\] coding_file_read \[cursor r1:[0-9a-f]{24}:2\]/);
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);
213
+ assert.match(secondOutput.stdout,/\[REPLAY\] \[OK\] coding_file_read \[cursor r1:[0-9a-f]{24}:4\]/);
178
214
  assert.match(secondOutput.stdout,/♻️ \[SESSION\] Previous result stream replayed/);
215
+ assert.doesNotMatch(secondOutput.stdout,/DO_NOT_REPLAY_SECRET/);
179
216
  assert.doesNotMatch(secondOutput.stdout,/\[REPLAY\] \[OK\] coding_tree/);
180
- const replayIndex=secondOutput.stdout.indexOf('[REPLAY]');
217
+ assert.equal((secondOutput.stdout.match(/\| coding_file_read\s+\| Arguments:/g)||[]).length,1,'tool-call replay duplicated');
218
+ assert.equal((secondOutput.stdout.match(/\[REPLAY\] \[OK\] coding_file_read/g)||[]).length,1,'terminal replay duplicated');
219
+ const callReplayIndex=secondOutput.stdout.indexOf('| coding_file_read');
220
+ const resultReplayIndex=secondOutput.stdout.indexOf('[REPLAY] [OK] coding_file_read');
181
221
  const liveIndex=secondOutput.stdout.indexOf('[LOG] Unified live timeline');
182
- assert.ok(replayIndex>=0&&liveIndex>replayIndex,'resume replay must happen before new live tail');
222
+ assert.ok(callReplayIndex>=0&&resultReplayIndex>callReplayIndex&&liveIndex>resultReplayIndex,'resume ordering must be call -> result -> live tail');
183
223
  second.stdin.end();
184
224
  const secondEnded=await Promise.race([secondOutput.closed,sleep(6000).then(()=>({timeout:true}))]);
185
225
  assert.equal(secondEnded.timeout,undefined);
@@ -210,8 +250,8 @@ winTest('detached guardian revokes authority, parks, and removes the session mar
210
250
  child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
211
251
  const output=await collect(child);
212
252
  const ready=await waitFor(fx.trace,commands=>commands.slice(0,8).join(',')==='start,armprocess,armcoding,armautonomous,processstatus,codingstatus,autonomousstatus,hoststatus');
213
- assert.deepEqual(ready.slice(0,8),[
214
- 'start','armprocess','armcoding','armautonomous',
253
+ assert.deepEqual(ready.slice(0,9),[
254
+ 'status','start','armprocess','armcoding','armautonomous',
215
255
  'processstatus','codingstatus','autonomousstatus','hoststatus'
216
256
  ]);
217
257
  const markerPath=path.join(fx.state,'runtime','remote-session.json');
@@ -254,7 +294,7 @@ winTest('bare remote rolls back authority and parks if one plane fails to arm',a
254
294
  assert.equal(ended.timeout,undefined,'failed startup did not terminate');
255
295
  assert.notEqual(ended.code,0);
256
296
  const commands=await traceCommands(fx.trace);
257
- assert.deepEqual(commands.slice(0,3),['start','armprocess','armcoding']);
297
+ assert.deepEqual(commands.slice(0,4),['status','start','armprocess','armcoding']);
258
298
  assert.deepEqual(commands.slice(-5),['disarmautonomous','disarmcoding','disarmprocess','disarmhost','park']);
259
299
  assert.doesNotMatch(output.stdout,/Live logs/i);
260
300
  }finally{await rm(fx.dir,{recursive:true,force:true});}
@@ -271,7 +311,8 @@ winTest('bare remote recovers a stale crashed session before arming a new one',a
271
311
  const output=await collect(child);
272
312
  const ready=await waitFor(fx.trace,commands=>commands.includes('hoststatus'));
273
313
  assert.deepEqual(ready.slice(0,5),['disarmautonomous','disarmcoding','disarmprocess','disarmhost','park']);
274
- assert.equal(ready[5],'start');
314
+ assert.equal(ready[5],'status');
315
+ assert.equal(ready[6],'start');
275
316
  assert.match(output.stdout,/♻️ \[RECOVERY\] Stale remote session pid=2147483000; revoking authority before restart\./);
276
317
  child.stdin.end();
277
318
  const ended=await Promise.race([output.closed,sleep(6000).then(()=>({timeout:true}))]);