deadbyte-mcp 0.15.44 → 0.15.46

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 (174) hide show
  1. package/MANIFEST.SHA256 +86 -138
  2. package/PROVENANCE.json +35 -18
  3. package/README.txt +22 -21
  4. package/RELEASE.json +369 -334
  5. package/SBOM.cdx.json +2 -2
  6. package/TEST-MATRIX.json +27 -17
  7. package/bridge/package.json +1 -1
  8. package/controller/deadbyte-controller.ps1 +1871 -1769
  9. package/controller/deadbyte-desktop-policy.json +6 -6
  10. package/controller/deadbyte-process-policy.json +4 -4
  11. package/docs/R68-COMPAT-HOST-EXEC-CANDIDATE.md +63 -0
  12. package/docs/R69-LIVE-OUTCOME-R70-POLICY-TRANSFER.md +136 -0
  13. package/docs/R70-CODING-DIGEST-SUPERVISOR-CHECKPOINT-20261013.md +42 -0
  14. package/docs/R70-FINITE-GRANT-OWNER-BOUNDARY-20261013.md +80 -0
  15. package/docs/R70-OWNER-BOOTSTRAP-CHECKPOINT-20261013.md +60 -0
  16. package/docs/R70-REFERENCE-MECHANISMS.json +95 -0
  17. package/docs/R70-TRUST-GUARD-EXPIRY-CHECKPOINT-20261013.md +47 -0
  18. package/package.json +2 -2
  19. package/scripts/benchmark-l0-r71.mjs +76 -0
  20. package/scripts/gate-windows-r71.ps1 +64 -0
  21. package/scripts/gate-windows-r72.ps1 +76 -0
  22. package/scripts/npm-release-r48.mjs +4 -0
  23. package/scripts/npm-release-readiness-r71.mjs +21 -0
  24. package/scripts/npm-release-readiness-r72.mjs +76 -0
  25. package/scripts/verify-r70-full-regression.ps1 +72 -0
  26. package/src/authority-continuity-r65.mjs +28 -8
  27. package/src/autonomous-mcp-tools.mjs +1 -1
  28. package/src/autonomous-output-contracts.mjs +4 -1
  29. package/src/autonomous-policy.mjs +54 -7
  30. package/src/capability-ledger.mjs +1 -1
  31. package/src/capability-resolver.mjs +2 -1
  32. package/src/commander-compat-runtime.mjs +30 -2
  33. package/src/deadbyte-cli.mjs +722 -719
  34. package/src/launcher-isolation.mjs +58 -0
  35. package/src/native-diff-v2.mjs +18 -5
  36. package/src/native-diff.mjs +21 -5
  37. package/src/r70-owner-approval.mjs +78 -0
  38. package/src/remote-authority.mjs +75 -75
  39. package/src/remote-live-log.mjs +48 -14
  40. package/src/remote-mcp-machine-smoke-client.mjs +84 -84
  41. package/src/remote-result-journal.mjs +1 -1
  42. package/src/runtime-update.mjs +232 -24
  43. package/src/staging-input-isolation.mjs +79 -0
  44. package/src/tool-audit.mjs +2 -0
  45. package/src/version.mjs +1 -1
  46. package/test/autonomous-local-supervisor.test.mjs +2 -1
  47. package/test/autonomous-output-contract.test.mjs +17 -1
  48. package/test/autonomous-supervisor-integration.test.mjs +2 -1
  49. package/test/capability-resolver.test.mjs +17 -0
  50. package/test/codex-autonomous-r44.test.mjs +1 -1
  51. package/test/commander-compat-runtime.test.mjs +42 -0
  52. package/test/controller-policy-preflight-r59.test.mjs +1 -0
  53. package/test/deferred-slot-operation-behavior.test.mjs +2 -2
  54. package/test/native-diff-topology-r36.test.mjs +35 -2
  55. package/test/native-diff.test.mjs +83 -3
  56. package/test/r58-cleanup-retention.test.mjs +3 -3
  57. package/test/r58-concurrent-recovery.test.mjs +3 -3
  58. package/test/r58-stale-owner.test.mjs +1 -1
  59. package/test/r59-tool-surface-compat.test.mjs +9 -5
  60. package/test/r60-authority-coherence.test.mjs +10 -2
  61. package/test/r65-authority-runtime-epoch.test.mjs +9 -1
  62. package/test/r67-isolated-slot-rollback-restore.test.mjs +2 -1
  63. package/test/r67-npm-publish-gate.test.mjs +4 -2
  64. package/test/r67-release-contract.test.mjs +8 -7
  65. package/test/r69-live-outcome.test.mjs +137 -0
  66. package/test/r70-autonomous-grant-expiry.test.mjs +89 -0
  67. package/test/r70-autonomous-policy-bootstrap.test.mjs +166 -0
  68. package/test/r70-controller-autonomous-root.test.mjs +104 -0
  69. package/test/r70-controller-grant-subset.test.mjs +28 -0
  70. package/test/r70-controller-owner-issue-boundary.test.mjs +80 -0
  71. package/test/r70-controller-policy-snapshot.test.mjs +66 -0
  72. package/test/r70-owner-approval.test.mjs +67 -0
  73. package/test/r71-full-verifier-artifact.test.mjs +28 -0
  74. package/test/r71-isolated-slot-rollback-restore.test.mjs +62 -0
  75. package/test/r71-native-diff-mcp-wire.test.mjs +75 -0
  76. package/test/r71-publish-fence.test.mjs +38 -0
  77. package/test/r71-release-identity.test.mjs +33 -0
  78. package/test/r72-launcher-isolation.test.mjs +99 -0
  79. package/test/r72-publication-fence.test.mjs +56 -0
  80. package/test/r72-publication-output-integrity.test.mjs +110 -0
  81. package/test/r72-remote-safe-contract.test.mjs +101 -0
  82. package/test/r72-staging-input-isolation.test.mjs +87 -0
  83. package/test/r72-staging-workspace-isolation.test.mjs +114 -0
  84. package/test/remote-result-journal.test.mjs +12 -0
  85. package/test/remote-session-cli.test.mjs +112 -65
  86. package/test/standing-grants.test.mjs +2 -2
  87. package/test/tool-audit.test.mjs +14 -0
  88. package/bin/appcontainer-stage.obj +0 -0
  89. package/bin/bootstrap-advapi32.obj +0 -0
  90. package/bin/bootstrap-exitcode.obj +0 -0
  91. package/bin/bootstrap-kernel32.obj +0 -0
  92. package/bin/child-control-probe.obj +0 -0
  93. package/bin/child-control-stage.obj +0 -0
  94. package/bin/contained-reverse-worker.obj +0 -0
  95. package/bin/contained-transform-worker.obj +0 -0
  96. package/bin/containment-probe.obj +0 -0
  97. package/bin/deadbyte-contain.obj +0 -0
  98. package/bin/deadbyte-desktop-input-r40.obj +0 -0
  99. package/bin/deadbyte-desktop-observer-r40.obj +0 -0
  100. package/bin/deadbyte-desktop-uia-r40.obj +0 -0
  101. package/bin/deadbyte-exec.obj +0 -0
  102. package/bin/deadbyte-hardware-observer-r45.obj +0 -0
  103. package/bin/deadbyte-native-inspect-r67.obj +0 -0
  104. package/bin/deadbyte-process-host.obj +0 -0
  105. package/bin/deadbyte-tunnel-host.obj +0 -0
  106. package/conpty-input-observer.obj +0 -0
  107. package/miniconpty.obj +0 -0
  108. package/proof/CONTAINMENT-BUILD.txt +0 -163
  109. package/proof/MCP-SMOKE-STATUS.txt +0 -9
  110. package/proof/NODE-SYNTAX.txt +0 -4
  111. package/proof/PROOF.txt +0 -6
  112. package/proof/R34-TASK8-SUPERVISOR-CHECKPOINT.json +0 -29
  113. package/proof/R34-TASK9-MCP-SURFACE-CHECKPOINT.json +0 -28
  114. package/proof/SECRET-SCAN.txt +0 -4
  115. package/proof/SOURCE-GATES.txt +0 -16
  116. package/proof/STATUS.txt +0 -11
  117. package/proof/TARGET-V0313-CONTAINMENT-PASS.sha256 +0 -1
  118. package/proof/TARGET-V0313-CONTAINMENT-PASS.txt +0 -215
  119. package/proof/TARGET-V040-CONTAINED-IPC-FAIL.sha256 +0 -1
  120. package/proof/TARGET-V040-CONTAINED-IPC-FAIL.txt +0 -299
  121. package/proof/TARGET-V041-CONTAINED-CREATEPROCESS-203.sha256 +0 -1
  122. package/proof/TARGET-V041-CONTAINED-CREATEPROCESS-203.txt +0 -311
  123. package/proof/TARGET-V042-CONTAINED-CREATEPROCESS-203.sha256 +0 -1
  124. package/proof/TARGET-V042-CONTAINED-CREATEPROCESS-203.txt +0 -313
  125. package/proof/TARGET-V043-CONTAINED-CREATEPROCESS-203.sha256 +0 -1
  126. package/proof/TARGET-V043-CONTAINED-CREATEPROCESS-203.txt +0 -308
  127. package/proof/TARGET-V044-CONTAINED-PASS.sha256 +0 -1
  128. package/proof/TARGET-V044-CONTAINED-PASS.txt +0 -432
  129. package/proof/TARGET-V045-DUAL-OPERATION-PASS.sha256 +0 -1
  130. package/proof/TARGET-V045-DUAL-OPERATION-PASS.txt +0 -481
  131. package/proof/TARGET-V046-FIXED-EXECUTABLE-REGISTRY-PASS.sha256 +0 -1
  132. package/proof/TARGET-V046-FIXED-EXECUTABLE-REGISTRY-PASS.txt +0 -610
  133. package/proof/TARGET-V047-RUNTIME-MANIFEST-PASS.sha256 +0 -1
  134. package/proof/TARGET-V047-RUNTIME-MANIFEST-PASS.txt +0 -642
  135. package/proof/TARGET-V050-BATCH-GATE-PASS.sha256 +0 -1
  136. package/proof/TARGET-V050-BATCH-GATE-PASS.txt +0 -713
  137. package/proof/TESTS.txt +0 -686
  138. package/proof/TRUST-EPHEMERAL.txt +0 -4
  139. package/proof/V03-FREEZE.txt +0 -27
  140. package/proof/V041-IPC-HOTFIX.txt +0 -16
  141. package/proof/V042-ENV-HOTFIX.txt +0 -15
  142. package/proof/V043-DRIVE-CWD-HOTFIX.txt +0 -14
  143. package/proof/V044-LOCALAPPDATA-HOTFIX.txt +0 -18
  144. package/proof/V045-OPERATION-REGISTRY.txt +0 -7
  145. package/proof/V046-WORKER-REGISTRY.txt +0 -12
  146. package/proof/V047-WORKER-MANIFEST.txt +0 -18
  147. package/proof/V050-BATCH-TRUST-CLOSURE.txt +0 -21
  148. package/proof/V060-ACTIVE-NETWORK-AUTHORITY.txt +0 -29
  149. package/proof/V070-NODE-SYNTAX.txt +0 -36
  150. package/proof/V070-NODE-TESTS.txt +0 -752
  151. package/proof/V070-PACK-DRY-RUN.txt +0 -126
  152. package/proof/V070-SOURCE-GATE.txt +0 -30
  153. package/proof/V070-STATIC-SCAN.txt +0 -4
  154. package/proof/V070-WINDOWS-GATE-PENDING.txt +0 -25
  155. package/proof/V071-NODE-SYNTAX.txt +0 -1
  156. package/proof/V071-NODE-TESTS.txt +0 -796
  157. package/proof/V071-PACK-DRY-RUN.json +0 -656
  158. package/proof/V071-SOURCE-GATE.txt +0 -16
  159. package/proof/V071-WINDOWS-GATE-PENDING.txt +0 -24
  160. package/proof/V073-NODE-SYNTAX.txt +0 -4
  161. package/proof/V073-SOURCE-GATE.txt +0 -21
  162. package/proof/V073-STATIC-SCAN.txt +0 -10
  163. package/proof/V073-WINDOWS-GATE-PENDING.txt +0 -5
  164. package/proof/VERIFY.txt +0 -7
  165. package/proof/WINDOWS-CONTAINED-STATUS.txt +0 -5
  166. package/proof/WINDOWS-CONTAINMENT-STATUS.txt +0 -3
  167. package/proof/commander-closure-20260927/CONTINUATION.json +0 -43
  168. package/proof/commander-closure-20260927/RESULT.json +0 -30
  169. package/proof/commander-closure-20260927/SEARCH-CONTINUATION.json +0 -30
  170. package/proof/commander-closure-20260927/XLS-REFERENCE-PROBE.json +0 -13
  171. package/proof/commander-closure-20260928/DIFFERENTIAL-CHECKPOINT.json +0 -122
  172. package/proof/r59-full-regression-current.json +0 -13
  173. package/proof/r59-full-regression-current.stderr.log +0 -0
  174. package/proof/r59-full-regression-current.stdout.log +0 -1268
