deadbyte-mcp 0.15.30 → 0.15.32

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.
@@ -0,0 +1,76 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { mkdir, open, readFile } from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { doctor } from '../src/doctor-r45.mjs';
7
+
8
+ const root=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
9
+ const stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
10
+ const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
11
+ const insist=(ok,message)=>{if(!ok)throw new Error(message);};
12
+ const pkg=JSON.parse(await readFile(path.join(root,'package.json'),'utf8'));
13
+ const release=JSON.parse(await readFile(path.join(root,'RELEASE.json'),'utf8'));
14
+ const provenance=JSON.parse(await readFile(path.join(root,'PROVENANCE.json'),'utf8'));
15
+ const matrix=JSON.parse(await readFile(path.join(root,'TEST-MATRIX.json'),'utf8'));
16
+ const active=JSON.parse(await readFile(path.join(stateRoot,'active-release.json'),'utf8'));
17
+ const manifestSha256=sha256(await readFile(path.join(root,'MANIFEST.SHA256')));
18
+
19
+ insist(pkg.version==='0.15.31'&&release.version===pkg.version&&release.train==='R54','R54 candidate identity mismatch');
20
+ insist(release.parent.version==='0.15.30','R54 source parent mismatch');
21
+ insist(release.parent.manifest_sha256==='ddf7c7338d9a371f5667d7b138695e7f9cfced553d14073ac5a44fd2fe0a0399','R54 source parent manifest mismatch');
22
+ insist(release.parent.tarball_sha256==='72881981bf76eb45527946b310caed8387943e2ca8e37ea6e606c32189dd5a70','R54 source parent tarball mismatch');
23
+ insist(
24
+ active.release_id===release.runtime_predecessor.release_id&&
25
+ active.manifest_sha256===release.runtime_predecessor.manifest_sha256&&
26
+ active.generation_manifest_sha256===release.runtime_predecessor.generation_manifest_sha256,
27
+ 'active runtime is not exact sealed 0.15.29 predecessor'
28
+ );
29
+ insist(release.hotfix?.activation_ancestry_excluded===true,'R54 activation ancestry fix missing');
30
+ insist(release.hotfix?.unrelated_stale_runtime_fail_closed===true,'R54 stale-runtime negative control missing');
31
+ insist(provenance.operator_override?.stable_final_claim===false,'R54 must not claim stable/final');
32
+ insist(matrix.operator_override?.four_hour_soak==='NOT_COMPLETED','R54 matrix must preserve soak bypass');
33
+
34
+ const health=await doctor();
35
+ insist(health.status==='ok'&&health.package_version===pkg.version&&health.manifest?.verified===true,'R54 doctor evidence invalid');
36
+
37
+ const evidence={
38
+ schema:'deadbyte.r54-windows-gate.v1',
39
+ status:'passed',
40
+ exit_code:0,
41
+ version:pkg.version,
42
+ train:'R54',
43
+ completed_at_utc:new Date().toISOString(),
44
+ manifest_sha256:manifestSha256,
45
+ parent:release.parent,
46
+ runtime_predecessor:release.runtime_predecessor,
47
+ hotfix:release.hotfix,
48
+ operator_override:provenance.operator_override,
49
+ active_predecessor:{
50
+ release_id:active.release_id,
51
+ version:active.version,
52
+ manifest_sha256:active.manifest_sha256,
53
+ generation_manifest_sha256:active.generation_manifest_sha256
54
+ },
55
+ doctor:{verified_entries:health.manifest.verified_entries},
56
+ gates:{
57
+ r54_focused:true,
58
+ package_boundary:true,
59
+ full_regression:true,
60
+ manifest_final_verify:true,
61
+ four_hour_soak_completed:false
62
+ }
63
+ };
64
+ const bytes=Buffer.from(JSON.stringify(evidence,null,2)+'\n');
65
+ const dir=path.join(stateRoot,'evidence','release');
66
+ await mkdir(dir,{recursive:true});
67
+ const target=path.join(dir,`r54-windows-gate-${manifestSha256.slice(0,16)}.json`);
68
+ try{
69
+ const handle=await open(target,'wx',0o600);
70
+ try{await handle.writeFile(bytes);await handle.sync();}finally{await handle.close();}
71
+ }catch(error){
72
+ if(error?.code!=='EEXIST')throw error;
73
+ const prior=JSON.parse(await readFile(target,'utf8'));
74
+ insist(prior.schema===evidence.schema&&prior.status==='passed'&&prior.version===evidence.version&&prior.manifest_sha256===manifestSha256,'conflicting R54 gate evidence identity');
75
+ }
76
+ console.log(JSON.stringify({status:'passed',path:target,sha256:sha256(bytes),manifest_sha256:manifestSha256}));
@@ -0,0 +1,79 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { mkdir, open, readFile } from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { doctor } from '../src/doctor-r45.mjs';
7
+
8
+ const root=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
9
+ const stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
10
+ const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
11
+ const insist=(ok,message)=>{if(!ok)throw new Error(message);};
12
+ const pkg=JSON.parse(await readFile(path.join(root,'package.json'),'utf8'));
13
+ const release=JSON.parse(await readFile(path.join(root,'RELEASE.json'),'utf8'));
14
+ const provenance=JSON.parse(await readFile(path.join(root,'PROVENANCE.json'),'utf8'));
15
+ const matrix=JSON.parse(await readFile(path.join(root,'TEST-MATRIX.json'),'utf8'));
16
+ const active=JSON.parse(await readFile(path.join(stateRoot,'active-release.json'),'utf8'));
17
+ const manifestSha256=sha256(await readFile(path.join(root,'MANIFEST.SHA256')));
18
+
19
+ insist(pkg.version==='0.15.32'&&release.version===pkg.version&&release.train==='R55','R55 candidate identity mismatch');
20
+ insist(release.parent.version==='0.15.31','R55 source parent mismatch');
21
+ insist(release.parent.manifest_sha256==='16854fe5b3eb0fa1c6dd2b96e3c5d6f792c5adbc91dd2a71e7fc2771472bbdd4','R55 source parent manifest mismatch');
22
+ insist(release.parent.tarball_sha256==='ff6eba3036cb00ac639ac8907ad6063e6ea8169cf32aca8721f75b1e403e501a','R55 source parent tarball mismatch');
23
+ insist(
24
+ active.release_id===release.runtime_predecessor.release_id&&
25
+ active.manifest_sha256===release.runtime_predecessor.manifest_sha256&&
26
+ active.generation_manifest_sha256===release.runtime_predecessor.generation_manifest_sha256,
27
+ 'active runtime is not exact sealed 0.15.29 predecessor'
28
+ );
29
+ insist(release.hotfix?.foreground_guardian_owner_parent_binding===true,'R55 guardian owner/parent binding missing');
30
+ insist(release.hotfix?.foreground_guardian_session_nonce_contract===true,'R55 guardian nonce contract missing');
31
+ insist(release.hotfix?.unrelated_stale_runtime_fail_closed===true,'R55 stale-runtime negative control missing');
32
+ insist(release.hotfix?.full_regression==='PASS','R55 full regression metadata is not PASS');
33
+ insist(matrix.observed_pre_release_evidence?.full_regression?.status==='PASS','R55 full regression evidence is not PASS');
34
+ insist(provenance.operator_override?.stable_final_claim===false,'R55 must not claim stable/final');
35
+ insist(matrix.operator_override?.four_hour_soak==='NOT_COMPLETED','R55 matrix must preserve soak bypass');
36
+
37
+ const health=await doctor();
38
+ insist(health.status==='ok'&&health.package_version===pkg.version&&health.manifest?.verified===true,'R55 doctor evidence invalid');
39
+
40
+ const evidence={
41
+ schema:'deadbyte.r55-windows-gate.v1',
42
+ status:'passed',
43
+ exit_code:0,
44
+ version:pkg.version,
45
+ train:'R55',
46
+ completed_at_utc:new Date().toISOString(),
47
+ manifest_sha256:manifestSha256,
48
+ parent:release.parent,
49
+ runtime_predecessor:release.runtime_predecessor,
50
+ hotfix:release.hotfix,
51
+ operator_override:provenance.operator_override,
52
+ active_predecessor:{
53
+ release_id:active.release_id,
54
+ version:active.version,
55
+ manifest_sha256:active.manifest_sha256,
56
+ generation_manifest_sha256:active.generation_manifest_sha256
57
+ },
58
+ doctor:{verified_entries:health.manifest.verified_entries},
59
+ gates:{
60
+ r55_focused:true,
61
+ package_boundary:true,
62
+ full_regression:true,
63
+ manifest_final_verify:true,
64
+ four_hour_soak_completed:false
65
+ }
66
+ };
67
+ const bytes=Buffer.from(JSON.stringify(evidence,null,2)+'\n');
68
+ const dir=path.join(stateRoot,'evidence','release');
69
+ await mkdir(dir,{recursive:true});
70
+ const target=path.join(dir,`r55-windows-gate-${manifestSha256.slice(0,16)}.json`);
71
+ try{
72
+ const handle=await open(target,'wx',0o600);
73
+ try{await handle.writeFile(bytes);await handle.sync();}finally{await handle.close();}
74
+ }catch(error){
75
+ if(error?.code!=='EEXIST')throw error;
76
+ const prior=JSON.parse(await readFile(target,'utf8'));
77
+ insist(prior.schema===evidence.schema&&prior.status==='passed'&&prior.version===evidence.version&&prior.manifest_sha256===manifestSha256,'conflicting R55 gate evidence identity');
78
+ }
79
+ console.log(JSON.stringify({status:'passed',path:target,sha256:sha256(bytes),manifest_sha256:manifestSha256}));
@@ -647,6 +647,48 @@ async function readLedger(ctx,name){
647
647
  function sameGeneration(a,b){
648
648
  return a.pid===b.pid&&a.instance_nonce===b.instance_nonce&&a.creation_time_utc===b.creation_time_utc&&a.image_sha256===b.image_sha256;
649
649
  }
650
+ function activationGuardianOwnedByLineage(item,selfLineage){
651
+ const name=String(item?.Name??'').toLowerCase();
652
+ if(name!=='node.exe') return false;
653
+ const commandLine=String(item?.CommandLine??'');
654
+ if(!commandLine.toLowerCase().includes('remote-session-guardian.mjs')) return false;
655
+ const ownerMatch=/(?:^|\s)--owner-pid(?:=|\s+)(\d+)(?=\s|$)/i.exec(commandLine);
656
+ const nonceMatch=/(?:^|\s)--session-nonce(?:=|\s+)([0-9a-f]{64})(?=\s|$)/i.exec(commandLine);
657
+ if(!ownerMatch||!nonceMatch) return false;
658
+ const ownerPid=Number(ownerMatch[1]);
659
+ const parentPid=Number(item?.ParentProcessId);
660
+ return Number.isInteger(ownerPid)&&ownerPid>0&&parentPid===ownerPid&&selfLineage.has(ownerPid);
661
+ }
662
+ export function selectOfflineRecoveryBlockers(processes,currentPid=process.pid){
663
+ const list=(Array.isArray(processes)?processes:[processes]).filter(Boolean);
664
+ const byPid=new Map();
665
+ for(const item of list){
666
+ const pid=Number(item?.ProcessId);
667
+ if(Number.isInteger(pid)&&pid>0) byPid.set(pid,item);
668
+ }
669
+ const selfLineage=new Set();
670
+ let cursor=Number(currentPid);
671
+ while(Number.isInteger(cursor)&&cursor>0&&!selfLineage.has(cursor)){
672
+ selfLineage.add(cursor);
673
+ const item=byPid.get(cursor);
674
+ if(!item) break;
675
+ const parent=Number(item?.ParentProcessId);
676
+ if(!Number.isInteger(parent)||parent<1||parent===cursor) break;
677
+ cursor=parent;
678
+ }
679
+ const runtimeNames=new Set(['node.exe','cloudflared.exe','deadbyte-tunnel-host.exe']);
680
+ return list.filter(item=>{
681
+ const pid=Number(item?.ProcessId);
682
+ if(selfLineage.has(pid)) return false;
683
+ if(activationGuardianOwnedByLineage(item,selfLineage)) return false;
684
+ const name=String(item?.Name??'').toLowerCase();
685
+ if(!runtimeNames.has(name)) return false;
686
+ const commandLine=String(item?.CommandLine??'').toLowerCase();
687
+ return commandLine.includes('deadbyte-mcp')||commandLine.includes('mcp-server.mjs')||
688
+ commandLine.includes('runtime-self-update.mjs')||commandLine.includes('remote-session-guardian.mjs')||
689
+ commandLine.includes('deadbyte-tunnel-host.exe');
690
+ });
691
+ }
650
692
  function cleanOfflinePredecessor(ctx){
651
693
  const runtimeRoot=path.resolve(ctx.runtime_root);
652
694
  const blockers=[
@@ -656,19 +698,13 @@ function cleanOfflinePredecessor(ctx){
656
698
  ].filter(name=>existsSync(path.join(runtimeRoot,name)));
657
699
  if(blockers.length) throw new Error('offline predecessor recovery blocked by runtime state: '+blockers.join(','));
658
700
 
659
- const command="Get-CimInstance Win32_Process | Where-Object { \$_.Name -in @('node.exe','cloudflared.exe','deadbyte-tunnel-host.exe') } | Select-Object ProcessId,Name,ExecutablePath,CommandLine | ConvertTo-Json -Compress";
701
+ const command="Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,Name,ExecutablePath,CommandLine | ConvertTo-Json -Compress";
660
702
  const result=runCaptured(powershellPath(),['-NoLogo','-NoProfile','-Command',command],{timeoutMs:15000});
661
703
  const text=assertRun(result,'runtime process query').trim();
662
704
  if(text){
663
705
  let parsed;
664
706
  try { parsed=JSON.parse(text); } catch(error){ throw new Error('runtime process query JSON invalid: '+error.message); }
665
- const processes=(Array.isArray(parsed)?parsed:[parsed]).filter(item=>Number(item?.ProcessId)!==process.pid);
666
- const relevant=processes.filter(item=>{
667
- const commandLine=String(item?.CommandLine??'').toLowerCase();
668
- return commandLine.includes('deadbyte-mcp')||commandLine.includes('mcp-server.mjs')||
669
- commandLine.includes('runtime-self-update.mjs')||commandLine.includes('remote-session-guardian.mjs')||
670
- commandLine.includes('deadbyte-tunnel-host.exe');
671
- });
707
+ const relevant=selectOfflineRecoveryBlockers(Array.isArray(parsed)?parsed:[parsed],process.pid);
672
708
  if(relevant.length) throw new Error('offline predecessor recovery blocked by DEADBYTE runtime processes: '+relevant.map(item=>String(item?.Name??'unknown')+'#'+String(item?.ProcessId??'?')).join(','));
673
709
  }
674
710
  return {
package/src/version.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export const DEADBYTE_VERSION = '0.15.30';
1
+ export const DEADBYTE_VERSION = '0.15.32';
2
2
  export const MCP_PROTOCOL_VERSION = '2026-07-28';
3
3
  export const RECEIPT_SCHEMA_V1 = 'deadbyte.receipt.v1';
4
4
  export const RECEIPT_SCHEMA_V2 = 'deadbyte.receipt.v2';
@@ -2,11 +2,15 @@ import assert from 'node:assert/strict';
2
2
  import { readFile } from 'node:fs/promises';
3
3
  import test from 'node:test';
4
4
 
5
- const read = path => readFile(new URL(`../${path}`, import.meta.url), 'utf8');
5
+ const read=path=>readFile(new URL(`../${path}`,import.meta.url),'utf8');
6
6
 
7
- test('R53 canonical Windows gate is successor-bound and preserves R52/R51/R50/R49 historical gates', async () => {
8
- const [pkgText, gate, evidence, historicalR52, historicalEvidenceR52, historicalR51, historicalEvidenceR51, historicalR50, historicalR49, deferred] = await Promise.all([
7
+ test('R55 canonical Windows gate is successor-bound and preserves R54/R53/R52/R51/R50/R49 historical gates',async()=>{
8
+ const [pkgText,gate,evidence,historicalR54,historicalEvidenceR54,historicalR53,historicalEvidenceR53,historicalR52,historicalEvidenceR52,historicalR51,historicalEvidenceR51,historicalR50,historicalR49,deferred]=await Promise.all([
9
9
  read('package.json'),
10
+ read('scripts/gate-windows-r55.ps1'),
11
+ read('scripts/windows-gate-evidence-r55.mjs'),
12
+ read('scripts/gate-windows-r54.ps1'),
13
+ read('scripts/windows-gate-evidence-r54.mjs'),
10
14
  read('scripts/gate-windows-r53.ps1'),
11
15
  read('scripts/windows-gate-evidence-r53.mjs'),
12
16
  read('scripts/gate-windows-r52.ps1'),
@@ -17,31 +21,35 @@ test('R53 canonical Windows gate is successor-bound and preserves R52/R51/R50/R4
17
21
  read('scripts/gate-windows-r49.ps1'),
18
22
  read('scripts/deferred-slot-operation-r46.mjs')
19
23
  ]);
20
- const pkg = JSON.parse(pkgText);
21
- assert.match(pkg.scripts['gate:windows'], /gate-windows-r53\.ps1$/);
22
- assert.match(gate, /DEADBYTE 0\.15\.30 \/ R53 WINDOWS GATE: PASS/);
23
- assert.match(gate, /r53-package-boundary/);
24
- assert.match(gate, /r53-focused-contracts/);
25
- assert.match(gate, /r49-remote-control-donors\.test\.mjs/);
26
- assert.match(gate, /desktop-runtime-r40\.test\.mjs/);
27
- assert.match(gate, /manifest-final-verify/);
28
- assert.match(evidence, /deadbyte\.r53-windows-gate\.v1/);
29
- assert.match(evidence, /pkg\.version === '0\.15\.30'/);
30
- assert.match(evidence, /release\.train === 'R53'/);
31
- assert.match(evidence, /release\.parent\.version === '0\.15\.29'/);
32
- assert.match(evidence, /four_hour_soak_completed: false/);
33
- assert.match(historicalR52, /DEADBYTE 0\.15\.29 \/ R52 WINDOWS GATE: PASS/);
34
- assert.match(historicalEvidenceR52, /deadbyte\.r52-windows-gate\.v1/);
35
- assert.match(historicalR51, /DEADBYTE 0\.15\.28 \/ R51 WINDOWS GATE: PASS/);
36
- assert.match(historicalEvidenceR51, /deadbyte\.r51-windows-gate\.v1/);
37
- assert.match(historicalR50, /DEADBYTE 0\.15\.27 \/ R50 WINDOWS GATE: PASS/);
38
- assert.match(historicalR49, /DEADBYTE 0\.15\.26 \/ R49 WINDOWS GATE: PASS/);
39
- assert.match(deferred, /const expectedVersion=packageIdentity\.version/);
40
- assert.match(deferred, /'--expected-version',expectedVersion/);
41
- assert.match(deferred, /async function awaitHandoffCompletion/);
42
- assert.match(deferred, /verifySlotUpdateEnvelope\(envelope,publicKey\)/);
43
- assert.match(deferred, /active pointer does not match signed activation receipt/);
44
- assert.match(deferred, /failure-receipt\.json/);
45
- assert.match(deferred, /await awaitHandoffCompletion\(await runSlotUpdateCli/);
46
- assert.doesNotMatch(deferred, /'--expected-version','0\.15\.5'/);
24
+ const pkg=JSON.parse(pkgText);
25
+ assert.match(pkg.scripts['gate:windows'],/gate-windows-r55\.ps1$/);
26
+ assert.match(gate,/DEADBYTE 0\.15\.32 \/ R55 WINDOWS GATE: PASS/);
27
+ assert.match(gate,/r55-package-boundary/);
28
+ assert.match(gate,/r55-focused-contracts/);
29
+ assert.match(gate,/full-regression/);
30
+ assert.match(gate,/manifest-verify/);
31
+ assert.match(gate,/doctor/);
32
+ assert.match(evidence,/deadbyte\.r55-windows-gate\.v1/);
33
+ assert.match(evidence,/pkg\.version==='0\.15\.32'/);
34
+ assert.match(evidence,/release\.train==='R55'/);
35
+ assert.match(evidence,/release\.parent\.version==='0\.15\.31'/);
36
+ assert.match(evidence,/four_hour_soak_completed:false/);
37
+ assert.match(historicalR54,/DEADBYTE 0\.15\.31 \/ R54 WINDOWS GATE: PASS/);
38
+ assert.match(historicalEvidenceR54,/deadbyte\.r54-windows-gate\.v1/);
39
+ assert.match(historicalR53,/DEADBYTE 0\.15\.30 \/ R53 WINDOWS GATE: PASS/);
40
+ assert.match(historicalEvidenceR53,/deadbyte\.r53-windows-gate\.v1/);
41
+ assert.match(historicalR52,/DEADBYTE 0\.15\.29 \/ R52 WINDOWS GATE: PASS/);
42
+ assert.match(historicalEvidenceR52,/deadbyte\.r52-windows-gate\.v1/);
43
+ assert.match(historicalR51,/DEADBYTE 0\.15\.28 \/ R51 WINDOWS GATE: PASS/);
44
+ assert.match(historicalEvidenceR51,/deadbyte\.r51-windows-gate\.v1/);
45
+ assert.match(historicalR50,/DEADBYTE 0\.15\.27 \/ R50 WINDOWS GATE: PASS/);
46
+ assert.match(historicalR49,/DEADBYTE 0\.15\.26 \/ R49 WINDOWS GATE: PASS/);
47
+ assert.match(deferred,/const expectedVersion=packageIdentity\.version/);
48
+ assert.match(deferred,/'--expected-version',expectedVersion/);
49
+ assert.match(deferred,/async function awaitHandoffCompletion/);
50
+ assert.match(deferred,/verifySlotUpdateEnvelope\(envelope,publicKey\)/);
51
+ assert.match(deferred,/active pointer does not match signed activation receipt/);
52
+ assert.match(deferred,/failure-receipt\.json/);
53
+ assert.match(deferred,/await awaitHandoffCompletion\(await runSlotUpdateCli/);
54
+ assert.doesNotMatch(deferred,/'--expected-version','0\.15\.5'/);
47
55
  });
@@ -5,8 +5,10 @@ import { readFile } from 'node:fs/promises';
5
5
  const root=new URL('../',import.meta.url);
6
6
  const read=rel=>readFile(new URL(rel,root),'utf8');
7
7
  const json=rel=>read(rel).then(JSON.parse);
8
+ const currentPackage=await json('package.json');
9
+ const r53test=currentPackage.version==='0.15.30'?test:test.skip;
8
10
 
9
- test('R53 current release identity is coherent across package lock source metadata SBOM and gate',async()=>{
11
+ r53test('R53 current release identity is coherent across package lock source metadata SBOM and gate',async()=>{
10
12
  const [pkg,lock,release,provenance,matrix,sbom,versionSource]=await Promise.all([
11
13
  json('package.json'),json('package-lock.json'),json('RELEASE.json'),json('PROVENANCE.json'),json('TEST-MATRIX.json'),json('SBOM.cdx.json'),read('src/version.mjs')
12
14
  ]);
@@ -25,7 +27,7 @@ test('R53 current release identity is coherent across package lock source metada
25
27
  assert.match(pkg.scripts['r53:focused:test'],/stabilization-semver\.test\.mjs/);
26
28
  });
27
29
 
28
- test('R53 lineage binds exact published 0.15.29 as parent and runtime predecessor',async()=>{
30
+ r53test('R53 lineage binds exact published 0.15.29 as parent and runtime predecessor',async()=>{
29
31
  const [release,provenance]=await Promise.all([json('RELEASE.json'),json('PROVENANCE.json')]);
30
32
  const parent={
31
33
  release_id:'v0.15.29-f74eaa1b3d00e6fb',
@@ -49,7 +51,7 @@ test('R53 lineage binds exact published 0.15.29 as parent and runtime predecesso
49
51
  assert.deepEqual(provenance.runtime_predecessor,parent);
50
52
  });
51
53
 
52
- test('R53 records stabilization evidence and explicit soak bypass without STABLE/FINAL claim',async()=>{
54
+ r53test('R53 records stabilization evidence and explicit soak bypass without STABLE/FINAL claim',async()=>{
53
55
  const [release,provenance,matrix]=await Promise.all([json('RELEASE.json'),json('PROVENANCE.json'),json('TEST-MATRIX.json')]);
54
56
  assert.equal(release.stabilization.semver_strict_validation,true);
55
57
  assert.equal(release.stabilization.powershell_child_environment_normalized,true);
@@ -0,0 +1,56 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { pathToFileURL } from 'node:url';
4
+ import path from 'node:path';
5
+
6
+ const target=process.env.R54_RUNTIME_UPDATE_PATH
7
+ ? path.resolve(process.env.R54_RUNTIME_UPDATE_PATH)
8
+ : path.resolve(new URL('../src/runtime-update.mjs',import.meta.url).pathname.replace(/^\/(?:[A-Za-z]:)/,m=>m.slice(1)));
9
+ const runtimeUpdate=await import(pathToFileURL(target).href+'?r54='+Date.now());
10
+
11
+ test('R54 exposes behavior-testable offline recovery blocker selection',()=>{
12
+ assert.equal(typeof runtimeUpdate.selectOfflineRecoveryBlockers,'function');
13
+ });
14
+
15
+ test('R54 excludes only the current activation ancestry across non-Node wrapper processes',()=>{
16
+ const processes=[
17
+ {ProcessId:100,ParentProcessId:50,Name:'node.exe',CommandLine:'node npm-cli.js exec -- deadbyte-mcp@latest remote'},
18
+ {ProcessId:200,ParentProcessId:100,Name:'cmd.exe',CommandLine:'cmd /d /s /c deadbyte-mcp remote'},
19
+ {ProcessId:300,ParentProcessId:200,Name:'node.exe',CommandLine:'node C:\\cache\\deadbyte-mcp\\src\\deadbyte-cli.mjs remote'},
20
+ {ProcessId:400,ParentProcessId:300,Name:'node.exe',CommandLine:'node C:\\slot\\deadbyte-mcp\\scripts\\runtime-self-update.mjs --resume-handoff x'},
21
+ {ProcessId:900,ParentProcessId:1,Name:'node.exe',CommandLine:'node C:\\stale\\deadbyte-mcp\\src\\mcp-server.mjs'}
22
+ ];
23
+ const blockers=runtimeUpdate.selectOfflineRecoveryBlockers(processes,400);
24
+ assert.deepEqual(blockers.map(item=>item.ProcessId),[900]);
25
+ });
26
+
27
+ test('R54 does not exempt a sibling stale DEADBYTE runtime',()=>{
28
+ const processes=[
29
+ {ProcessId:100,ParentProcessId:50,Name:'node.exe',CommandLine:'node npm-cli.js exec -- deadbyte-mcp@latest remote'},
30
+ {ProcessId:200,ParentProcessId:100,Name:'cmd.exe',CommandLine:'cmd /d /s /c deadbyte-mcp remote'},
31
+ {ProcessId:300,ParentProcessId:200,Name:'node.exe',CommandLine:'node C:\\cache\\deadbyte-mcp\\src\\deadbyte-cli.mjs remote'},
32
+ {ProcessId:400,ParentProcessId:300,Name:'node.exe',CommandLine:'node C:\\slot\\deadbyte-mcp\\scripts\\runtime-self-update.mjs --resume-handoff x'},
33
+ {ProcessId:700,ParentProcessId:300,Name:'node.exe',CommandLine:'node C:\\stale\\deadbyte-mcp\\src\\mcp-server.mjs'}
34
+ ];
35
+ const blockers=runtimeUpdate.selectOfflineRecoveryBlockers(processes,400);
36
+ assert.deepEqual(blockers.map(item=>item.ProcessId),[700]);
37
+ });
38
+
39
+ test('R54 still blocks unrelated stale guardian, tunnel, and cloud DEADBYTE processes',()=>{
40
+ const processes=[
41
+ {ProcessId:400,ParentProcessId:300,Name:'node.exe',CommandLine:'node C:\\slot\\deadbyte-mcp\\scripts\\runtime-self-update.mjs --resume-handoff x'},
42
+ {ProcessId:910,ParentProcessId:1,Name:'node.exe',CommandLine:'node C:\\stale\\deadbyte-mcp\\src\\remote-session-guardian.mjs'},
43
+ {ProcessId:920,ParentProcessId:1,Name:'deadbyte-tunnel-host.exe',CommandLine:'C:\\stale\\deadbyte-tunnel-host.exe'},
44
+ {ProcessId:930,ParentProcessId:1,Name:'cloudflared.exe',CommandLine:'cloudflared tunnel --config C:\\deadbyte-mcp\\cloud.yml run'}
45
+ ];
46
+ const blockers=runtimeUpdate.selectOfflineRecoveryBlockers(processes,400);
47
+ assert.deepEqual(blockers.map(item=>item.ProcessId),[910,920,930]);
48
+ });
49
+
50
+ test('R54 ignores unrelated Node processes without DEADBYTE runtime identity',()=>{
51
+ const processes=[
52
+ {ProcessId:400,ParentProcessId:300,Name:'node.exe',CommandLine:'node C:\\slot\\deadbyte-mcp\\scripts\\runtime-self-update.mjs --resume-handoff x'},
53
+ {ProcessId:950,ParentProcessId:1,Name:'node.exe',CommandLine:'node C:\\work\\unrelated-app\\server.js'}
54
+ ];
55
+ assert.deepEqual(runtimeUpdate.selectOfflineRecoveryBlockers(processes,400),[]);
56
+ });
@@ -0,0 +1,61 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { readFile } from 'node:fs/promises';
4
+
5
+ const root=new URL('../',import.meta.url);
6
+ const read=rel=>readFile(new URL(rel,root),'utf8');
7
+ const json=rel=>read(rel).then(JSON.parse);
8
+ const currentPackage=await json('package.json');
9
+ const r54test=currentPackage.version==='0.15.31'?test:test.skip;
10
+
11
+ r54test('R54 release identity is coherent across package lock source metadata SBOM and gate',async()=>{
12
+ const [pkg,lock,release,provenance,matrix,sbom,versionSource]=await Promise.all([
13
+ json('package.json'),json('package-lock.json'),json('RELEASE.json'),json('PROVENANCE.json'),json('TEST-MATRIX.json'),json('SBOM.cdx.json'),read('src/version.mjs')
14
+ ]);
15
+ assert.equal(pkg.version,'0.15.31');
16
+ assert.equal(lock.version,pkg.version);
17
+ assert.equal(lock.packages[''].version,pkg.version);
18
+ assert.match(versionSource,/DEADBYTE_VERSION = '0\.15\.31'/);
19
+ assert.equal(release.version,pkg.version);
20
+ assert.equal(release.train,'R54');
21
+ assert.equal(provenance.version,pkg.version);
22
+ assert.equal(matrix.version,pkg.version);
23
+ assert.equal(matrix.train,'R54');
24
+ assert.equal(sbom.metadata.component.version,pkg.version);
25
+ assert.equal(sbom.serialNumber,'urn:cdx:deadbyte-mcp:r54:0.15.31');
26
+ assert.match(pkg.scripts['gate:windows'],/gate-windows-r54\.ps1/);
27
+ assert.match(pkg.scripts['r54:focused:test'],/r54-offline-predecessor-self-exclusion\.test\.mjs/);
28
+ });
29
+
30
+ r54test('R54 source predecessor is exact immutable published 0.15.30 while runtime predecessor remains exact 0.15.29',async()=>{
31
+ const [release,provenance]=await Promise.all([json('RELEASE.json'),json('PROVENANCE.json')]);
32
+ assert.equal(release.parent.version,'0.15.30');
33
+ assert.equal(release.parent.release_id,'v0.15.30-ddf7c7338d9a371f');
34
+ assert.equal(release.parent.manifest_sha256,'ddf7c7338d9a371f5667d7b138695e7f9cfced553d14073ac5a44fd2fe0a0399');
35
+ assert.equal(release.parent.tarball_sha256,'72881981bf76eb45527946b310caed8387943e2ca8e37ea6e606c32189dd5a70');
36
+ assert.equal(release.parent.activation_status,'PUBLISHED_NOT_ACTIVATED');
37
+ assert.equal(release.source_predecessor.version,'0.15.30');
38
+ assert.equal(release.source_predecessor.tarball_sha256,release.parent.tarball_sha256);
39
+ assert.equal(release.source_predecessor.manifest_file_sha256,release.parent.manifest_sha256);
40
+ assert.deepEqual(release.runtime_predecessor,{
41
+ release_id:'v0.15.29-f74eaa1b3d00e6fb',
42
+ manifest_sha256:'f74eaa1b3d00e6fb5a36b2358efb815e3686c9fe9dbd3b84d25a713ef957748c',
43
+ generation_manifest_sha256:'289b4fc065de0681da6864cc1bbe09aab198ca804945ffc27c786438dad13f5a'
44
+ });
45
+ assert.equal(provenance.parent_manifest_sha256,release.parent.manifest_sha256);
46
+ assert.deepEqual(provenance.runtime_predecessor,release.runtime_predecessor);
47
+ });
48
+
49
+ r54test('R54 records surgical activation recovery fix and preserves explicit non-final claim',async()=>{
50
+ const [release,provenance,matrix]=await Promise.all([json('RELEASE.json'),json('PROVENANCE.json'),json('TEST-MATRIX.json')]);
51
+ assert.equal(release.hotfix.activation_ancestry_excluded,true);
52
+ assert.equal(release.hotfix.unrelated_stale_runtime_fail_closed,true);
53
+ assert.equal(release.hotfix.red_parent_0_15_30,'FAIL_5_OF_5');
54
+ assert.equal(release.hotfix.green_r54_candidate,'PASS_5_OF_5');
55
+ assert.equal(release.hotfix.stable_final_claim,false);
56
+ assert.equal(release.stabilization.four_hour_soak,'NOT_COMPLETED_OPERATOR_BYPASS');
57
+ assert.equal(provenance.operator_override.four_hour_soak,'NOT_COMPLETED');
58
+ assert.equal(provenance.operator_override.stable_final_claim,false);
59
+ assert.equal(matrix.operator_override.four_hour_soak,'NOT_COMPLETED');
60
+ assert.equal(matrix.operator_override.stable_final_claim,false);
61
+ });
@@ -0,0 +1,51 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { pathToFileURL } from 'node:url';
4
+ import path from 'node:path';
5
+
6
+ const target=process.env.R55_RUNTIME_UPDATE_PATH
7
+ ? path.resolve(process.env.R55_RUNTIME_UPDATE_PATH)
8
+ : path.resolve(new URL('../src/runtime-update.mjs',import.meta.url).pathname.replace(/^\/(?:[A-Za-z]:)/,m=>m.slice(1)));
9
+ const runtimeUpdate=await import(pathToFileURL(target).href+'?r55='+Date.now());
10
+ const nonce='a'.repeat(64);
11
+
12
+ test('R55 excludes the verified foreground remote guardian sibling owned by an activation ancestor',()=>{
13
+ const processes=[
14
+ {ProcessId:100,ParentProcessId:50,Name:'node.exe',CommandLine:'node npx-cli.js --yes deadbyte-mcp@0.15.32 remote'},
15
+ {ProcessId:200,ParentProcessId:100,Name:'cmd.exe',CommandLine:'cmd /d /s /c deadbyte-mcp remote'},
16
+ {ProcessId:300,ParentProcessId:200,Name:'node.exe',CommandLine:'node C:\\cache\\deadbyte-mcp\\src\\deadbyte-cli.mjs remote'},
17
+ {ProcessId:350,ParentProcessId:300,Name:'node.exe',CommandLine:'node C:\\cache\\deadbyte-mcp\\scripts\\deploy-r48.mjs'},
18
+ {ProcessId:400,ParentProcessId:350,Name:'node.exe',CommandLine:'node C:\\slot\\deadbyte-mcp\\scripts\\runtime-self-update.mjs --resume-handoff x'},
19
+ {ProcessId:500,ParentProcessId:300,Name:'node.exe',CommandLine:`node C:\\cache\\deadbyte-mcp\\src\\remote-session-guardian.mjs --state-root C:\\Users\\DEADBYTE\\.deadbyte-mcp --owner-pid 300 --session-nonce ${nonce}`},
20
+ {ProcessId:900,ParentProcessId:1,Name:'node.exe',CommandLine:'node C:\\stale\\deadbyte-mcp\\src\\mcp-server.mjs'}
21
+ ];
22
+ const blockers=runtimeUpdate.selectOfflineRecoveryBlockers(processes,400);
23
+ assert.deepEqual(blockers.map(item=>item.ProcessId),[900]);
24
+ });
25
+
26
+ test('R55 does not exempt a guardian whose parent does not equal its declared ancestor owner',()=>{
27
+ const processes=[
28
+ {ProcessId:300,ParentProcessId:200,Name:'node.exe',CommandLine:'node C:\\cache\\deadbyte-mcp\\src\\deadbyte-cli.mjs remote'},
29
+ {ProcessId:400,ParentProcessId:300,Name:'node.exe',CommandLine:'node C:\\slot\\deadbyte-mcp\\scripts\\runtime-self-update.mjs --resume-handoff x'},
30
+ {ProcessId:510,ParentProcessId:999,Name:'node.exe',CommandLine:`node C:\\cache\\deadbyte-mcp\\src\\remote-session-guardian.mjs --owner-pid 300 --session-nonce ${nonce}`}
31
+ ];
32
+ assert.deepEqual(runtimeUpdate.selectOfflineRecoveryBlockers(processes,400).map(item=>item.ProcessId),[510]);
33
+ });
34
+
35
+ test('R55 does not exempt a guardian whose owner is outside the activation lineage',()=>{
36
+ const processes=[
37
+ {ProcessId:300,ParentProcessId:200,Name:'node.exe',CommandLine:'node C:\\cache\\deadbyte-mcp\\src\\deadbyte-cli.mjs remote'},
38
+ {ProcessId:400,ParentProcessId:300,Name:'node.exe',CommandLine:'node C:\\slot\\deadbyte-mcp\\scripts\\runtime-self-update.mjs --resume-handoff x'},
39
+ {ProcessId:520,ParentProcessId:777,Name:'node.exe',CommandLine:`node C:\\cache\\deadbyte-mcp\\src\\remote-session-guardian.mjs --owner-pid 777 --session-nonce ${nonce}`}
40
+ ];
41
+ assert.deepEqual(runtimeUpdate.selectOfflineRecoveryBlockers(processes,400).map(item=>item.ProcessId),[520]);
42
+ });
43
+
44
+ test('R55 does not exempt a guardian without the signed-session-shaped nonce contract',()=>{
45
+ const processes=[
46
+ {ProcessId:300,ParentProcessId:200,Name:'node.exe',CommandLine:'node C:\\cache\\deadbyte-mcp\\src\\deadbyte-cli.mjs remote'},
47
+ {ProcessId:400,ParentProcessId:300,Name:'node.exe',CommandLine:'node C:\\slot\\deadbyte-mcp\\scripts\\runtime-self-update.mjs --resume-handoff x'},
48
+ {ProcessId:530,ParentProcessId:300,Name:'node.exe',CommandLine:'node C:\\cache\\deadbyte-mcp\\src\\remote-session-guardian.mjs --owner-pid 300 --session-nonce short'}
49
+ ];
50
+ assert.deepEqual(runtimeUpdate.selectOfflineRecoveryBlockers(processes,400).map(item=>item.ProcessId),[530]);
51
+ });
@@ -0,0 +1,61 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { readFile } from 'node:fs/promises';
4
+
5
+ const root=new URL('../',import.meta.url);
6
+ const read=rel=>readFile(new URL(rel,root),'utf8');
7
+ const json=rel=>read(rel).then(JSON.parse);
8
+
9
+ test('R55 release identity is coherent across package lock source metadata SBOM and gate',async()=>{
10
+ const [pkg,lock,release,provenance,matrix,sbom,versionSource]=await Promise.all([
11
+ json('package.json'),json('package-lock.json'),json('RELEASE.json'),json('PROVENANCE.json'),json('TEST-MATRIX.json'),json('SBOM.cdx.json'),read('src/version.mjs')
12
+ ]);
13
+ assert.equal(pkg.version,'0.15.32');
14
+ assert.equal(lock.version,pkg.version);
15
+ assert.equal(lock.packages[''].version,pkg.version);
16
+ assert.match(versionSource,/DEADBYTE_VERSION = '0\.15\.32'/);
17
+ assert.equal(release.version,pkg.version);
18
+ assert.equal(release.train,'R55');
19
+ assert.equal(provenance.version,pkg.version);
20
+ assert.equal(matrix.version,pkg.version);
21
+ assert.equal(matrix.train,'R55');
22
+ assert.equal(sbom.metadata.component.version,pkg.version);
23
+ assert.equal(sbom.serialNumber,'urn:cdx:deadbyte-mcp:r55:0.15.32');
24
+ assert.match(pkg.scripts['gate:windows'],/gate-windows-r55\.ps1/);
25
+ assert.match(pkg.scripts['r55:focused:test'],/r55-offline-predecessor-guardian-family\.test\.mjs/);
26
+ });
27
+
28
+ test('R55 source predecessor is exact immutable published 0.15.31 while runtime predecessor remains exact 0.15.29',async()=>{
29
+ const [release,provenance]=await Promise.all([json('RELEASE.json'),json('PROVENANCE.json')]);
30
+ assert.equal(release.parent.version,'0.15.31');
31
+ assert.equal(release.parent.release_id,'v0.15.31-16854fe5b3eb0fa1');
32
+ assert.equal(release.parent.manifest_sha256,'16854fe5b3eb0fa1c6dd2b96e3c5d6f792c5adbc91dd2a71e7fc2771472bbdd4');
33
+ assert.equal(release.parent.tarball_sha256,'ff6eba3036cb00ac639ac8907ad6063e6ea8169cf32aca8721f75b1e403e501a');
34
+ assert.equal(release.parent.activation_status,'PUBLISHED_NOT_ACTIVATED');
35
+ assert.equal(release.source_predecessor.version,'0.15.31');
36
+ assert.equal(release.source_predecessor.tarball_sha256,release.parent.tarball_sha256);
37
+ assert.equal(release.source_predecessor.manifest_file_sha256,release.parent.manifest_sha256);
38
+ assert.deepEqual(release.runtime_predecessor,{
39
+ release_id:'v0.15.29-f74eaa1b3d00e6fb',
40
+ manifest_sha256:'f74eaa1b3d00e6fb5a36b2358efb815e3686c9fe9dbd3b84d25a713ef957748c',
41
+ generation_manifest_sha256:'289b4fc065de0681da6864cc1bbe09aab198ca804945ffc27c786438dad13f5a'
42
+ });
43
+ assert.equal(provenance.parent_manifest_sha256,release.parent.manifest_sha256);
44
+ assert.deepEqual(provenance.runtime_predecessor,release.runtime_predecessor);
45
+ });
46
+
47
+ test('R55 records the guardian sibling RED to GREEN and preserves fail-closed negative controls',async()=>{
48
+ const [release,provenance,matrix]=await Promise.all([json('RELEASE.json'),json('PROVENANCE.json'),json('TEST-MATRIX.json')]);
49
+ assert.equal(release.hotfix.activation_ancestry_excluded,true);
50
+ assert.equal(release.hotfix.foreground_guardian_owner_parent_binding,true);
51
+ assert.equal(release.hotfix.foreground_guardian_session_nonce_contract,true);
52
+ assert.equal(release.hotfix.unrelated_stale_runtime_fail_closed,true);
53
+ assert.equal(release.hotfix.red_parent_0_15_31,'FAIL_1_OF_4');
54
+ assert.equal(release.hotfix.green_r55_candidate,'PASS_4_OF_4');
55
+ assert.equal(release.hotfix.stable_final_claim,false);
56
+ assert.equal(matrix.observed_pre_release_evidence.red_parent_0_15_31.receipt_sha256,'07ba973aa9224fbb1dde572af35640a1e07ca47273f1e50958d787bfe2aaf429');
57
+ assert.equal(matrix.observed_pre_release_evidence.green_r55_candidate.receipt_sha256,'a217f72cce51a9daf56136f9075ba487adb2a899c291a63af835ea15f8c632f0');
58
+ assert.equal(provenance.operator_override.four_hour_soak,'NOT_COMPLETED');
59
+ assert.equal(provenance.operator_override.stable_final_claim,false);
60
+ assert.equal(matrix.operator_override.stable_final_claim,false);
61
+ });