deadbyte-mcp 0.15.31 → 0.15.33

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,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}));
@@ -0,0 +1,81 @@
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.33'&&release.version===pkg.version&&release.train==='R56','R56 candidate identity mismatch');
20
+ insist(release.parent.version==='0.15.32','R56 parent mismatch');
21
+ insist(release.parent.manifest_sha256==='e7223f467777f5dfeb20fd2cc7a6eca22619a44ed95e5bc0b32d9c7aabba361b','R56 parent manifest mismatch');
22
+ insist(release.parent.generation_manifest_sha256==='740443fd207c5e6ffd5952079214bf6e81e9281a6ec880de9bbe3b8ce1deb00e','R56 parent generation mismatch');
23
+ insist(release.parent.tarball_sha256==='c9e1f5875dd2177cee0089305b40321c128c54ce7f5522e34e507d4ecfb22638','R56 parent tarball mismatch');
24
+ insist(
25
+ active.release_id===release.runtime_predecessor.release_id&&
26
+ active.manifest_sha256===release.runtime_predecessor.manifest_sha256&&
27
+ active.generation_manifest_sha256===release.runtime_predecessor.generation_manifest_sha256,
28
+ 'active runtime is not exact sealed 0.15.32 predecessor'
29
+ );
30
+ insist(release.hotfix?.signed_handoff_launcher_snapshot_required===true,'R56 signed rollback handoff launcher requirement missing');
31
+ insist(release.hotfix?.stored_predecessor_verified_without_live_launcher===true,'R56 stored predecessor verification split missing');
32
+ insist(release.hotfix?.predecessor_launcher_restored_before_pointer_commit===true,'R56 predecessor launcher ordering missing');
33
+ insist(release.hotfix?.successor_launcher_restored_before_recovery_pointer===true,'R56 successor recovery ordering missing');
34
+ insist(release.hotfix?.full_regression==='PASS','R56 full regression metadata is not PASS');
35
+ insist(matrix.observed_pre_release_evidence?.full_regression?.status==='PASS','R56 full regression evidence is not PASS');
36
+ insist(provenance.operator_override?.stable_final_claim===false,'R56 must not claim stable/final');
37
+ insist(matrix.operator_override?.four_hour_soak==='NOT_COMPLETED','R56 matrix must preserve soak bypass');
38
+
39
+ const health=await doctor();
40
+ insist(health.status==='ok'&&health.package_version===pkg.version&&health.manifest?.verified===true,'R56 doctor evidence invalid');
41
+
42
+ const evidence={
43
+ schema:'deadbyte.r56-windows-gate.v1',
44
+ status:'passed',
45
+ exit_code:0,
46
+ version:pkg.version,
47
+ train:'R56',
48
+ completed_at_utc:new Date().toISOString(),
49
+ manifest_sha256:manifestSha256,
50
+ parent:release.parent,
51
+ runtime_predecessor:release.runtime_predecessor,
52
+ hotfix:release.hotfix,
53
+ operator_override:provenance.operator_override,
54
+ active_predecessor:{
55
+ release_id:active.release_id,
56
+ version:active.version,
57
+ manifest_sha256:active.manifest_sha256,
58
+ generation_manifest_sha256:active.generation_manifest_sha256
59
+ },
60
+ doctor:{verified_entries:health.manifest.verified_entries},
61
+ gates:{
62
+ r56_focused:true,
63
+ package_boundary:true,
64
+ full_regression:true,
65
+ manifest_final_verify:true,
66
+ four_hour_soak_completed:false
67
+ }
68
+ };
69
+ const bytes=Buffer.from(JSON.stringify(evidence,null,2)+'\n');
70
+ const dir=path.join(stateRoot,'evidence','release');
71
+ await mkdir(dir,{recursive:true});
72
+ const target=path.join(dir,`r56-windows-gate-${manifestSha256.slice(0,16)}.json`);
73
+ try{
74
+ const handle=await open(target,'wx',0o600);
75
+ try{await handle.writeFile(bytes);await handle.sync();}finally{await handle.close();}
76
+ }catch(error){
77
+ if(error?.code!=='EEXIST')throw error;
78
+ const prior=JSON.parse(await readFile(target,'utf8'));
79
+ insist(prior.schema===evidence.schema&&prior.status==='passed'&&prior.version===evidence.version&&prior.manifest_sha256===manifestSha256,'conflicting R56 gate evidence identity');
80
+ }
81
+ console.log(JSON.stringify({status:'passed',path:target,sha256:sha256(bytes),manifest_sha256:manifestSha256}));
@@ -647,6 +647,18 @@ 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
+ }
650
662
  export function selectOfflineRecoveryBlockers(processes,currentPid=process.pid){
651
663
  const list=(Array.isArray(processes)?processes:[processes]).filter(Boolean);
652
664
  const byPid=new Map();
@@ -668,6 +680,7 @@ export function selectOfflineRecoveryBlockers(processes,currentPid=process.pid){
668
680
  return list.filter(item=>{
669
681
  const pid=Number(item?.ProcessId);
670
682
  if(selfLineage.has(pid)) return false;
683
+ if(activationGuardianOwnedByLineage(item,selfLineage)) return false;
671
684
  const name=String(item?.Name??'').toLowerCase();
672
685
  if(!runtimeNames.has(name)) return false;
673
686
  const commandLine=String(item?.CommandLine??'').toLowerCase();
@@ -848,16 +861,21 @@ async function verifyPackageRoot(root,expectedVersion,expectedManifest,label){
848
861
  if(pkg?.name!=='deadbyte-mcp'||pkg?.version!==expectedVersion) throw new Error(`${label} package identity mismatch`);
849
862
  return {root:absolute,manifest_sha256:digest,entries:entries.size};
850
863
  }
851
- async function verifyActiveInstallation(stateRoot,pointer){
864
+ async function verifyStoredInstallation(stateRoot,pointer){
852
865
  const state=path.resolve(stateRoot); const expectedRelease=path.join(state,'releases',releaseId(pointer.version,pointer.manifest_sha256));
853
866
  if(path.resolve(pointer.release_root)!==path.resolve(expectedRelease)) throw new Error('active pointer release root is not content-addressed store path');
854
867
  const release=await verifyPackageRoot(pointer.release_root,pointer.version,pointer.manifest_sha256,'active release');
855
868
  const generation=await verifyGenerationBundle(pointer.generation_root,pointer.generation_manifest_sha256);
856
869
  const expectedConfig=path.join(path.resolve(pointer.generation_root),'controller-config.psd1');
857
870
  if(path.resolve(pointer.config_path)!==path.resolve(expectedConfig)) throw new Error('active pointer config path mismatch');
871
+ return {release,generation};
872
+ }
873
+ async function verifyActiveInstallation(stateRoot,pointer){
874
+ const state=path.resolve(stateRoot);
875
+ const verified=await verifyStoredInstallation(state,pointer);
858
876
  const currentLauncher=await sha256File(launcherPath(state));
859
877
  if(currentLauncher!==pointer.launcher_sha256) throw new Error('active pointer launcher digest mismatch');
860
- return {release,generation};
878
+ return verified;
861
879
  }
862
880
  async function loadPointerIfPresent(stateRoot){
863
881
  const file=path.join(path.resolve(stateRoot),'active-release.json');
@@ -1071,6 +1089,41 @@ function decodeSnapshot(snapshot,label){
1071
1089
  }
1072
1090
  return {exists:false,bytes:null,sha256:null};
1073
1091
  }
1092
+ export function rollbackLauncherPlanFromHandoff(body,priorPointer,activePointer,stateRoot=DEFAULT_STATE_ROOT){
1093
+ if(!body||typeof body!=='object') throw new Error('rollback handoff body required');
1094
+ const handoffPrior=body.prior_pointer?parseActivePointer(JSON.stringify(body.prior_pointer)):null;
1095
+ const handoffActive=body.new_pointer?parseActivePointer(JSON.stringify(body.new_pointer)):null;
1096
+ if(!samePublicPointer(handoffPrior,priorPointer)||!samePublicPointer(handoffActive,activePointer)) throw new Error('rollback handoff pointer binding mismatch');
1097
+ const state=path.resolve(stateRoot);
1098
+ const launchers={
1099
+ ps1:path.resolve(String(body.launchers?.ps1??'')),
1100
+ cmd:path.resolve(String(body.launchers?.cmd??'')),
1101
+ top:path.resolve(String(body.launchers?.top??TOP_LAUNCHER)),
1102
+ launcher_sha256:String(body.launchers?.launcher_sha256??''),
1103
+ ps1Bytes:Buffer.from(String(body.launchers?.ps1_bytes??''),'base64'),
1104
+ cmdBytes:Buffer.from(String(body.launchers?.cmd_bytes??''),'base64'),
1105
+ snapshots:{
1106
+ ps1:decodeSnapshot(body.launchers?.snapshots?.ps1,'rollback.launcher.ps1'),
1107
+ cmd:decodeSnapshot(body.launchers?.snapshots?.cmd,'rollback.launcher.cmd'),
1108
+ top:decodeSnapshot(body.launchers?.snapshots?.top,'rollback.launcher.top')
1109
+ },
1110
+ installed:true
1111
+ };
1112
+ if(launchers.ps1!==path.resolve(launcherPath(state))||
1113
+ launchers.cmd!==path.resolve(path.join(state,'bin','DEADBYTE-MCP.cmd'))||
1114
+ launchers.top!==path.resolve(TOP_LAUNCHER)) throw new Error('rollback launcher paths are not canonical');
1115
+ if(!HEX64.test(launchers.launcher_sha256)||sha256Bytes(launchers.ps1Bytes)!==launchers.launcher_sha256) throw new Error('rollback successor launcher bytes/hash mismatch');
1116
+ if(launchers.launcher_sha256!==activePointer.launcher_sha256) throw new Error('rollback successor launcher hash does not match active pointer');
1117
+ if(!launchers.snapshots.ps1.exists||launchers.snapshots.ps1.sha256!==priorPointer.launcher_sha256) throw new Error('rollback predecessor launcher snapshot does not match signed prior pointer');
1118
+ return launchers;
1119
+ }
1120
+ async function restoreRollbackLaunchers(plan){
1121
+ await restoreFile(plan.ps1,plan.snapshots.ps1);
1122
+ await restoreFile(plan.cmd,plan.snapshots.cmd);
1123
+ await restoreFile(plan.top,plan.snapshots.top);
1124
+ if(await sha256File(plan.ps1)!==plan.snapshots.ps1.sha256) throw new Error('rollback predecessor launcher restore hash mismatch');
1125
+ return plan;
1126
+ }
1074
1127
  const UPDATE_PHASE_RANK=Object.freeze({
1075
1128
  initial:0,candidate_prepared:10,old_runtime_verified:20,shutdown_handoff_armed:25,supervisor_spawned:30,
1076
1129
  authority_revoked:40,old_runtime_stopped:50,workspace_ready:60,launcher_installed:70,pointer_committed:80,
@@ -1574,19 +1627,28 @@ export async function performSlotRollback({activationReceipt,stateRoot=DEFAULT_S
1574
1627
  const activePointer=parseActivePointer(JSON.stringify(activationEnvelope.body.active_pointer));
1575
1628
  const pointerInfo=await loadPointerIfPresent(state);
1576
1629
  if(!pointerInfo.pointer||canonicalJson(publicPointer(pointerInfo.pointer))!==canonicalJson(publicPointer(activePointer))) throw new Error('rollback current pointer does not match signed activation pointer');
1577
- await verifyActiveInstallation(state,priorPointer);
1630
+
1631
+ const handoffPath=path.join(path.dirname(receiptFile),'handoff.json');
1632
+ const {body:handoffBody}=await readHandoffEnvelope(handoffPath,state);
1633
+ if(handoffBody.update_id!==activationEnvelope.body.update_id) throw new Error('rollback handoff update identity mismatch');
1634
+ const rollbackLaunchers=rollbackLauncherPlanFromHandoff(handoffBody,priorPointer,activePointer,state);
1635
+ await verifyStoredInstallation(state,priorPointer);
1636
+
1578
1637
  const currentCtx=slotContext(state,pointerInfo.pointer),currentRuntime=await captureRuntime(currentCtx);
1579
1638
  const revoked=await revokeAuthority(currentCtx,currentRuntime.status);
1580
1639
  const rollbackId=`r31-rollback-${activationEnvelope.receipt_sha256.slice(0,16)}-${Date.now().toString(36)}-${randomBytes(4).toString('hex')}`;
1581
1640
  const evidenceDir=path.join(state,'evidence','updates',rollbackId),statePath=path.join(evidenceDir,'state.json'),receiptPath=path.join(evidenceDir,'receipt.json');
1582
1641
  await mkdir(evidenceDir,{recursive:true});
1583
1642
  const journal={schema:'deadbyte.r31-slot-rollback-state.v1',rollback_id:rollbackId,activation_receipt:path.resolve(receiptFile),
1584
- activation_receipt_sha256:activationEnvelope.receipt_sha256,from_pointer:publicPointer(activePointer),to_pointer:publicPointer(priorPointer),created_at_utc:new Date().toISOString()};
1643
+ activation_receipt_sha256:activationEnvelope.receipt_sha256,handoff_path:handoffPath,
1644
+ from_pointer:publicPointer(activePointer),to_pointer:publicPointer(priorPointer),created_at_utc:new Date().toISOString()};
1585
1645
  await writeState(statePath,journal,'verified');
1586
- let stopped=false,pointerCommitted=false,priorCtx=null,priorRuntime=null;
1646
+ let stopped=false,launchersRestored=false,pointerCommitted=false,priorCtx=null,priorRuntime=null;
1587
1647
  try {
1588
1648
  await stopAndVerify(currentCtx,currentRuntime); stopped=true;
1589
1649
  await writeState(statePath,journal,'successor_stopped');
1650
+ await restoreRollbackLaunchers(rollbackLaunchers); launchersRestored=true;
1651
+ await writeState(statePath,journal,'predecessor_launcher_restored',{launcher_sha256:priorPointer.launcher_sha256});
1590
1652
  await atomicWriteActivePointer(pointerInfo.file,priorPointer); pointerCommitted=true;
1591
1653
  await verifyActiveInstallation(state,priorPointer);
1592
1654
  await writeState(statePath,journal,'prior_pointer_restored',{active_pointer:publicPointer(priorPointer)});
@@ -1597,16 +1659,27 @@ export async function performSlotRollback({activationReceipt,stateRoot=DEFAULT_S
1597
1659
  if(finalStatus.process_armed||finalStatus.coding_armed||finalStatus.autonomous_armed||finalStatus.desktop_armed||finalStatus.host_armed) throw new Error('rollback predecessor authority must remain disarmed');
1598
1660
  const body={schema:ROLLBACK_SCHEMA,rollback_id:rollbackId,activation_receipt_sha256:activationEnvelope.receipt_sha256,
1599
1661
  completed_at_utc:new Date().toISOString(),from_pointer:publicPointer(activePointer),active_pointer:publicPointer(priorPointer),
1600
- old_runtime:generationTuple(currentRuntime),new_runtime:generationTuple(priorRuntime),stabilization,authority_revoked:revoked.revoked,rollback_performed:true};
1662
+ launcher_restored:true,old_runtime:generationTuple(currentRuntime),new_runtime:generationTuple(priorRuntime),stabilization,
1663
+ authority_revoked:revoked.revoked,rollback_performed:true};
1601
1664
  const receipt=await writeEnvelope(receiptPath,body,key);
1602
1665
  await writeState(statePath,journal,'completed',{receipt_path:receiptPath,receipt_sha256:receipt.receipt_sha256});
1603
1666
  return {ok:true,rollback_id:rollbackId,state_path:statePath,receipt_path:receiptPath,receipt_sha256:receipt.receipt_sha256,pointer:priorPointer,new_runtime:priorRuntime};
1604
1667
  } catch(error){
1605
- const recovery={attempted:false,prior_runtime_stopped:false,successor_pointer_restored:false,successor_runtime_restarted:false,errors:[]};
1668
+ const recovery={attempted:false,prior_runtime_stopped:false,successor_launcher_restored:false,successor_pointer_restored:false,successor_runtime_restarted:false,errors:[]};
1606
1669
  if(stopped){
1607
1670
  recovery.attempted=true;
1608
1671
  if(pointerCommitted&&priorCtx){ try { controllerCaptured(priorCtx,'stop',30000); recovery.prior_runtime_stopped=true; } catch(recoveryError){ recovery.errors.push(`stop-prior:${recoveryError.message}`); } }
1609
- if(pointerCommitted){ try { await atomicWriteActivePointer(pointerInfo.file,activePointer); await verifyActiveInstallation(state,activePointer); recovery.successor_pointer_restored=true; } catch(recoveryError){ recovery.errors.push(`restore-pointer:${recoveryError.message}`); } }
1672
+ if(launchersRestored){
1673
+ try { await installLaunchers(rollbackLaunchers); recovery.successor_launcher_restored=true; }
1674
+ catch(recoveryError){ recovery.errors.push(`restore-successor-launcher:${recoveryError.message}`); }
1675
+ }
1676
+ if(pointerCommitted){
1677
+ try { await atomicWriteActivePointer(pointerInfo.file,activePointer); await verifyActiveInstallation(state,activePointer); recovery.successor_pointer_restored=true; }
1678
+ catch(recoveryError){ recovery.errors.push(`restore-pointer:${recoveryError.message}`); }
1679
+ }else if(recovery.successor_launcher_restored){
1680
+ try { await verifyActiveInstallation(state,activePointer); recovery.successor_pointer_restored=true; }
1681
+ catch(recoveryError){ recovery.errors.push(`verify-successor-pointer:${recoveryError.message}`); }
1682
+ }
1610
1683
  try { await startAndVerify(currentCtx,currentRuntime); recovery.successor_runtime_restarted=true; } catch(recoveryError){ recovery.errors.push(`restart-successor:${recoveryError.message}`); }
1611
1684
  }
1612
1685
  await writeState(statePath,journal,'failed',{error:{name:error?.name??'Error',message:String(error?.message??error)},recovery}).catch(()=>{});
package/src/version.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export const DEADBYTE_VERSION = '0.15.31';
1
+ export const DEADBYTE_VERSION = '0.15.33';
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';
@@ -4,9 +4,13 @@ import test from 'node:test';
4
4
 
5
5
  const read=path=>readFile(new URL(`../${path}`,import.meta.url),'utf8');
6
6
 
7
- test('R54 canonical Windows gate is successor-bound and preserves R53/R52/R51/R50/R49 historical gates',async()=>{
8
- const [pkgText,gate,evidence,historicalR53,historicalEvidenceR53,historicalR52,historicalEvidenceR52,historicalR51,historicalEvidenceR51,historicalR50,historicalR49,deferred]=await Promise.all([
7
+ test('R56 canonical Windows gate is successor-bound and preserves R55/R54/R53/R52/R51/R50/R49 historical gates',async()=>{
8
+ const [pkgText,gate,evidence,historicalR55,historicalEvidenceR55,historicalR54,historicalEvidenceR54,historicalR53,historicalEvidenceR53,historicalR52,historicalEvidenceR52,historicalR51,historicalEvidenceR51,historicalR50,historicalR49,deferred]=await Promise.all([
9
9
  read('package.json'),
10
+ read('scripts/gate-windows-r56.ps1'),
11
+ read('scripts/windows-gate-evidence-r56.mjs'),
12
+ read('scripts/gate-windows-r55.ps1'),
13
+ read('scripts/windows-gate-evidence-r55.mjs'),
10
14
  read('scripts/gate-windows-r54.ps1'),
11
15
  read('scripts/windows-gate-evidence-r54.mjs'),
12
16
  read('scripts/gate-windows-r53.ps1'),
@@ -20,18 +24,22 @@ test('R54 canonical Windows gate is successor-bound and preserves R53/R52/R51/R5
20
24
  read('scripts/deferred-slot-operation-r46.mjs')
21
25
  ]);
22
26
  const pkg=JSON.parse(pkgText);
23
- assert.match(pkg.scripts['gate:windows'],/gate-windows-r54\.ps1$/);
24
- assert.match(gate,/DEADBYTE 0\.15\.31 \/ R54 WINDOWS GATE: PASS/);
25
- assert.match(gate,/r54-package-boundary/);
26
- assert.match(gate,/r54-focused-contracts/);
27
- assert.match(gate,/full-regression/);
27
+ assert.match(pkg.scripts['gate:windows'],/gate-windows-r56\.ps1$/);
28
+ assert.match(gate,/DEADBYTE 0\.15\.33 \/ R56 WINDOWS GATE: PASS/);
29
+ assert.match(gate,/r56-package-boundary/);
30
+ assert.match(gate,/r56-focused-contracts/);
31
+ assert.match(gate,/full-regression-evidence/);
28
32
  assert.match(gate,/manifest-verify/);
29
33
  assert.match(gate,/doctor/);
30
- assert.match(evidence,/deadbyte\.r54-windows-gate\.v1/);
31
- assert.match(evidence,/pkg\.version==='0\.15\.31'/);
32
- assert.match(evidence,/release\.train==='R54'/);
33
- assert.match(evidence,/release\.parent\.version==='0\.15\.30'/);
34
+ assert.match(evidence,/deadbyte\.r56-windows-gate\.v1/);
35
+ assert.match(evidence,/pkg\.version==='0\.15\.33'/);
36
+ assert.match(evidence,/release\.train==='R56'/);
37
+ assert.match(evidence,/release\.parent\.version==='0\.15\.32'/);
34
38
  assert.match(evidence,/four_hour_soak_completed:false/);
39
+ assert.match(historicalR55,/DEADBYTE 0\.15\.32 \/ R55 WINDOWS GATE: PASS/);
40
+ assert.match(historicalEvidenceR55,/deadbyte\.r55-windows-gate\.v1/);
41
+ assert.match(historicalR54,/DEADBYTE 0\.15\.31 \/ R54 WINDOWS GATE: PASS/);
42
+ assert.match(historicalEvidenceR54,/deadbyte\.r54-windows-gate\.v1/);
35
43
  assert.match(historicalR53,/DEADBYTE 0\.15\.30 \/ R53 WINDOWS GATE: PASS/);
36
44
  assert.match(historicalEvidenceR53,/deadbyte\.r53-windows-gate\.v1/);
37
45
  assert.match(historicalR52,/DEADBYTE 0\.15\.29 \/ R52 WINDOWS GATE: PASS/);
@@ -42,10 +50,5 @@ test('R54 canonical Windows gate is successor-bound and preserves R53/R52/R51/R5
42
50
  assert.match(historicalR49,/DEADBYTE 0\.15\.26 \/ R49 WINDOWS GATE: PASS/);
43
51
  assert.match(deferred,/const expectedVersion=packageIdentity\.version/);
44
52
  assert.match(deferred,/'--expected-version',expectedVersion/);
45
- assert.match(deferred,/async function awaitHandoffCompletion/);
46
53
  assert.match(deferred,/verifySlotUpdateEnvelope\(envelope,publicKey\)/);
47
- assert.match(deferred,/active pointer does not match signed activation receipt/);
48
- assert.match(deferred,/failure-receipt\.json/);
49
- assert.match(deferred,/await awaitHandoffCompletion\(await runSlotUpdateCli/);
50
- assert.doesNotMatch(deferred,/'--expected-version','0\.15\.5'/);
51
54
  });
@@ -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 r54test=currentPackage.version==='0.15.31'?test:test.skip;
8
10
 
9
- test('R54 release identity is coherent across package lock source metadata SBOM and gate',async()=>{
11
+ r54test('R54 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('R54 release identity is coherent across package lock source metadata SBOM
25
27
  assert.match(pkg.scripts['r54:focused:test'],/r54-offline-predecessor-self-exclusion\.test\.mjs/);
26
28
  });
27
29
 
28
- test('R54 source predecessor is exact immutable published 0.15.30 while runtime predecessor remains exact 0.15.29',async()=>{
30
+ r54test('R54 source predecessor is exact immutable published 0.15.30 while runtime predecessor remains exact 0.15.29',async()=>{
29
31
  const [release,provenance]=await Promise.all([json('RELEASE.json'),json('PROVENANCE.json')]);
30
32
  assert.equal(release.parent.version,'0.15.30');
31
33
  assert.equal(release.parent.release_id,'v0.15.30-ddf7c7338d9a371f');
@@ -44,7 +46,7 @@ test('R54 source predecessor is exact immutable published 0.15.30 while runtime
44
46
  assert.deepEqual(provenance.runtime_predecessor,release.runtime_predecessor);
45
47
  });
46
48
 
47
- test('R54 records surgical activation recovery fix and preserves explicit non-final claim',async()=>{
49
+ r54test('R54 records surgical activation recovery fix and preserves explicit non-final claim',async()=>{
48
50
  const [release,provenance,matrix]=await Promise.all([json('RELEASE.json'),json('PROVENANCE.json'),json('TEST-MATRIX.json')]);
49
51
  assert.equal(release.hotfix.activation_ancestry_excluded,true);
50
52
  assert.equal(release.hotfix.unrelated_stale_runtime_fail_closed,true);
@@ -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,63 @@
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 r55test=currentPackage.version==='0.15.32'?test:test.skip;
10
+
11
+ r55test('R55 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.32');
16
+ assert.equal(lock.version,pkg.version);
17
+ assert.equal(lock.packages[''].version,pkg.version);
18
+ assert.match(versionSource,/DEADBYTE_VERSION = '0\.15\.32'/);
19
+ assert.equal(release.version,pkg.version);
20
+ assert.equal(release.train,'R55');
21
+ assert.equal(provenance.version,pkg.version);
22
+ assert.equal(matrix.version,pkg.version);
23
+ assert.equal(matrix.train,'R55');
24
+ assert.equal(sbom.metadata.component.version,pkg.version);
25
+ assert.equal(sbom.serialNumber,'urn:cdx:deadbyte-mcp:r55:0.15.32');
26
+ assert.match(pkg.scripts['gate:windows'],/gate-windows-r55\.ps1/);
27
+ assert.match(pkg.scripts['r55:focused:test'],/r55-offline-predecessor-guardian-family\.test\.mjs/);
28
+ });
29
+
30
+ r55test('R55 source predecessor is exact immutable published 0.15.31 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.31');
33
+ assert.equal(release.parent.release_id,'v0.15.31-16854fe5b3eb0fa1');
34
+ assert.equal(release.parent.manifest_sha256,'16854fe5b3eb0fa1c6dd2b96e3c5d6f792c5adbc91dd2a71e7fc2771472bbdd4');
35
+ assert.equal(release.parent.tarball_sha256,'ff6eba3036cb00ac639ac8907ad6063e6ea8169cf32aca8721f75b1e403e501a');
36
+ assert.equal(release.parent.activation_status,'PUBLISHED_NOT_ACTIVATED');
37
+ assert.equal(release.source_predecessor.version,'0.15.31');
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
+ r55test('R55 records the guardian sibling RED to GREEN and preserves fail-closed negative controls',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.foreground_guardian_owner_parent_binding,true);
53
+ assert.equal(release.hotfix.foreground_guardian_session_nonce_contract,true);
54
+ assert.equal(release.hotfix.unrelated_stale_runtime_fail_closed,true);
55
+ assert.equal(release.hotfix.red_parent_0_15_31,'FAIL_1_OF_4');
56
+ assert.equal(release.hotfix.green_r55_candidate,'PASS_4_OF_4');
57
+ assert.equal(release.hotfix.stable_final_claim,false);
58
+ assert.equal(matrix.observed_pre_release_evidence.red_parent_0_15_31.receipt_sha256,'07ba973aa9224fbb1dde572af35640a1e07ca47273f1e50958d787bfe2aaf429');
59
+ assert.equal(matrix.observed_pre_release_evidence.green_r55_candidate.receipt_sha256,'a217f72cce51a9daf56136f9075ba487adb2a899c291a63af835ea15f8c632f0');
60
+ assert.equal(provenance.operator_override.four_hour_soak,'NOT_COMPLETED');
61
+ assert.equal(provenance.operator_override.stable_final_claim,false);
62
+ assert.equal(matrix.operator_override.stable_final_claim,false);
63
+ });
@@ -0,0 +1,63 @@
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('R56 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.33');
14
+ assert.equal(lock.version,pkg.version);
15
+ assert.equal(lock.packages[''].version,pkg.version);
16
+ assert.match(versionSource,/DEADBYTE_VERSION = '0\.15\.33'/);
17
+ assert.equal(release.version,pkg.version);
18
+ assert.equal(release.train,'R56');
19
+ assert.equal(provenance.version,pkg.version);
20
+ assert.equal(matrix.version,pkg.version);
21
+ assert.equal(matrix.train,'R56');
22
+ assert.equal(sbom.metadata.component.version,pkg.version);
23
+ assert.equal(sbom.serialNumber,'urn:cdx:deadbyte-mcp:r56:0.15.33');
24
+ assert.match(pkg.scripts['gate:windows'],/gate-windows-r56\.ps1/);
25
+ assert.match(pkg.scripts['r56:focused:test'],/r56-rollback-launcher-restore\.test\.mjs/);
26
+ });
27
+
28
+ test('R56 source and runtime predecessor are exact active published 0.15.32',async()=>{
29
+ const [release,provenance]=await Promise.all([json('RELEASE.json'),json('PROVENANCE.json')]);
30
+ assert.equal(release.parent.version,'0.15.32');
31
+ assert.equal(release.parent.release_id,'v0.15.32-e7223f467777f5df');
32
+ assert.equal(release.parent.manifest_sha256,'e7223f467777f5dfeb20fd2cc7a6eca22619a44ed95e5bc0b32d9c7aabba361b');
33
+ assert.equal(release.parent.generation_manifest_sha256,'740443fd207c5e6ffd5952079214bf6e81e9281a6ec880de9bbe3b8ce1deb00e');
34
+ assert.equal(release.parent.tarball_sha256,'c9e1f5875dd2177cee0089305b40321c128c54ce7f5522e34e507d4ecfb22638');
35
+ assert.equal(release.parent.activation_status,'ACTIVATED_ROLLBACK_DEFECT_OBSERVED');
36
+ assert.equal(release.source_predecessor.version,'0.15.32');
37
+ assert.deepEqual(release.runtime_predecessor,{
38
+ release_id:'v0.15.32-e7223f467777f5df',
39
+ manifest_sha256:'e7223f467777f5dfeb20fd2cc7a6eca22619a44ed95e5bc0b32d9c7aabba361b',
40
+ generation_manifest_sha256:'740443fd207c5e6ffd5952079214bf6e81e9281a6ec880de9bbe3b8ce1deb00e'
41
+ });
42
+ assert.equal(provenance.parent_manifest_sha256,release.parent.manifest_sha256);
43
+ assert.equal(provenance.parent_generation_manifest_sha256,release.parent.generation_manifest_sha256);
44
+ assert.deepEqual(provenance.runtime_predecessor,release.runtime_predecessor);
45
+ });
46
+
47
+ test('R56 records signed rollback launcher ordering RED to GREEN and preserves non-final claim',async()=>{
48
+ const [release,provenance,matrix]=await Promise.all([json('RELEASE.json'),json('PROVENANCE.json'),json('TEST-MATRIX.json')]);
49
+ assert.equal(release.hotfix.signed_handoff_launcher_snapshot_required,true);
50
+ assert.equal(release.hotfix.stored_predecessor_verified_without_live_launcher,true);
51
+ assert.equal(release.hotfix.predecessor_launcher_restored_before_pointer_commit,true);
52
+ assert.equal(release.hotfix.successor_launcher_restored_before_recovery_pointer,true);
53
+ assert.equal(release.hotfix.exact_parent_activation_receipt_sha256,'6518a04154f485cfae42e582269634d69a8b05a0183149d5e10006fbdd9d933c');
54
+ assert.equal(release.hotfix.observed_parent_rollback_failure_receipt_sha256,'00cbd497e4902c67ab39313a378e2fcf32159113b46339ad1d54b5e5a7714205');
55
+ assert.equal(release.hotfix.red_parent_0_15_32,'FAIL_5_OF_5');
56
+ assert.equal(release.hotfix.green_r56_candidate,'PASS_5_OF_5');
57
+ assert.equal(matrix.observed_pre_release_evidence.red_parent_0_15_32.receipt_sha256,'f3b446306691d61e97896ab4d237abaa20d1243237299812e790233c46451dba');
58
+ assert.equal(matrix.observed_pre_release_evidence.green_r56_candidate.receipt_sha256,'4198930f38a3fc4b7978cfc94ca4509127561c170b05f7566bdf79513e449a8b');
59
+ assert.equal(release.hotfix.stable_final_claim,false);
60
+ assert.equal(provenance.operator_override.four_hour_soak,'NOT_COMPLETED');
61
+ assert.equal(provenance.operator_override.stable_final_claim,false);
62
+ assert.equal(matrix.operator_override.stable_final_claim,false);
63
+ });