@@ -12,6 +12,15 @@ const root=path.resolve(fileURLToPath(new URL('..',import.meta.url)));
12
12
  const cliPath=path.join(root,'src','deadbyte-cli.mjs');
13
13
  const isWindows=process.platform==='win32';
14
14
  const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));
15
+ const fixtureTimeoutMs=30000;
16
+ async function boundedCompletion(promise,timeoutMs=fixtureTimeoutMs){
17
+ let timer;
18
+ try{return await Promise.race([promise,new Promise(resolve=>{
19
+ timer=setTimeout(()=>resolve({timeout:true}),timeoutMs);
20
+ timer.unref?.();
21
+ })]);}
22
+ finally{clearTimeout(timer);}
23
+ }
15
24
 
16
25
  async function fixture({failCommand='',statusOnline=false}={}){
17
26
  const dir=await mkdtemp(path.join(os.tmpdir(),'deadbyte-remote-session-'));
@@ -45,7 +54,7 @@ async function traceCommands(file,{read=readFile,retryDelayMs=10,maxAttempts=20}
45
54
  }
46
55
  return [];
47
56
  }
48
- async function waitFor(file,predicate,{timeoutMs=12000}={}){
57
+ async function waitFor(file,predicate,{timeoutMs=fixtureTimeoutMs}={}){
49
58
  const deadline=Date.now()+timeoutMs;
50
59
  while(Date.now()<deadline){
51
60
  const commands=await traceCommands(file);
@@ -73,6 +82,17 @@ async function collect(child){
73
82
  const closed=new Promise(resolve=>child.once('close',(code,signal)=>resolve({code,signal})));
74
83
  return {closed,get stdout(){return stdout;},get stderr(){return stderr;}};
75
84
  }
85
+ // Windows: SIGKILL leaves PowerShell child holding a handle on the .ps1 fixture
86
+ // for a short window; retry rm() until it succeeds or gives up.
87
+ async function safeRm(dir,{maxAttempts=10,retryDelayMs=200}={}){
88
+ for(let i=0;i<maxAttempts;i++){
89
+ try{await rm(dir,{recursive:true,force:true});return;}
90
+ catch(err){
91
+ if(err?.code==='EBUSY'&&i<maxAttempts-1){await sleep(retryDelayMs);continue;}
92
+ throw err;
93
+ }
94
+ }
95
+ }
76
96
 
77
97
  const winTest=isWindows?test:test.skip;
78
98
 
@@ -80,14 +100,14 @@ winTest('bare remote reuses a fully verified ONLINE runtime without invoking blo
80
100
  const fx=await fixture({failCommand:'start',statusOnline:true});
81
101
  let child=null;
82
102
  try{
83
- child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
103
+ child=spawn(process.execPath,[cliPath,'remote','--operator'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
84
104
  const output=await collect(child);
85
- const ready=await waitFor(fx.trace,commands=>commands.filter(x=>x==='status').length>=3,{timeoutMs:8000});
105
+ const ready=await waitFor(fx.trace,commands=>commands.filter(x=>x==='status').length>=3,{timeoutMs:fixtureTimeoutMs});
86
106
  assert.deepEqual(ready.slice(0,6),['status','status','armprocess','armcoding','armautonomous','status'],output.stderr);
87
107
  assert.doesNotMatch(ready.join(','),/(^|,)start(,|$)/);
88
108
  assert.equal(child.exitCode,null,'remote session must remain foreground after reusing ONLINE runtime');
89
109
  assert.match(output.stdout,/Runtime already ONLINE; reusing verified bridge\/cloud\/supervisor/);
90
- const authDeadline=Date.now()+3000;
110
+ const authDeadline=Date.now()+fixtureTimeoutMs;
91
111
  while(Date.now()<authDeadline&&!/\[AUTH\] process ARMED \| coding ARMED \| autonomous ARMED \| desktop DISARMED \| host DISARMED/.test(output.stdout)) await sleep(50);
92
112
  assert.match(output.stdout,/\[DISPLAY\] ASCII fallback: stdout_not_tty/);
93
113
  assert.match(output.stdout,/\[AUTH\] process ARMED \| coding ARMED \| autonomous ARMED \| desktop DISARMED \| host DISARMED/);
@@ -95,7 +115,31 @@ winTest('bare remote reuses a fully verified ONLINE runtime without invoking blo
95
115
  await output.closed;
96
116
  }finally{
97
117
  if(child&&child.exitCode===null) child.kill('SIGKILL');
98
- await rm(fx.dir,{recursive:true,force:true});
118
+ await safeRm(fx.dir);
119
+ }
120
+ });
121
+
122
+ winTest('R72 bare remote reaches READY with every authority disarmed and never arms a plane',async()=>{
123
+ const fx=await fixture({statusOnline:true});
124
+ let child=null;
125
+ try{
126
+ child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
127
+ const output=await collect(child);
128
+ const deadline=Date.now()+fixtureTimeoutMs;
129
+ while(Date.now()<deadline&&!/\[READY\]/.test(output.stdout)&&child.exitCode===null)await sleep(50);
130
+ assert.match(output.stdout,/\[READY\]/,output.stderr);
131
+ assert.match(output.stdout,/\[AUTH\] process DISARMED \| coding DISARMED \| autonomous DISARMED \| desktop DISARMED \| host DISARMED/);
132
+ const before=await traceCommands(fx.trace);
133
+ assert.deepEqual(before.slice(0,6),['status','status','disarmautonomous','disarmcoding','disarmprocess','status']);
134
+ assert.equal(before.filter(x=>/^arm(?:process|coding|autonomous|host|desktop)$/.test(x)).length,0,'bare remote must issue zero ARM commands');
135
+ child.stdin.end();
136
+ const ended=await boundedCompletion(output.closed);
137
+ assert.equal(ended.timeout,undefined,'bare remote did not stop');
138
+ assert.equal(ended.code,0,output.stderr);
139
+ assert.equal((await traceCommands(fx.trace)).at(-1),'park');
140
+ }finally{
141
+ if(child?.exitCode===null)child.kill('SIGKILL');
142
+ await safeRm(fx.dir);
99
143
  }
100
144
  });
101
145
 
@@ -106,16 +150,16 @@ winTest('bounded remote disarms a stale standing Host grant before READY',async(
106
150
  try{
107
151
  child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
108
152
  const output=await collect(child);
109
- const commands=await waitFor(fx.trace,items=>items.filter(x=>x==='status').length>=3,{timeoutMs:8000});
153
+ const commands=await waitFor(fx.trace,items=>items.filter(x=>x==='status').length>=3,{timeoutMs:fixtureTimeoutMs});
110
154
  assert.ok(commands.indexOf('disarmhost')>commands.indexOf('status'));
111
- const deadline=Date.now()+3000;
155
+ const deadline=Date.now()+fixtureTimeoutMs;
112
156
  while(Date.now()<deadline&&!/\[READY\]/.test(output.stdout)) await sleep(50);
113
157
  assert.match(output.stdout,/\[READY\]/,output.stderr);
114
158
  child.stdin.end();
115
159
  assert.equal((await output.closed).code,0,output.stderr);
116
160
  }finally{
117
161
  if(child&&child.exitCode===null) child.kill('SIGKILL');
118
- await rm(fx.dir,{recursive:true,force:true});
162
+ await safeRm(fx.dir);
119
163
  }
120
164
  });
121
165
 
@@ -125,7 +169,7 @@ winTest('remote --full verifies all five planes before READY and revokes them on
125
169
  try{
126
170
  child=spawn(process.execPath,[cliPath,'remote','--full'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
127
171
  const output=await collect(child);
128
- const deadline=Date.now()+8000;
172
+ const deadline=Date.now()+fixtureTimeoutMs;
129
173
  while(Date.now()<deadline&&!/\[READY\]/.test(output.stdout)) await sleep(50);
130
174
  assert.match(output.stdout,/\[AUTH\] process ARMED \| coding ARMED \| autonomous ARMED \| desktop ARMED \| host ARMED/,output.stderr);
131
175
  assert.match(output.stdout,/\[READY\]/);
@@ -137,7 +181,7 @@ winTest('remote --full verifies all five planes before READY and revokes them on
137
181
  assert.deepEqual(after.slice(-8),['disarmautonomous','disarmcoding','disarmprocess','disarmdesktop','disarmhost','status','machinetest','park']);
138
182
  }finally{
139
183
  if(child?.exitCode===null) child.kill('SIGKILL');
140
- await rm(fx.dir,{recursive:true,force:true});
184
+ await safeRm(fx.dir);
141
185
  }
142
186
  });
143
187
 
@@ -148,7 +192,7 @@ for(const [flag,armedPlane,disarmedPlane] of [['--desktop','desktop','host'],['-
148
192
  try{
149
193
  child=spawn(process.execPath,[cliPath,'remote',flag],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
150
194
  const output=await collect(child);
151
- const deadline=Date.now()+8000;
195
+ const deadline=Date.now()+fixtureTimeoutMs;
152
196
  while(Date.now()<deadline&&!/\[READY\]/.test(output.stdout)) await sleep(50);
153
197
  assert.match(output.stdout,/\[READY\]/,output.stderr);
154
198
  assert.match(output.stdout,new RegExp(`${armedPlane} ARMED`));
@@ -160,7 +204,7 @@ for(const [flag,armedPlane,disarmedPlane] of [['--desktop','desktop','host'],['-
160
204
  assert.equal((await output.closed).code,0,output.stderr);
161
205
  }finally{
162
206
  if(child?.exitCode===null) child.kill('SIGKILL');
163
- await rm(fx.dir,{recursive:true,force:true});
207
+ await safeRm(fx.dir);
164
208
  }
165
209
  });
166
210
  }
@@ -173,7 +217,7 @@ winTest('conflicting remote authority modes fail before controller mutation',asy
173
217
  assert.notEqual((await output.closed).code,0);
174
218
  assert.match(output.stderr,/mutually exclusive/);
175
219
  assert.deepEqual(await traceCommands(fx.trace),[]);
176
- }finally{await rm(fx.dir,{recursive:true,force:true});}
220
+ }finally{await safeRm(fx.dir);}
177
221
  });
178
222
 
179
223
  winTest('remote refuses READY when public signed MCP execution probe fails',async()=>{
@@ -182,14 +226,14 @@ winTest('remote refuses READY when public signed MCP execution probe fails',asyn
182
226
  try{
183
227
  child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
184
228
  const output=await collect(child);
185
- const ended=await Promise.race([output.closed,sleep(12000).then(()=>({timeout:true}))]);
229
+ const ended=await boundedCompletion(output.closed);
186
230
  assert.equal(ended.timeout,undefined,'remote did not fail closed after execution probe failure');
187
231
  assert.notEqual(ended.code,0);
188
232
  assert.doesNotMatch(output.stdout,/\[READY\]|\[OK\] ONLINE/);
189
233
  assert.match(output.stderr,/machinetest|execution probe/i);
190
234
  }finally{
191
235
  if(child?.exitCode===null) child.kill('SIGKILL');
192
- await rm(fx.dir,{recursive:true,force:true});
236
+ await safeRm(fx.dir);
193
237
  }
194
238
  });
195
239
 
@@ -201,14 +245,14 @@ winTest('remote refuses READY when controller snapshot lies about Host enforceme
201
245
  try{
202
246
  child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
203
247
  const output=await collect(child);
204
- const ended=await Promise.race([output.closed,sleep(12000).then(()=>({timeout:true}))]);
248
+ const ended=await boundedCompletion(output.closed);
205
249
  assert.equal(ended.timeout,undefined,`remote did not reject split authority truth; stdout=${output.stdout.slice(-1200)} stderr=${output.stderr.slice(-1200)} trace=${(await traceCommands(fx.trace)).join(',')}`);
206
250
  assert.notEqual(ended.code,0);
207
251
  assert.doesNotMatch(output.stdout,/\[READY\]|\[OK\] ONLINE/);
208
252
  assert.match(output.stderr,/machinetest|enforcement/i);
209
253
  }finally{
210
254
  if(child?.exitCode===null) child.kill('SIGKILL');
211
- await rm(fx.dir,{recursive:true,force:true});
255
+ await safeRm(fx.dir);
212
256
  }
213
257
  });
214
258
 
@@ -220,7 +264,7 @@ winTest('foreground cleanup retains ownership when status lies about a no-op Hos
220
264
  try{
221
265
  child=spawn(process.execPath,[cliPath,'remote','--full'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
222
266
  const output=await collect(child);
223
- const deadline=Date.now()+8000;
267
+ const deadline=Date.now()+fixtureTimeoutMs;
224
268
  while(Date.now()<deadline&&!/\[READY\]/.test(output.stdout)) await sleep(50);
225
269
  assert.match(output.stdout,/\[READY\]/,output.stderr);
226
270
  child.stdin.end();
@@ -230,7 +274,7 @@ winTest('foreground cleanup retains ownership when status lies about a no-op Hos
230
274
  assert.ok(!(await traceCommands(fx.trace)).includes('park'));
231
275
  }finally{
232
276
  if(child?.exitCode===null) child.kill('SIGKILL');
233
- await rm(fx.dir,{recursive:true,force:true});
277
+ await safeRm(fx.dir);
234
278
  }
235
279
  });
236
280
 
@@ -240,26 +284,28 @@ winTest('bare remote PARKED startup does not wait for a long-lived child holding
240
284
  let child=null;
241
285
  try{
242
286
  const startedAt=Date.now();
243
- child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
287
+ child=spawn(process.execPath,[cliPath,'remote','--operator'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
244
288
  const output=await collect(child);
245
- const ready=await waitFor(fx.trace,commands=>commands.filter(x=>x==='status').length>=4,{timeoutMs:8000});
289
+ const afterStart=await waitFor(fx.trace,commands=>commands.length>=3,{timeoutMs:15000});
246
290
  const elapsed=Date.now()-startedAt;
291
+ assert.deepEqual(afterStart.slice(0,3),['status','start','status']);
292
+ assert.ok(elapsed<12000,`PARKED startup waited on inherited child pipe handles: ${elapsed}ms`);
293
+ const ready=await waitFor(fx.trace,commands=>commands.filter(x=>x==='status').length>=4,{timeoutMs:fixtureTimeoutMs});
247
294
  assert.deepEqual(ready.slice(0,8),['status','start','status','status','armprocess','armcoding','armautonomous','status']);
248
- assert.ok(elapsed<7000,`PARKED startup waited on inherited child pipe handles: ${elapsed}ms`);
249
295
  assert.equal(child.exitCode,null,'remote session must remain foreground after PARKED startup');
250
296
  assert.match(output.stdout,/\[BOOT\] Starting bridge\/runtime\.\.\./);
251
- const readyDeadline=Date.now()+3000;
297
+ const readyDeadline=Date.now()+fixtureTimeoutMs;
252
298
  while(Date.now()<readyDeadline&&!/\[OK\] ONLINE/.test(output.stdout)) await sleep(50);
253
299
  assert.match(output.stdout,/\[OK\] ONLINE/);
254
300
  child.stdin.end();
255
- const ended=await Promise.race([output.closed,sleep(6000).then(()=>({timeout:true}))]);
301
+ const ended=await boundedCompletion(output.closed);
256
302
  assert.equal(ended.timeout,undefined,'remote session did not exit after PARKED startup proof');
257
303
  assert.equal(ended.code,0,output.stderr);
258
304
  }finally{
259
305
  if(child?.exitCode===null) child.kill('SIGKILL');
260
306
  try{const pid=Number((await readFile(fx.spawnedPid,'utf8')).trim());if(Number.isInteger(pid)&&pid>0) process.kill(pid,'SIGKILL');}catch{}
261
307
  await sleep(100);
262
- await rm(fx.dir,{recursive:true,force:true});
308
+ await safeRm(fx.dir);
263
309
  }
264
310
  });
265
311
 
@@ -267,13 +313,14 @@ winTest('bare remote uses one unified live timeline, keeps authority semantics,
267
313
  const fx=await fixture();
268
314
  let child=null;
269
315
  try{
270
- child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
316
+ child=spawn(process.execPath,[cliPath,'remote','--operator'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
271
317
  const output=await collect(child);
272
318
  const ready=await waitFor(fx.trace,commands=>commands.filter(x=>x==='status').length>=4);
273
319
  assert.deepEqual(ready.slice(0,8),['status','start','status','status','armprocess','armcoding','armautonomous','status']);
274
320
  assert.equal(child.exitCode,null,'remote session must remain foreground after becoming ready');
275
- const tailDeadline=Date.now()+3000;
276
- while(Date.now()<tailDeadline&&!/\[AUTH\] process ARMED \| coding ARMED \| autonomous ARMED \| desktop DISARMED \| host DISARMED/.test(output.stdout)) await sleep(50);
321
+ const tailDeadline=Date.now()+fixtureTimeoutMs;
322
+ while(Date.now()<tailDeadline&&(!/\[AUTH\] process ARMED \| coding ARMED \| autonomous ARMED \| desktop DISARMED \| host DISARMED/.test(output.stdout)||
323
+ !/\[READY\] DEADBYTE MCP online/.test(output.stdout))) await sleep(50);
277
324
  assert.match(output.stdout,/\[DISPLAY\] ASCII fallback: stdout_not_tty/);
278
325
  assert.match(output.stdout,/\[DEVICE\] Starting DEADBYTE MCP/);
279
326
  assert.match(output.stdout,/\[BRIDGE\] Local bridge connected/);
@@ -305,7 +352,7 @@ winTest('bare remote uses one unified live timeline, keeps authority semantics,
305
352
  '[TOOL OUT] 2026-09-16T00:00:00.001Z #000001 coding_tree {"is_error":false}',
306
353
  '[TOOL OUT] 2026-09-16T00:00:00.002Z #000002 coding_file_read {"is_error":true}'
307
354
  ].join('\n')+'\n','utf8');
308
- const logDeadline=Date.now()+3000;
355
+ const logDeadline=Date.now()+fixtureTimeoutMs;
309
356
  while(Date.now()<logDeadline&&!/^R .*#4 \[fedcba98\] coding_file_read projects:src\/deadbyte-cli\.mjs 1\.73s \[SLOW\] ERR$/m.test(output.stdout)) await sleep(50);
310
357
  assert.doesNotMatch(output.stdout,/\| Arguments:/,'default human view must not print request JSON');
311
358
  assert.match(output.stdout,/^S .*#2 \[abcdef12\] coding_tree projects:src 42ms OK$/m);
@@ -325,7 +372,7 @@ winTest('bare remote uses one unified live timeline, keeps authority semantics,
325
372
  assert.doesNotMatch(output.stdout,/\[TOOL IN \]|\[TOOL OUT\]/);
326
373
  assert.doesNotMatch(output.stdout,/payload bytes=/);
327
374
  child.stdin.end();
328
- const ended=await Promise.race([output.closed,sleep(6000).then(()=>({timeout:true}))]);
375
+ const ended=await boundedCompletion(output.closed);
329
376
  assert.equal(ended.timeout,undefined,'remote session did not exit after foreground input closed');
330
377
  const commands=await traceCommands(fx.trace);
331
378
  assert.deepEqual(commands.slice(-8),['disarmautonomous','disarmcoding','disarmprocess','disarmdesktop','disarmhost','status','machinetest','park']);
@@ -336,7 +383,7 @@ winTest('bare remote uses one unified live timeline, keeps authority semantics,
336
383
  assert.doesNotMatch(output.stdout,/\p{Extended_Pictographic}/u,'piped Windows fallback must remain ASCII-safe');
337
384
  }finally{
338
385
  if(child?.exitCode===null) child.kill();
339
- await rm(fx.dir,{recursive:true,force:true});
386
+ await safeRm(fx.dir);
340
387
  }
341
388
  });
342
389
 
@@ -373,7 +420,7 @@ winTest('remote --resume replays sanitized tool-call and terminal result events
373
420
  deadline=Date.now()+3000;
374
421
  while(Date.now()<deadline&&!/^R .*#4 \[resume-r\] coding_file_read projects:src\/deadbyte-cli\.mjs.*OK$/m.test(firstOutput.stdout)) await sleep(50);
375
422
  first.stdin.end();
376
- const firstEnded=await Promise.race([firstOutput.closed,sleep(6000).then(()=>({timeout:true}))]);
423
+ const firstEnded=await boundedCompletion(firstOutput.closed);
377
424
  assert.equal(firstEnded.timeout,undefined);
378
425
 
379
426
  second=spawn(process.execPath,[cliPath,'remote','--resume',cursor1],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
@@ -394,12 +441,12 @@ winTest('remote --resume replays sanitized tool-call and terminal result events
394
441
  const liveIndex=secondOutput.stdout.indexOf('[LOG] Human live timeline');
395
442
  assert.ok(callReplayIndex>=0&&resultReplayIndex>callReplayIndex&&liveIndex>resultReplayIndex,'resume ordering must be call -> result -> live tail');
396
443
  second.stdin.end();
397
- const secondEnded=await Promise.race([secondOutput.closed,sleep(12000).then(()=>({timeout:true}))]);
444
+ const secondEnded=await boundedCompletion(secondOutput.closed);
398
445
  assert.equal(secondEnded.timeout,undefined);
399
446
  assert.equal(secondEnded.code,0,secondOutput.stderr);
400
447
  }finally{
401
448
  if(first?.exitCode===null) first.kill();if(second?.exitCode===null) second.kill();
402
- await rm(fx.dir,{recursive:true,force:true});
449
+ await safeRm(fx.dir);
403
450
  }
404
451
  });
405
452
 
@@ -423,14 +470,14 @@ winTest('remote --verbose enables sanitized request detail while preserving fore
423
470
  assert.match(output.stdout,/coding_tree\s+\| Arguments: .*"path":"src".*"root_id":"projects"/);
424
471
  assert.doesNotMatch(output.stdout,/DO_NOT_PRINT_VERBOSE_SECRET/);
425
472
  child.stdin.end();
426
- const ended=await Promise.race([output.closed,sleep(6000).then(()=>({timeout:true}))]);
473
+ const ended=await boundedCompletion(output.closed);
427
474
  assert.equal(ended.timeout,undefined);
428
475
  assert.equal(ended.code,0,output.stderr);
429
476
  const commands=await traceCommands(fx.trace);
430
477
  assert.deepEqual(commands.slice(-8),['disarmautonomous','disarmcoding','disarmprocess','disarmdesktop','disarmhost','status','machinetest','park']);
431
478
  }finally{
432
479
  if(child?.exitCode===null) child.kill('SIGKILL');
433
- await rm(fx.dir,{recursive:true,force:true});
480
+ await safeRm(fx.dir);
434
481
  }
435
482
  });
436
483
 
@@ -438,7 +485,7 @@ winTest('detached guardian revokes authority, parks, and removes the session mar
438
485
  const fx=await fixture();
439
486
  let child=null;
440
487
  try{
441
- child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
488
+ child=spawn(process.execPath,[cliPath,'remote','--operator'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
442
489
  const output=await collect(child);
443
490
  const ready=await waitFor(fx.trace,commands=>commands.filter(x=>x==='status').length>=4);
444
491
  assert.deepEqual(ready.slice(0,8),['status','start','status','status','armprocess','armcoding','armautonomous','status']);
@@ -469,7 +516,7 @@ winTest('detached guardian revokes authority, parks, and removes the session mar
469
516
  assert.equal(markerGone,true,'guardian left stale remote-session marker after hard kill');
470
517
  }finally{
471
518
  if(child?.exitCode===null) child.kill();
472
- await rm(fx.dir,{recursive:true,force:true});
519
+ await safeRm(fx.dir);
473
520
  }
474
521
  });
475
522
 
@@ -480,12 +527,12 @@ winTest('guardian retains ownership marker when disarm exits zero but Host remai
480
527
  try{
481
528
  child=spawn(process.execPath,[cliPath,'remote','--full'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
482
529
  const output=await collect(child);
483
- const deadline=Date.now()+8000;
530
+ const deadline=Date.now()+fixtureTimeoutMs;
484
531
  while(Date.now()<deadline&&!/\[READY\]/.test(output.stdout)) await sleep(50);
485
532
  assert.match(output.stdout,/\[READY\]/,output.stderr);
486
533
  child.kill('SIGKILL');
487
534
  await output.closed;
488
- await waitFor(fx.trace,commands=>commands.includes('disarmhost'),{timeoutMs:8000});
535
+ await waitFor(fx.trace,commands=>commands.includes('disarmhost'),{timeoutMs:fixtureTimeoutMs});
489
536
  await sleep(750);
490
537
  const marker=JSON.parse(await readFile(path.join(fx.state,'runtime','remote-session.json'),'utf8'));
491
538
  assert.equal(marker.schema,'deadbyte.remote-session.v2');
@@ -493,23 +540,23 @@ winTest('guardian retains ownership marker when disarm exits zero but Host remai
493
540
  assert.ok(!commands.includes('park'),'guardian must not park after unverified revocation');
494
541
  }finally{
495
542
  if(child?.exitCode===null) child.kill('SIGKILL');
496
- await rm(fx.dir,{recursive:true,force:true});
543
+ await safeRm(fx.dir);
497
544
  }
498
545
  });
499
546
 
500
547
  winTest('bare remote rolls back authority and parks if one plane fails to arm',async()=>{
501
548
  const fx=await fixture({failCommand:'armcoding'});
502
549
  try{
503
- const child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['ignore','pipe','pipe'],windowsHide:true});
550
+ const child=spawn(process.execPath,[cliPath,'remote','--operator'],{env:fx.env,stdio:['ignore','pipe','pipe'],windowsHide:true});
504
551
  const output=await collect(child);
505
- const ended=await Promise.race([output.closed,sleep(12000).then(()=>({timeout:true}))]);
552
+ const ended=await boundedCompletion(output.closed);
506
553
  assert.equal(ended.timeout,undefined,`failed startup did not terminate; stdout=${output.stdout.slice(-1200)} stderr=${output.stderr.slice(-1200)} trace=${(await traceCommands(fx.trace)).join(',')}`);
507
554
  assert.notEqual(ended.code,0);
508
555
  const commands=await traceCommands(fx.trace);
509
556
  assert.deepEqual(commands.slice(0,6),['status','start','status','status','armprocess','armcoding']);
510
557
  assert.deepEqual(commands.slice(-8),['disarmautonomous','disarmcoding','disarmprocess','disarmdesktop','disarmhost','status','machinetest','park']);
511
558
  assert.doesNotMatch(output.stdout,/Live logs/i);
512
- }finally{await rm(fx.dir,{recursive:true,force:true});}
559
+ }finally{await safeRm(fx.dir);}
513
560
  });
514
561
 
515
562
  winTest('bare remote recovers a stale crashed session before arming a new one',async()=>{
@@ -521,18 +568,18 @@ winTest('bare remote recovers a stale crashed session before arming a new one',a
521
568
  await writeFile(path.join(runtime,'remote-session.json'),JSON.stringify({schema:'deadbyte.remote-session.v1',pid:2147483000,started_at_utc:'2026-01-01T00:00:00.000Z'}),'utf8');
522
569
  child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
523
570
  const output=await collect(child);
524
- const ready=await waitFor(fx.trace,commands=>commands.filter(x=>x==='status').length>=5);
571
+ const ready=await waitFor(fx.trace,commands=>commands.length>=10&&commands[9]==='start');
525
572
  assert.deepEqual(ready.slice(0,8),['disarmautonomous','disarmcoding','disarmprocess','disarmdesktop','disarmhost','status','machinetest','park']);
526
573
  assert.equal(ready[8],'status');
527
574
  assert.equal(ready[9],'start');
528
575
  assert.match(output.stdout,/\[RECOVERY\] Stale remote session pid=2147483000; revoking authority before restart\./);
529
576
  child.stdin.end();
530
- const ended=await Promise.race([output.closed,sleep(6000).then(()=>({timeout:true}))]);
577
+ const ended=await boundedCompletion(output.closed);
531
578
  assert.equal(ended.timeout,undefined);
532
579
  assert.equal(ended.code,0,output.stderr);
533
580
  }finally{
534
581
  if(child?.exitCode===null) child.kill();
535
- await rm(fx.dir,{recursive:true,force:true});
582
+ await safeRm(fx.dir);
536
583
  }
537
584
  });
538
585
 
@@ -546,13 +593,13 @@ winTest('remote warning lines use deterministic ASCII fallback on piped Windows
546
593
  const markerPath=path.join(fx.state,'runtime','remote-session.json');
547
594
  await writeFile(markerPath,'{invalid-json\n','utf8');
548
595
  child.stdin.end();
549
- const ended=await Promise.race([output.closed,sleep(6000).then(()=>({timeout:true}))]);
596
+ const ended=await boundedCompletion(output.closed);
550
597
  assert.equal(ended.timeout,undefined,'remote session did not exit after warning fixture');
551
598
  assert.match(output.stderr,/^\[WARN\] remote session marker cleanup:/m);
552
599
  assert.doesNotMatch(output.stderr,/\p{Extended_Pictographic}/u);
553
600
  }finally{
554
601
  if(child?.exitCode===null) child.kill();
555
- await rm(fx.dir,{recursive:true,force:true});
602
+ await safeRm(fx.dir);
556
603
  }
557
604
  });
558
605
 
@@ -560,7 +607,7 @@ winTest('R58 concurrent cold remote claims have one winner and no loser cleanup'
560
607
  const fx=await fixture({statusOnline:true});const children=[],outputs=[];
561
608
  try{
562
609
  for(let i=0;i<3;i++){
563
- const child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
610
+ const child=spawn(process.execPath,[cliPath,'remote','--operator'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
564
611
  children.push(child);outputs.push(await collect(child));
565
612
  }
566
613
  const commands=await waitFor(fx.trace,items=>items.filter(x=>x==='status').length>=3);
@@ -578,18 +625,18 @@ winTest('R58 concurrent cold remote claims have one winner and no loser cleanup'
578
625
  live[0].stdin.end();assert.equal((await outputs[children.indexOf(live[0])].closed).code,0);
579
626
  }finally{
580
627
  for(const child of children)if(child.exitCode===null)child.kill();
581
- await rm(fx.dir,{recursive:true,force:true});
628
+ await safeRm(fx.dir);
582
629
  }
583
630
  });
584
631
 
585
632
  winTest('R58 duplicate remote verifies the real live owner and leaves its authority untouched',async()=>{
586
633
  const fx=await fixture({statusOnline:true});let first=null,second=null;
587
634
  try{
588
- first=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
635
+ first=spawn(process.execPath,[cliPath,'remote','--operator'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
589
636
  const firstOutput=await collect(first);
590
637
  const commands=await waitFor(fx.trace,items=>items.filter(x=>x==='status').length>=3);
591
638
  assert.ok(commands.filter(x=>x==='status').length>=3,firstOutput.stderr);
592
- const ownerReadyDeadline=Date.now()+3000;
639
+ const ownerReadyDeadline=Date.now()+fixtureTimeoutMs;
593
640
  while(Date.now()<ownerReadyDeadline&&!/\[READY\]/.test(firstOutput.stdout)) await sleep(50);
594
641
  assert.match(firstOutput.stdout,/\[READY\]/,firstOutput.stderr);
595
642
  const before=await traceCommands(fx.trace);
@@ -597,7 +644,7 @@ winTest('R58 duplicate remote verifies the real live owner and leaves its author
597
644
  const marker=JSON.parse(await readFile(markerPath,'utf8'));
598
645
  assert.equal(marker.owner_identity.pid,first.pid);
599
646
  assert.equal(marker.guardian_identity.parent_pid,first.pid);
600
- second=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
647
+ second=spawn(process.execPath,[cliPath,'remote','--operator'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
601
648
  const secondOutput=await collect(second);
602
649
  const stopped=await secondOutput.closed;
603
650
  assert.notEqual(stopped.code,0);
@@ -608,7 +655,7 @@ winTest('R58 duplicate remote verifies the real live owner and leaves its author
608
655
  first.stdin.end();assert.equal((await firstOutput.closed).code,0,firstOutput.stderr);
609
656
  }finally{
610
657
  if(first?.exitCode===null)first.kill();if(second?.exitCode===null)second.kill();
611
- await rm(fx.dir,{recursive:true,force:true});
658
+ await safeRm(fx.dir);
612
659
  }
613
660
  });
614
661
 
@@ -623,14 +670,14 @@ winTest('bare remote refuses unverified legacy ownership without touching author
623
670
  const output=await collect(child);
624
671
  await sleep(500);
625
672
  if(child.exitCode===null) child.stdin.end();
626
- const ended=await Promise.race([output.closed,sleep(6000).then(()=>({timeout:true}))]);
673
+ const ended=await boundedCompletion(output.closed);
627
674
  assert.equal(ended.timeout,undefined);
628
675
  assert.notEqual(ended.code,0);
629
676
  assert.deepEqual(await traceCommands(fx.trace),[]);
630
677
  assert.match(output.stderr,/remote session ownership unverified/i);
631
678
  }finally{
632
679
  if(child?.exitCode===null) child.kill();
633
- await rm(fx.dir,{recursive:true,force:true});
680
+ await safeRm(fx.dir);
634
681
  }
635
682
  });
636
683
 
@@ -639,11 +686,11 @@ winTest('explicit remote status remains a one-shot controller command',async()=>
639
686
  try{
640
687
  const child=spawn(process.execPath,[cliPath,'remote','status'],{env:fx.env,stdio:['ignore','pipe','pipe'],windowsHide:true});
641
688
  const output=await collect(child);
642
- const ended=await Promise.race([output.closed,sleep(6000).then(()=>({timeout:true}))]);
689
+ const ended=await boundedCompletion(output.closed);
643
690
  assert.equal(ended.timeout,undefined);
644
691
  assert.equal(ended.code,0,output.stderr);
645
692
  assert.deepEqual(await traceCommands(fx.trace),['status']);
646
- }finally{await rm(fx.dir,{recursive:true,force:true});}
693
+ }finally{await safeRm(fx.dir);}
647
694
  });
648
695
 
649
696
  winTest('explicit remote status keeps the coherent runtime one-shot and silent',async()=>{
@@ -658,12 +705,12 @@ winTest('explicit remote status keeps the coherent runtime one-shot and silent',
658
705
  }),'utf8');
659
706
  const child=spawn(process.execPath,[cliPath,'remote','status'],{env:fx.env,stdio:['ignore','pipe','pipe'],windowsHide:true});
660
707
  const output=await collect(child);
661
- const ended=await Promise.race([output.closed,sleep(6000).then(()=>({timeout:true}))]);
708
+ const ended=await boundedCompletion(output.closed);
662
709
  assert.equal(ended.timeout,undefined);
663
710
  assert.equal(ended.code,0,output.stderr);
664
711
  assert.doesNotMatch(output.stderr,/VERSION SKEW/);
665
712
  assert.deepEqual(await traceCommands(fx.trace),['status']);
666
- }finally{await rm(fx.dir,{recursive:true,force:true});}
713
+ }finally{await safeRm(fx.dir);}
667
714
  });
668
715
 
669
716
  winTest('bare remote surfaces bounded controller-start-failure evidence instead of only exit code',async()=>{
@@ -671,12 +718,12 @@ winTest('bare remote surfaces bounded controller-start-failure evidence instead
671
718
  try{
672
719
  const child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['ignore','pipe','pipe'],windowsHide:true});
673
720
  const output=await collect(child);
674
- const ended=await Promise.race([output.closed,sleep(6000).then(()=>({timeout:true}))]);
721
+ const ended=await boundedCompletion(output.closed);
675
722
  assert.equal(ended.timeout,undefined,'failed start did not terminate');
676
723
  assert.notEqual(ended.code,0);
677
724
  assert.match(output.stderr,/fixture controller evidence detail/);
678
725
  assert.match(output.stderr,/controller-start-failure/i);
679
- }finally{await rm(fx.dir,{recursive:true,force:true});}
726
+ }finally{await safeRm(fx.dir);}
680
727
  });
681
728
 
682
729
 
@@ -710,11 +757,11 @@ winTest('remote --trace --filter selects presentation without dropping journaled
710
757
  const journal=JSON.parse(await readFile(path.join(fx.state,'runtime','remote-results',marker.result_session_id+'.json'),'utf8'));
711
758
  assert.equal(journal.events.length,4,'presentation filter must not remove journal evidence');
712
759
  child.stdin.end();
713
- const ended=await Promise.race([output.closed,sleep(6000).then(()=>({timeout:true}))]);
760
+ const ended=await boundedCompletion(output.closed);
714
761
  assert.equal(ended.timeout,undefined);
715
762
  assert.equal(ended.code,0,output.stderr);
716
763
  }finally{
717
764
  if(child?.exitCode===null) child.kill('SIGKILL');
718
- await rm(fx.dir,{recursive:true,force:true});
765
+ await safeRm(fx.dir);
719
766
  }
720
767
  });
@@ -85,13 +85,13 @@ test('host standing grant remains armed until explicit revocation', async () =>
85
85
  assert.equal(status.remaining_ms, null);
86
86
  });
87
87
 
88
- test('controller emits standing grants and hides expiry UX', async () => {
88
+ test('controller retains coding/host standing grants but issues bounded autonomous expiry', async () => {
89
89
  const controller = await import('node:fs/promises').then(fs => fs.readFile(
90
90
  new URL('../controller/deadbyte-controller.ps1', import.meta.url), 'utf8'));
91
91
  assert.match(controller, /deadbyte\.host-grant\.v2/);
92
92
  assert.match(controller, /deadbyte\.coding-grant\.v2/);
93
93
  assert.match(controller, /deadbyte\.autonomous-grant\.v2/);
94
- assert.doesNotMatch(controller, /expires_at_utc/);
94
+ assert.match(controller, /expires_at_utc=\$now\.AddHours\(1\)\.ToString\('o'\)/);
95
95
  assert.doesNotMatch(controller, /AddMinutes\((?:15|30|60)\)/);
96
96
  assert.doesNotMatch(controller, /expires=/);
97
97
  });
@@ -71,6 +71,20 @@ test('tool wrapper durably records request before handler and writes correlated
71
71
  }finally{await rm(root,{recursive:true,force:true});}
72
72
  });
73
73
 
74
+ test('R69 audit retains explicit unknown side effect even when a tool envelope says ok',async()=>{
75
+ const root=await temp();
76
+ try{
77
+ const k=await keys(root);
78
+ const audit=await createToolAudit({stateRoot:root,signingKeyPath:k.privateKeyPath,contextProvider:async()=>context()});
79
+ const server=fakeServer();installToolAudit(server,audit);
80
+ server.registerTool('uncertain_write',{},async()=>({isError:false,
81
+ structuredContent:{status:'ok',side_effect_state:'unknown'}}));
82
+ await server.handlers.get('uncertain_write')({path:'scratch.txt'});
83
+ const all=await events(root);
84
+ assert.equal(all.at(-1).outcome.side_effect_state,'unknown');
85
+ }finally{await rm(root,{recursive:true,force:true});}
86
+ });
87
+
74
88
  test('audit failure before request commit prevents handler side effects',async()=>{
75
89
  const server=fakeServer();let sideEffect=false;
76
90
  installToolAudit(server,{async recordRequest(){throw new Error('audit unavailable');},async recordResult(){throw new Error('unexpected');}});
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/miniconpty.obj DELETED
Binary file