deadbyte-mcp 0.15.70 → 0.15.72

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 (55) hide show
  1. package/MANIFEST.SHA256 +54 -30
  2. package/PROVENANCE.json +64 -15
  3. package/README.txt +19 -11
  4. package/RELEASE.json +76 -17
  5. package/SBOM.cdx.json +2 -2
  6. package/TEST-MATRIX.json +58 -2
  7. package/bridge/package.json +1 -1
  8. package/controller/deadbyte-process-policy.json +4 -4
  9. package/docs/R184-package-lock.json +109 -16
  10. package/docs/R192-LIVE-LOG-HARDENING.txt +39 -0
  11. package/package.json +1 -1
  12. package/scripts/deploy-r48.mjs +17 -4
  13. package/scripts/r191-acceptance-readonly.mjs +7 -0
  14. package/scripts/r191-existing-regression.mjs +5 -0
  15. package/scripts/r191-existing-stage-audit.mjs +21 -0
  16. package/scripts/r191-extended-security-gate.mjs +14 -0
  17. package/scripts/r191-focused-tests.mjs +3 -0
  18. package/scripts/r191-full-runner.mjs +18 -0
  19. package/scripts/r191-historical-release-regression.mjs +9 -0
  20. package/scripts/r191-live-claim-inspect.mjs +15 -0
  21. package/scripts/r191-npm-registry-readonly.mjs +14 -0
  22. package/scripts/r191-old-version-audit.mjs +12 -0
  23. package/scripts/r191-privilege-readonly.mjs +6 -0
  24. package/scripts/r191-process-policy-focused.mjs +1 -0
  25. package/scripts/r191-protected-failure-gate.mjs +3 -0
  26. package/scripts/r191-release-contract-runner.mjs +1 -0
  27. package/scripts/r191-unreached-focused.mjs +29 -0
  28. package/scripts/r192-focused.mjs +10 -0
  29. package/scripts/r192-release-tests.mjs +8 -0
  30. package/src/activation-lock-r65.mjs +9 -1
  31. package/src/deadbyte-cli.mjs +4 -2
  32. package/src/remote-live-log.mjs +22 -1
  33. package/src/runtime-update.mjs +2 -2
  34. package/src/trusted-epoch-bootstrap-r158.mjs +8 -0
  35. package/src/version.mjs +1 -1
  36. package/test/process-policy-refresh.test.mjs +11 -1
  37. package/test/r130-release-security-contract.test.mjs +8 -8
  38. package/test/r132-release-identity.test.mjs +7 -7
  39. package/test/r153-prepublish-identity.test.mjs +1 -1
  40. package/test/r160-release-contract.test.mjs +3 -3
  41. package/test/r165-live-cli-skew.test.mjs +1 -1
  42. package/test/r167-release-contract.test.mjs +11 -11
  43. package/test/r168-release-contract.test.mjs +4 -2
  44. package/test/r172-release-contract.test.mjs +6 -6
  45. package/test/r173-release-contract.test.mjs +15 -15
  46. package/test/r179-release-contract.test.mjs +10 -10
  47. package/test/r190-foreground-cli.test.mjs +14 -4
  48. package/test/r190-release-contract.test.mjs +10 -10
  49. package/test/r191-epoch-root-selection.test.mjs +24 -0
  50. package/test/r191-epoch-source-claim.test.mjs +88 -0
  51. package/test/r191-inherited-epoch-preflight.test.mjs +65 -0
  52. package/test/r191-release-contract.test.mjs +31 -0
  53. package/test/r192-live-log-hardening.test.mjs +50 -0
  54. package/test/r192-release-identity.test.mjs +40 -0
  55. package/test/r59-tool-surface-compat.test.mjs +1 -1
@@ -62,6 +62,19 @@ export function formatRemoteLogResetNotice(file,reason){
62
62
  return '[LIVELOG] RUNTIME_LOG_REOPENED '+name+' — '+detail+'; console diagnostic continuity may have gaps; audit verification is separate';
63
63
  }
64
64
 
65
+ // Bound the foreground reader state to the current discovery snapshot.
66
+ // Audit continuity is still enforced by the signed journal, not this cache.
67
+ export function pruneLiveLogReaders(offsets,partialLines,liveFiles){
68
+ if(!(offsets instanceof Map)||!(partialLines instanceof Map)||
69
+ !Array.isArray(liveFiles)||liveFiles.some(file=>typeof file!=='string'||!file))
70
+ throw new Error('live log reader state invalid');
71
+ const keep=new Set(liveFiles);
72
+ let cursorsRemoved=0,fragmentsRemoved=0;
73
+ for(const file of offsets.keys())if(!keep.has(file)){offsets.delete(file);cursorsRemoved++;}
74
+ for(const file of partialLines.keys())if(!keep.has(file)){partialLines.delete(file);fragmentsRemoved++;}
75
+ return {cursors_removed:cursorsRemoved,fragments_removed:fragmentsRemoved};
76
+ }
77
+
65
78
  export function selectLiveLogNames({auditNames=[],runtimeNames=[]}={}){
66
79
  if(!Array.isArray(auditNames)||!Array.isArray(runtimeNames)) throw new Error('live log names must be arrays');
67
80
  const audit=[...new Set(auditNames.filter(name=>typeof name==='string'&&/^segment-\d{8}\.jsonl$/.test(name)))].sort().slice(-2);
@@ -713,6 +726,14 @@ export function formatRuntimeDiagnosticLine(file,line,{verbose=false,displayMode
713
726
  return remoteDisplayText('['+label+'.DEBUG] OUT '+output[1],displayMode);
714
727
  }
715
728
  const compact=line.match(/^\[TOOL\]\s+(\S+)\s+#(\d+)\s+(✓|✗|OK|ERR)\s+([A-Za-z0-9_.-]+)\s+([^\s]+)(?:\s+—\s+(.+))?$/u);
716
- if(compact) return verbose?remoteDisplayText('['+label+'.DEBUG] #'+compact[2]+' '+compact[3]+' '+compact[4]+' '+compact[5]+(compact[6]?' — '+compact[6]:''),displayMode):null;
729
+ if(compact){
730
+ if(!verbose)return null;
731
+ // Runtime logs are lower-trust diagnostics than signed audit records.
732
+ // Never echo a donor/transport error reason before screening and bounding it.
733
+ const screened=compact[6]?sanitizeAuditArgs(compact[6]):null;
734
+ const reason=typeof screened==='string'?clipped(screened,180):screened?'[REDACTED]':'';
735
+ return remoteDisplayText('['+label+'.DEBUG] #'+compact[2]+' '+compact[3]+' '+compact[4]+' '+compact[5]+
736
+ (reason?' — '+reason:''),displayMode);
737
+ }
717
738
  return null;
718
739
  }
@@ -23,7 +23,7 @@ import {assertStageOwnedPath,assertStagingBootstrapInputs,assertStagingControlCo
23
23
  import { verifyProjectOwnerApproval } from './r70-owner-approval.mjs';
24
24
  import {windowsPowerShellEnvironment} from './windows-powershell-environment.mjs';
25
25
  import {verifyNarrowedPolicyGeneration} from './clean-activation-recovery-r153.mjs';
26
- import {parseProtectedEpochRoot,verifyTrustedEpochRelease} from './trusted-epoch-bootstrap-r158.mjs';
26
+ import {parseProtectedEpochRoot,selectActivationEpochRoot,verifyTrustedEpochRelease} from './trusted-epoch-bootstrap-r158.mjs';
27
27
 
28
28
  export {windowsPowerShellEnvironment};
29
29
 
@@ -1913,7 +1913,7 @@ export async function performSlotUpdate({stage,developmentRoot,expectedVersion,e
1913
1913
  workspace=await workspacePlan(control.workspaceRoot,state);launchers=await launcherPlan(state);
1914
1914
  // A protected installation is an explicit owner-provisioned candidate.
1915
1915
  // No discovery/fallback to writable npm roots and no automatic grant.
1916
- const requestedEpochRoot=authorityEpochRoot??control.config.AuthorityEpochRoot;
1916
+ const requestedEpochRoot=selectActivationEpochRoot({stageRoot,configuredEpochRoot:control.config.AuthorityEpochRoot,explicitEpochRoot:authorityEpochRoot});
1917
1917
  if(requestedEpochRoot){
1918
1918
  const proof=await verifyTrustedEpochRelease({
1919
1919
  epochRoot:requestedEpochRoot,releaseRoot:slot.release_root,
@@ -13,6 +13,14 @@ export function parseProtectedEpochRoot(input){
13
13
  throw new Error('authority epoch root may not be a drive root');
14
14
  return root;
15
15
  }
16
+ // An inherited protected root belongs to the predecessor. Successor bytes
17
+ // must be verified against their own exact, independently ACL-trusted stage.
18
+ export function selectActivationEpochRoot({stageRoot,configuredEpochRoot=null,explicitEpochRoot=null}={}){
19
+ if(explicitEpochRoot!==null)return parseProtectedEpochRoot(explicitEpochRoot);
20
+ if(!configuredEpochRoot)return null;
21
+ parseProtectedEpochRoot(configuredEpochRoot);
22
+ return parseProtectedEpochRoot(stageRoot);
23
+ }
16
24
  // This is a read-only proof, not installation or an authority grant.
17
25
  // Windows ACL verification must run against OS Get-Acl, never a staged snapshot.
18
26
  export async function verifyTrustedEpochRelease({epochRoot,releaseRoot,nodeExecutable}){
package/src/version.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export const DEADBYTE_VERSION = '0.15.70';
1
+ export const DEADBYTE_VERSION = '0.15.72';
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';
@@ -67,7 +67,17 @@ async function fixture() {
67
67
 
68
68
  test('R167 process policy binds coherently to the explicit development root', async () => {
69
69
  const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
70
- const expectedRoot = path.resolve(process.env.DEADBYTE_EXPECTED_DEVELOPMENT_ROOT || repoRoot);
70
+ // The distributed policy is pinned to its explicit development provenance,
71
+ // not to the physical extraction path of the exact immutable npm tarball.
72
+ const release = JSON.parse(await readFile(path.join(repoRoot, 'RELEASE.json'), 'utf8'));
73
+ const approvedRoot = release.r192?.development_policy_root;
74
+ assert.equal(typeof approvedRoot, 'string', 'R191 development policy root must be explicit in release metadata');
75
+ assert.ok(path.isAbsolute(approvedRoot), 'R191 development policy root must be absolute');
76
+ const expectedRoot = path.resolve(approvedRoot);
77
+ if (process.env.DEADBYTE_EXPECTED_DEVELOPMENT_ROOT) {
78
+ assert.equal(path.resolve(process.env.DEADBYTE_EXPECTED_DEVELOPMENT_ROOT), expectedRoot,
79
+ 'caller-supplied development root cannot override R191 release provenance');
80
+ }
71
81
  const policyPath = path.join(repoRoot, 'controller', 'deadbyte-process-policy.json');
72
82
  const policy = JSON.parse(await readFile(policyPath, 'utf8'));
73
83
  assert.equal(path.resolve(policy.roots.core.path), expectedRoot);
@@ -14,14 +14,14 @@ test('current successor retains the R130 security baseline with truthful R190 id
14
14
  read('SBOM.cdx.json'),readReleaseLock(root),read('TEST-MATRIX.json')]);
15
15
  assert.equal(pkg.name,'deadbyte-mcp');
16
16
  for(const actual of [pkg.version,release.version,provenance.version,matrix.version,bom.metadata.component.version,lock.version,lock.packages[''].version,DEADBYTE_VERSION])
17
- assert.equal(actual,'0.15.70');
18
- assert.equal(release.train,'R190');
19
- assert.equal(matrix.train,'R190');
20
- assert.equal(release.source_predecessor.version,'0.15.69');
21
- assert.equal(release.source_predecessor.train,'R179');
22
- assert.match(release.source_predecessor.source_path,/deadbyte-mcp-0\.15\.69\.tgz/i);
23
- assert.equal(release.source_predecessor.manifest_status,'PUBLISHED_PREVIEW_MANIFEST_VERIFIED_NOT_ACTIVE');
24
- assert.equal(release.runtime_predecessor.version,'0.15.68');
17
+ assert.equal(actual,'0.15.72');
18
+ assert.equal(release.train,'R192');
19
+ assert.equal(matrix.train,'R192');
20
+ assert.equal(release.source_predecessor.version,'0.15.71');
21
+ assert.equal(release.source_predecessor.train,'R191');
22
+ assert.match(release.source_predecessor.source_path,/deadbyte-mcp-0\.15\.71\.tgz/i);
23
+ assert.equal(release.source_predecessor.manifest_status,'PUBLISHED_EXACT_MANIFEST_VERIFIED_ACTIVE_PRODUCTION');
24
+ assert.equal(release.runtime_predecessor.version,'0.15.71');
25
25
  assert.equal(provenance.r160.source_predecessor_manifest_status,'STALE_REJECTED');
26
26
  assert.equal(pkg.dependencies['@modelcontextprotocol/client'],'2.3.1');
27
27
  assert.equal(pkg.dependencies['@modelcontextprotocol/server'],'2.3.1');
@@ -16,17 +16,17 @@ test('R190 package identity preserves R132 evidence and published R179 source pr
16
16
  for(const value of [pkg.version,lock.version,lock.packages[''].version,release.version,prov.version,bom.metadata.component.version,matrix.version,DEADBYTE_VERSION]){
17
17
  assert.equal(value,pkg.version);
18
18
  }
19
- assert.equal(release.train,'R190');
20
- assert.equal(matrix.train,'R190');
21
- assert.equal(release.source_predecessor.version,'0.15.69');
22
- assert.equal(release.source_predecessor.train,'R179');
23
- assert.match(release.source_predecessor.source_path,/deadbyte-mcp-0\.15\.69\.tgz/i);
19
+ assert.equal(release.train,'R192');
20
+ assert.equal(matrix.train,'R192');
21
+ assert.equal(release.source_predecessor.version,'0.15.71');
22
+ assert.equal(release.source_predecessor.train,'R191');
23
+ assert.match(release.source_predecessor.source_path,/deadbyte-mcp-0\.15\.71\.tgz/i);
24
24
  assert.equal(prov.r160.source_predecessor_manifest_status,'STALE_REJECTED');
25
25
  assert.equal(release.r165.published_source_manifest_sha256,'4adf7d94682fbb71c4a91eb3147ecc48076bbc5d79cb67fcb875cde6a1bb4805');
26
26
  assert.equal(release.r165.published_source_tarball_sha256,'812e97609b7c51353ed25f2202129737e43bb4fbe0778c3adec43ec065352641');
27
- assert.equal(release.source_predecessor.tarball_sha256,'578c1630608f9df816524c78abc9e1a55357fdc3cd25e142122f1a823e1d69e3');
27
+ assert.equal(release.source_predecessor.tarball_sha256,'20ed3b20e72b4e4226736a1e432b05b851e9fa265e9bc2966b74f266477b7e27');
28
28
  assert.notEqual(release.r179.source_predecessor_tarball_sha256,release.source_predecessor.tarball_sha256);
29
- assert.equal(release.runtime_predecessor.version,'0.15.68');
29
+ assert.equal(release.runtime_predecessor.version,'0.15.71');
30
30
  assert.equal(prov.runtime_predecessor.release_id,release.runtime_predecessor.release_id);
31
31
  assert.equal(prov.runtime_predecessor.manifest_sha256,release.runtime_predecessor.manifest_sha256);
32
32
  assert.equal(prov.runtime_predecessor.generation_manifest_sha256,release.runtime_predecessor.generation_manifest_sha256);
@@ -26,7 +26,7 @@ test('R153 historical verifier refuses current successor package identity',async
26
26
  const state={pkg:JSON.parse(await readFile(path.join(root,'package.json'),'utf8')),
27
27
  release:JSON.parse(await readFile(path.join(root,'RELEASE.json'),'utf8')),
28
28
  bridge:JSON.parse(await readFile(path.join(root,'bridge/package.json'),'utf8'))};
29
- assert.equal(state.pkg.version,'0.15.70');
29
+ assert.equal(state.pkg.version,'0.15.72');
30
30
  assert.throws(()=>verifyR153Lineage(state),/package version/);
31
31
  await assert.rejects(verifyR153IdentityTree(root),/package version/);
32
32
  });
@@ -8,9 +8,9 @@ const read=async rel=>JSON.parse(await readFile(path.join(root,rel),'utf8'));
8
8
 
9
9
  test('R160 historical contract remains distinct from the current package identity',async()=>{
10
10
  const [release,provenance]=await Promise.all([read('RELEASE.json'),read('PROVENANCE.json')]);
11
- assert.equal(release.runtime_predecessor.version,'0.15.68');
12
- assert.equal(release.runtime_predecessor.release_id,'v0.15.68-ff29dbb2fbb89862');
13
- assert.equal(release.runtime_predecessor.manifest_sha256,'ff29dbb2fbb898625592afb47835a4a62ef289429f1e0a89a83242398cd98885');
11
+ assert.equal(release.runtime_predecessor.version,'0.15.71');
12
+ assert.equal(release.runtime_predecessor.release_id,'v0.15.71-1818abc327478a96');
13
+ assert.equal(release.runtime_predecessor.manifest_sha256,'1818abc327478a96d935c200e25aad8515f15edc1842845b73bd0de57606da8c');
14
14
  assert.equal(release.r160.runtime_predecessor_version,'0.15.61');
15
15
  assert.equal(release.r160.source_predecessor_train,'R159');
16
16
  assert.equal(release.r160.public_tool_delta,0);
@@ -17,7 +17,7 @@ const hashMarker=c=>c.repeat(64);
17
17
  async function fixture(t,kind){
18
18
  assert.equal(typeof envRoot,'string'); assert.ok(path.isAbsolute(envRoot));
19
19
  assert.match(sha(await readFile(path.join(envRoot,'MANIFEST.SHA256'))),/^[0-9a-f]{64}$/);
20
- assert.equal(JSON.parse(await readFile(path.join(envRoot,'package.json'),'utf8')).version,'0.15.70');
20
+ assert.equal(JSON.parse(await readFile(path.join(envRoot,'package.json'),'utf8')).version,'0.15.72');
21
21
  const dir=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r164-skew-e2e-'));
22
22
  t.after(async()=>{await rm(dir,{recursive:true,force:true,maxRetries:10,retryDelay:150});});
23
23
  const state=path.join(dir,'state'),bin=path.join(state,'bin');
@@ -8,7 +8,7 @@ import {DEADBYTE_VERSION} from '../src/version.mjs';
8
8
  const root=path.resolve(fileURLToPath(new URL('..',import.meta.url)));
9
9
  const read=async rel=>JSON.parse(await readFile(path.join(root,rel),'utf8'));
10
10
  const readOptional=async rel=>{try{return await read(rel);}catch(error){if(error?.code==='ENOENT')return null;throw error;}};
11
- const VERSION='0.15.70';
11
+ const VERSION='0.15.72';
12
12
  const R166_MANIFEST='ad3c091fbbe2bac6d234548724008b67305fd483ad6542f92d5aeb1aa84f5849';
13
13
  const R166_TARBALL='3d22412c3cebabd66bfa92ca4dbaaf3ef49acba7f92436a16485d7e4cb18c653';
14
14
 
@@ -20,20 +20,20 @@ test('current package identity retains the immutable R167/R173 activation lineag
20
20
  provenance.version,matrix.version,bom.metadata.component.version,DEADBYTE_VERSION];
21
21
  if(lock)versions.push(lock.version,lock.packages[''].version);
22
22
  for(const version of versions)assert.equal(version,VERSION);
23
- assert.equal(release.train,'R190');
24
- assert.equal(matrix.train,'R190');
25
- assert.equal(bom.serialNumber,'urn:cdx:deadbyte-mcp:r190:0.15.70');
23
+ assert.equal(release.train,'R192');
24
+ assert.equal(matrix.train,'R192');
25
+ assert.equal(bom.serialNumber,'urn:cdx:deadbyte-mcp:r192:0.15.72');
26
26
  assert.deepEqual(release.runtime_predecessor,{
27
- version:'0.15.68',release_id:'v0.15.68-ff29dbb2fbb89862',
28
- manifest_sha256:'ff29dbb2fbb898625592afb47835a4a62ef289429f1e0a89a83242398cd98885',
29
- generation_manifest_sha256:'2887d4a8d54ea6fc6b28869072f72491c892dfe28178b3537936dce958147bd2'
27
+ version:'0.15.71',release_id:'v0.15.71-1818abc327478a96',
28
+ manifest_sha256:'1818abc327478a96d935c200e25aad8515f15edc1842845b73bd0de57606da8c',
29
+ generation_manifest_sha256:'aef437280102171a9b68da754fca16a03202104db7d5c420751624580ad6fadc'
30
30
  });
31
- assert.equal(release.source_predecessor.version,'0.15.69');
32
- assert.equal(release.source_predecessor.train,'R179');
33
- assert.equal(release.source_predecessor.tarball_sha256,'578c1630608f9df816524c78abc9e1a55357fdc3cd25e142122f1a823e1d69e3');
31
+ assert.equal(release.source_predecessor.version,'0.15.71');
32
+ assert.equal(release.source_predecessor.train,'R191');
33
+ assert.equal(release.source_predecessor.tarball_sha256,'20ed3b20e72b4e4226736a1e432b05b851e9fa265e9bc2966b74f266477b7e27');
34
34
  assert.equal(release.r173.source_predecessor_version,'0.15.67');
35
35
  assert.equal(release.r167.source_predecessor_manifest_sha256,R166_MANIFEST);
36
- assert.equal(provenance.source_predecessor_manifest_file_sha256,'cfede112761da00e73b626cfbce23d17e1d4b6e3a325bb675415196d31142ba0');
36
+ assert.equal(provenance.source_predecessor_manifest_file_sha256,'1818abc327478a96d935c200e25aad8515f15edc1842845b73bd0de57606da8c');
37
37
  assert.equal(provenance.r173.source_predecessor_manifest_sha256,'4fd7bfc76b1de6401c142b607cc84e847434b28c888bc99ceb09c9e8e5adc8f8');
38
38
  assert.equal(release.r172.source_predecessor_manifest_sha256,'962e227dace247d59aa860211388fbde461c5f9c8a7e8a878e34a14a27d355f8');
39
39
  assert.equal(release.r172.source_predecessor_tarball_sha256,'31b194a4fbff7dbdb9f4f275b4ea49c5115f7b0bb2241c0c72d72ef690311a5d');
@@ -13,8 +13,10 @@ const predecessorTarball='fc3ae5b1505e316bc9dfedf8d063cb00641754c8f5f1306a31f8cc
13
13
 
14
14
  test('R172 preserves the immutable R168 publication lineage separately from current identity',async()=>{
15
15
  const release=await read('RELEASE.json');
16
- assert.equal(release.runtime_predecessor.version,'0.15.68');
17
- assert.equal(release.parent.version,'0.15.68');
16
+ assert.equal(release.runtime_predecessor.version,'0.15.71');
17
+ assert.equal(release.parent.version,'0.15.71');
18
+ assert.equal(release.runtime_predecessor.release_id,'v0.15.71-1818abc327478a96');
19
+ assert.equal(release.parent.release_id,'v0.15.71-1818abc327478a96');
18
20
  assert.notEqual(release.runtime_predecessor.release_id,parent);
19
21
  assert.notEqual(release.parent.release_id,parent);
20
22
  assert.equal(release.r168.scope,'REMOTE_VERSION_SKEW_FAIL_CLOSED_AND_READONLY_RECONCILIATION');
@@ -16,12 +16,12 @@ test('R190 binds the published source predecessor separately from the active run
16
16
  const versions=[pkg.version,bridge.version,release.version,provenance.version,matrix.version,
17
17
  bom.metadata.component.version,DEADBYTE_VERSION];
18
18
  if(lock)versions.push(lock.version,lock.packages[''].version);
19
- for(const value of versions)assert.equal(value,'0.15.70');
20
- assert.equal(release.train,'R190'); assert.equal(matrix.train,'R190');
21
- assert.equal(release.source_predecessor.version,'0.15.69');
22
- assert.equal(release.source_predecessor.manifest_sha256,'cfede112761da00e73b626cfbce23d17e1d4b6e3a325bb675415196d31142ba0');
23
- assert.equal(release.source_predecessor.tarball_sha256,'578c1630608f9df816524c78abc9e1a55357fdc3cd25e142122f1a823e1d69e3');
24
- assert.equal(release.runtime_predecessor.release_id,'v0.15.68-ff29dbb2fbb89862');
19
+ for(const value of versions)assert.equal(value,'0.15.72');
20
+ assert.equal(release.train,'R192'); assert.equal(matrix.train,'R192');
21
+ assert.equal(release.source_predecessor.version,'0.15.71');
22
+ assert.equal(release.source_predecessor.manifest_sha256,'1818abc327478a96d935c200e25aad8515f15edc1842845b73bd0de57606da8c');
23
+ assert.equal(release.source_predecessor.tarball_sha256,'20ed3b20e72b4e4226736a1e432b05b851e9fa265e9bc2966b74f266477b7e27');
24
+ assert.equal(release.runtime_predecessor.release_id,'v0.15.71-1818abc327478a96');
25
25
  assert.equal(release.r173.public_tool_delta,0); assert.equal(release.r173.authority_scope_delta,0);
26
26
  });
27
27
 
@@ -13,21 +13,21 @@ test('R190 package identity binds the exact published R179 source and live runti
13
13
  json('package.json'),readReleaseLock(root),json('bridge/package.json'),json('RELEASE.json'),
14
14
  json('PROVENANCE.json'),json('TEST-MATRIX.json'),json('SBOM.cdx.json')
15
15
  ]);
16
- assert.equal(pkg.version,'0.15.70');
17
- assert.equal(lock.version,'0.15.70');
18
- assert.equal(lock.packages[''].version,'0.15.70');
19
- assert.equal(bridge.version,'0.15.70');
20
- assert.equal(release.version,'0.15.70');
21
- assert.equal(release.train,'R190');
22
- assert.equal(matrix.version,'0.15.70');
23
- assert.equal(matrix.train,'R190');
24
- assert.equal(sbom.metadata.component.version,'0.15.70');
25
- assert.equal(release.source_predecessor.version,'0.15.69');
26
- assert.equal(release.source_predecessor.train,'R179');
27
- assert.equal(release.source_predecessor.manifest_sha256,'cfede112761da00e73b626cfbce23d17e1d4b6e3a325bb675415196d31142ba0');
28
- assert.equal(release.source_predecessor.tarball_sha256,'578c1630608f9df816524c78abc9e1a55357fdc3cd25e142122f1a823e1d69e3');
29
- assert.equal(release.runtime_predecessor.version,'0.15.68');
30
- assert.equal(provenance.version,'0.15.70');
16
+ assert.equal(pkg.version,'0.15.72');
17
+ assert.equal(lock.version,'0.15.72');
18
+ assert.equal(lock.packages[''].version,'0.15.72');
19
+ assert.equal(bridge.version,'0.15.72');
20
+ assert.equal(release.version,'0.15.72');
21
+ assert.equal(release.train,'R192');
22
+ assert.equal(matrix.version,'0.15.72');
23
+ assert.equal(matrix.train,'R192');
24
+ assert.equal(sbom.metadata.component.version,'0.15.72');
25
+ assert.equal(release.source_predecessor.version,'0.15.71');
26
+ assert.equal(release.source_predecessor.train,'R191');
27
+ assert.equal(release.source_predecessor.manifest_sha256,'1818abc327478a96d935c200e25aad8515f15edc1842845b73bd0de57606da8c');
28
+ assert.equal(release.source_predecessor.tarball_sha256,'20ed3b20e72b4e4226736a1e432b05b851e9fa265e9bc2966b74f266477b7e27');
29
+ assert.equal(release.runtime_predecessor.version,'0.15.71');
30
+ assert.equal(provenance.version,'0.15.72');
31
31
  assert.equal(provenance.parent_tarball_sha256,release.source_predecessor.tarball_sha256);
32
32
  assert.equal(provenance.source_predecessor_manifest_file_sha256,release.source_predecessor.manifest_sha256);
33
33
  });
@@ -7,23 +7,23 @@ import {DEADBYTE_VERSION} from '../src/version.mjs';
7
7
  import {readReleaseLock} from './helpers/release-lock.mjs';
8
8
  const root=path.resolve(fileURLToPath(new URL('..',import.meta.url)));
9
9
  const read=async file=>JSON.parse(await readFile(path.join(root,file),'utf8'));
10
- const parent='v0.15.68-ff29dbb2fbb89862';
11
- const manifest='ff29dbb2fbb898625592afb47835a4a62ef289429f1e0a89a83242398cd98885';
12
- const generation='2887d4a8d54ea6fc6b28869072f72491c892dfe28178b3537936dce958147bd2';
10
+ const parent='v0.15.71-1818abc327478a96';
11
+ const manifest='1818abc327478a96d935c200e25aad8515f15edc1842845b73bd0de57606da8c';
12
+ const generation='aef437280102171a9b68da754fca16a03202104db7d5c420751624580ad6fadc';
13
13
  const tarball='1a7f1fe05a06178b8d772a140be6e0470790b743cef690c3f8f8165cc61075bf';
14
14
  test('R190 version, lock snapshot, bridge, matrix, SBOM and provenance identify exact 0.15.70 successor',async()=>{
15
15
  const [pkg,lock,bridge,release,provenance,matrix,sbom]=await Promise.all([
16
16
  read('package.json'),readReleaseLock(root),read('bridge/package.json'),read('RELEASE.json'),
17
17
  read('PROVENANCE.json'),read('TEST-MATRIX.json'),read('SBOM.cdx.json')]);
18
18
  for(const version of [pkg.version,lock.version,lock.packages[''].version,bridge.version,release.version,provenance.version,
19
- matrix.version,sbom.metadata.component.version,DEADBYTE_VERSION])assert.equal(version,'0.15.70');
20
- assert.equal(release.train,'R190');assert.equal(matrix.train,'R190');
21
- assert.equal(sbom.serialNumber,'urn:cdx:deadbyte-mcp:r190:0.15.70');
19
+ matrix.version,sbom.metadata.component.version,DEADBYTE_VERSION])assert.equal(version,'0.15.72');
20
+ assert.equal(release.train,'R192');assert.equal(matrix.train,'R192');
21
+ assert.equal(sbom.serialNumber,'urn:cdx:deadbyte-mcp:r192:0.15.72');
22
22
  assert.equal(release.parent.release_id,parent);assert.equal(release.parent.manifest_sha256,manifest);
23
23
  assert.equal(release.parent.generation_manifest_sha256,generation);
24
- assert.equal(release.source_predecessor.version,'0.15.69');
25
- assert.equal(release.source_predecessor.manifest_sha256,'cfede112761da00e73b626cfbce23d17e1d4b6e3a325bb675415196d31142ba0');
26
- assert.equal(release.source_predecessor.tarball_sha256,'578c1630608f9df816524c78abc9e1a55357fdc3cd25e142122f1a823e1d69e3');
24
+ assert.equal(release.source_predecessor.version,'0.15.71');
25
+ assert.equal(release.source_predecessor.manifest_sha256,'1818abc327478a96d935c200e25aad8515f15edc1842845b73bd0de57606da8c');
26
+ assert.equal(release.source_predecessor.tarball_sha256,'20ed3b20e72b4e4226736a1e432b05b851e9fa265e9bc2966b74f266477b7e27');
27
27
  assert.equal(release.runtime_predecessor.release_id,parent);
28
28
  assert.equal(provenance.runtime_predecessor.release_id,parent);
29
29
  assert.equal(provenance.parent_tarball_sha256,release.source_predecessor.tarball_sha256);
@@ -48,7 +48,7 @@ test('R190 retains historical R179 and R173 source evidence without promoting it
48
48
  assert.equal(release.r173.source_predecessor_version,'0.15.67');
49
49
  assert.equal(release.r173.source_predecessor_manifest_sha256,'4fd7bfc76b1de6401c142b607cc84e847434b28c888bc99ceb09c9e8e5adc8f8');
50
50
  assert.equal(prov.r173.source_predecessor_version,'0.15.67');
51
- assert.equal(release.source_predecessor.version,'0.15.69');
51
+ assert.equal(release.source_predecessor.version,'0.15.71');
52
52
  assert.notEqual(release.source_predecessor.tarball_sha256,release.r173.source_predecessor_tarball_sha256);
53
53
  });
54
54
  test('R184 ships a semantic lock snapshot matching installed package identity and dependencies',async()=>{
@@ -1,13 +1,17 @@
1
1
  import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import {spawnSync} from 'node:child_process';
4
+ import {mkdtemp,stat,rm} from 'node:fs/promises';
5
+ import os from 'node:os';
4
6
  import path from 'node:path';
5
7
  import {fileURLToPath} from 'node:url';
6
8
  import {inspectTrustedInstallation} from '../src/privileged-install-trust-r89.mjs';
7
9
 
8
10
  const root=path.dirname(path.dirname(fileURLToPath(import.meta.url)));
9
11
 
10
- test('R190 CLI exposes explicit marker recovery and applies the R89 trust boundary before mutation',async()=>{
12
+ test('R190 CLI proves R89 before touching isolated controller and fails closed on absent launcher',async t=>{
13
+ const stateRoot=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r191-r190-cli-'));
14
+ t.after(()=>rm(stateRoot,{recursive:true,force:true}));
11
15
  const installation=await inspectTrustedInstallation([
12
16
  process.execPath,
13
17
  path.join(root,'src','deadbyte-cli.mjs'),
@@ -21,11 +25,17 @@ test('R190 CLI exposes explicit marker recovery and applies the R89 trust bounda
21
25
  path.join(root,'bin','deadbyte-epoch-lock-r85.node')
22
26
  ]).catch(()=>({trusted:false}));
23
27
  const result=spawnSync(process.execPath,['src/deadbyte-cli.mjs','remote','reconcileforeground',
24
- '--confirm-marker-sha256','f'.repeat(64)],{encoding:'utf8',windowsHide:true,shell:false});
28
+ '--confirm-marker-sha256','f'.repeat(64)],{encoding:'utf8',windowsHide:true,shell:false,
29
+ env:{...process.env,DEADBYTE_STATE_ROOT:stateRoot}});
25
30
  const output=String(result.stdout||'')+String(result.stderr||'');
26
31
  assert.notEqual(result.status,0,output);
27
- if(installation.trusted) assert.match(output,/marker (?:hash differs from explicit confirmation|absent without a durable R190 intent)/);
28
- else assert.match(output,/R190_PROTECTED_RECOVERY_REQUIRED/);
32
+ if(installation.trusted){
33
+ // R89 succeeded, but this isolated fixture has no controller launcher.
34
+ // The test must fail closed before foreground marker or production access.
35
+ assert.match(output,/ENOENT: no such file or directory, lstat .*DEADBYTE-MCP\.ps1/);
36
+ }else assert.match(output,/R190_PROTECTED_RECOVERY_REQUIRED/);
37
+ await assert.rejects(stat(path.join(stateRoot,'evidence','foreground-recovery-r190')),{code:'ENOENT'});
38
+ await assert.rejects(stat(path.join(stateRoot,'runtime','remote-session.json')),{code:'ENOENT'});
29
39
  assert.doesNotMatch(output,/unsupported remote command|EXACT_ACTIVE_RELEASE_REQUIRED/);
30
40
  });
31
41
 
@@ -8,17 +8,17 @@ test('R190 candidate identity separates published source 0.15.69 from active run
8
8
  json('package.json'),json('bridge/package.json'),json('RELEASE.json'),json('PROVENANCE.json'),
9
9
  json('TEST-MATRIX.json'),json('SBOM.cdx.json'),readFile(new URL('../src/version.mjs',import.meta.url),'utf8')]);
10
10
  for(const value of [pkg.version,bridge.version,release.version,provenance.version,matrix.version,
11
- sbom.metadata.component.version])assert.equal(value,'0.15.70');
12
- assert.match(versionSource,/DEADBYTE_VERSION = '0\.15\.70'/);
13
- assert.equal(release.train,'R190');assert.equal(matrix.train,'R190');
14
- assert.equal(release.source_predecessor.version,'0.15.69');
15
- assert.equal(release.source_predecessor.tarball_sha256,'578c1630608f9df816524c78abc9e1a55357fdc3cd25e142122f1a823e1d69e3');
16
- assert.equal(release.source_predecessor.manifest_sha256,'cfede112761da00e73b626cfbce23d17e1d4b6e3a325bb675415196d31142ba0');
17
- assert.equal(release.runtime_predecessor.version,'0.15.68');
18
- assert.equal(release.runtime_predecessor.release_id,'v0.15.68-ff29dbb2fbb89862');
19
- assert.equal(provenance.source_predecessor_version,'0.15.69');
11
+ sbom.metadata.component.version])assert.equal(value,'0.15.72');
12
+ assert.match(versionSource,/DEADBYTE_VERSION = '0\.15\.72'/);
13
+ assert.equal(release.train,'R192');assert.equal(matrix.train,'R192');
14
+ assert.equal(release.source_predecessor.version,'0.15.71');
15
+ assert.equal(release.source_predecessor.tarball_sha256,'20ed3b20e72b4e4226736a1e432b05b851e9fa265e9bc2966b74f266477b7e27');
16
+ assert.equal(release.source_predecessor.manifest_sha256,'1818abc327478a96d935c200e25aad8515f15edc1842845b73bd0de57606da8c');
17
+ assert.equal(release.runtime_predecessor.version,'0.15.71');
18
+ assert.equal(release.runtime_predecessor.release_id,'v0.15.71-1818abc327478a96');
19
+ assert.equal(provenance.source_predecessor_version,'0.15.71');
20
20
  assert.equal(provenance.source_predecessor_tarball_sha256,release.source_predecessor.tarball_sha256);
21
- assert.match(sbom.serialNumber,/r190:0\.15\.70$/);
21
+ assert.match(sbom.serialNumber,/r192:0\.15\.72$/);
22
22
  });
23
23
 
24
24
  test('R190 release metadata records verified recovery without claiming publication or activation',async()=>{
@@ -0,0 +1,24 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import * as epoch from '../src/trusted-epoch-bootstrap-r158.mjs';
4
+
5
+ const predecessor='C:\\Program Files\\DEADBYTE-R173-Protected-0.15.68-ff29dbb2fbb89862-Test';
6
+ const candidate='C:\\Program Files\\DEADBYTE-01571-REGISTRY-candidate';
7
+ test('R191 inherited predecessor epoch is rebound to exact successor staging root',()=>{
8
+ assert.equal(epoch.selectActivationEpochRoot({
9
+ configuredEpochRoot:predecessor,explicitEpochRoot:null,stageRoot:candidate
10
+ }),candidate);
11
+ });
12
+ test('R191 no inherited epoch does not create an authority epoch path',()=>{
13
+ assert.equal(epoch.selectActivationEpochRoot({
14
+ configuredEpochRoot:null,explicitEpochRoot:null,stageRoot:candidate
15
+ }),null);
16
+ });
17
+ test('R191 explicit epoch root remains exact and invalid paths reject',()=>{
18
+ assert.equal(epoch.selectActivationEpochRoot({
19
+ configuredEpochRoot:predecessor,explicitEpochRoot:candidate,stageRoot:candidate
20
+ }),candidate);
21
+ assert.throws(()=>epoch.selectActivationEpochRoot({
22
+ configuredEpochRoot:predecessor,explicitEpochRoot:'..\\writable',stageRoot:candidate
23
+ }),/absolute|root|path/i);
24
+ });
@@ -0,0 +1,88 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {createHash,generateKeyPairSync,sign} from 'node:crypto';
4
+ import {mkdir,mkdtemp,readFile,rm,writeFile} from 'node:fs/promises';
5
+ import os from 'node:os';
6
+ import path from 'node:path';
7
+ import {canonicalJson} from '../src/canonical-json.mjs';
8
+ import {createActivationClaimManager} from '../src/activation-lock-r65.mjs';
9
+
10
+ const sha=v=>createHash('sha256').update(v).digest('hex');
11
+ const DOMAIN=Buffer.from('DEADBYTE-R27-SLOT-UPDATE-V1\\0'.replace('\\0','\0'),'utf8');
12
+ const manifest='d'.repeat(64);
13
+ function receipt(body,key){
14
+ const bytes=Buffer.from(canonicalJson(body));
15
+ const signed=sign(null,Buffer.concat([DOMAIN,bytes]),key.privateKey);
16
+ const payload={body,body_sha256:sha(bytes),
17
+ attestation:{algorithm:'ed25519',domain:'DEADBYTE-R27-SLOT-UPDATE-V1',
18
+ key_id:sha(key.publicKey.export({type:'spki',format:'der'})),signature_base64:signed.toString('base64')}};
19
+ payload.receipt_sha256=sha(Buffer.from(canonicalJson(payload)));
20
+ return payload;
21
+ }
22
+ async function fixture({tamper=false,drift=false}={}){
23
+ const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r191-r65-'));
24
+ const updates=path.join(root,'evidence','updates'),trust=path.join(root,'trust');
25
+ await mkdir(updates,{recursive:true});await mkdir(trust,{recursive:true});
26
+ const key=generateKeyPairSync('ed25519');
27
+ await writeFile(path.join(trust,'ed25519-public.pem'),key.publicKey.export({type:'spki',format:'pem'}));
28
+ const prior={schema:'deadbyte.active-release.v1',release_id:'v0.15.68-ff29dbb2fbb89862',
29
+ version:'0.15.68',manifest_sha256:'f'.repeat(64),generation_manifest_sha256:'a'.repeat(64)};
30
+ await writeFile(path.join(root,'active-release.json'),JSON.stringify(drift?{...prior,release_id:'v0-other'}:prior));
31
+ const manager=createActivationClaimManager({stateRoot:root}),subject='b'.repeat(64);
32
+ const claim=await manager.claim(subject);
33
+ const updateId='r27-'+manifest.slice(0,16)+'-r191proof';
34
+ const dir=path.join(updates,updateId);await mkdir(dir);
35
+ const body={schema:'deadbyte.r27-slot-update-failure.v1',update_id:updateId,
36
+ release_version:'0.15.70',candidate_manifest_sha256:manifest,
37
+ failed_at_utc:new Date().toISOString(),result:'PRECONDITION_REJECTED',phase:'initial',
38
+ error:{name:'Error',code:null,message:'authority epoch exact release source hash mismatch: manifest.sha256'},
39
+ prior_pointer:prior,attempted_pointer:null,
40
+ rollback:{attempted:false,errors:[]}};
41
+ const signed=receipt(body,key);
42
+ if(tamper)signed.body.error.message='altered message';
43
+ await writeFile(path.join(dir,'failure-receipt.json'),JSON.stringify(signed));
44
+ await writeFile(path.join(updates,'r65-activation-outcome-r191.json'),JSON.stringify({
45
+ schema:'deadbyte.r65-activation-outcome.v1',claim_operation_id:claim.operation_id,
46
+ preflight_subject_sha256:subject,candidate_version:'0.15.70',
47
+ candidate_manifest_sha256:manifest,predecessor_release_id:prior.release_id,
48
+ outcome:{state:'ACTIVATION_OUTCOME_UNKNOWN',reason:body.error.message},
49
+ update_id:null,state_path:null,continuity_update_id:null,observed_at_utc:new Date().toISOString()
50
+ }));
51
+ return {root,manager,claim};
52
+ }
53
+ test('R191 signed initial epoch source mismatch may reconcile an R65 claim with unchanged predecessor',async()=>{
54
+ const f=await fixture();
55
+ try{const next=await f.manager.claim('c'.repeat(64));
56
+ assert.notEqual(next.operation_id,f.claim.operation_id);await next.release();
57
+ }finally{await rm(f.root,{recursive:true,force:true});}
58
+ });
59
+ test('R191 tampered signed failure receipt cannot reconcile R65 claim',async()=>{
60
+ const f=await fixture({tamper:true});
61
+ try{await assert.rejects(()=>f.manager.claim('c'.repeat(64)),/unresolved|in progress/);}
62
+ finally{await rm(f.root,{recursive:true,force:true});}
63
+ });
64
+ test('R191 changed predecessor pointer cannot reconcile R65 claim',async()=>{
65
+ const f=await fixture({drift:true});
66
+ try{await assert.rejects(()=>f.manager.claim('c'.repeat(64)),/unresolved|in progress/);}
67
+ finally{await rm(f.root,{recursive:true,force:true});}
68
+ });
69
+
70
+
71
+ test('R191 read-only inspection reports a safe signed precondition claim without reclaiming it',async()=>{
72
+ const f=await fixture();
73
+ try{
74
+ const before=await readFile(path.join(f.root,'evidence','updates','r65-activation.lock'),'utf8');
75
+ const audit=await f.manager.inspect();
76
+ assert.equal(audit.status,'RECONCILABLE');
77
+ assert.equal(audit.operation_id,f.claim.operation_id);
78
+ const after=await readFile(path.join(f.root,'evidence','updates','r65-activation.lock'),'utf8');
79
+ assert.equal(after,before);
80
+ }finally{await rm(f.root,{recursive:true,force:true});}
81
+ });
82
+ test('R191 read-only inspection leaves a tampered evidence claim blocked',async()=>{
83
+ const f=await fixture({tamper:true});
84
+ try{
85
+ const audit=await f.manager.inspect();
86
+ assert.equal(audit.status,'UNRESOLVED');
87
+ }finally{await rm(f.root,{recursive:true,force:true});}
88
+ });
@@ -0,0 +1,65 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {mkdtemp,mkdir,readFile,readdir,rm,writeFile} from 'node:fs/promises';
4
+ import {spawnSync} from 'node:child_process';
5
+ import {createHash} from 'node:crypto';
6
+ import os from 'node:os';
7
+ import path from 'node:path';
8
+ import {fileURLToPath} from 'node:url';
9
+ const src=path.resolve(fileURLToPath(new URL('..',import.meta.url)));
10
+ const H=b=>createHash('sha256').update(b).digest('hex');
11
+
12
+ test('R191 real preflight rejects writable staging when predecessor has a protected epoch', {skip:process.platform!=='win32'}, async()=>{
13
+ const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r191-preflight-'));
14
+ try{
15
+ const state=path.join(root,'state'),bin=path.join(state,'bin'),gen=path.join(state,'generations','parent'),policies=path.join(state,'policies');
16
+ await Promise.all([mkdir(bin,{recursive:true}),mkdir(gen,{recursive:true}),mkdir(policies,{recursive:true}),mkdir(path.join(state,'runtime'),{recursive:true})]);
17
+ const release=JSON.parse(await readFile(path.join(src,'RELEASE.json'),'utf8'));
18
+ const configFields={process:'ProcessPolicyFile',coding:'CodingPolicyFile',autonomous:'AutonomousPolicyFile',desktop:'DesktopPolicyFile',host:'HostPolicyFile'};
19
+ const policyPaths={};
20
+ for(const plane of Object.keys(configFields)){
21
+ const f=path.join(policies,plane+'.json');
22
+ const grant=path.join(state,'runtime',plane+'-grant.json');
23
+ const grantField=plane==='host'?'arm_file':plane==='process'||plane==='desktop'?'grant_file':'lease_file';
24
+ await writeFile(f,JSON.stringify({schema:plane==='host'?'deadbyte.host-policy.v2':'deadbyte.'+plane+'-policy.v1',enabled:true,[grantField]:grant}));
25
+ policyPaths[configFields[plane]]=f;
26
+ }
27
+ const configPath=path.join(gen,'controller-config.psd1');
28
+ const epoch='C:\\Program Files\\DEADBYTE-R173-Protected-0.15.68-ff29dbb2fbb89862-Test';
29
+ await writeFile(configPath,'@{ '+Object.entries({...policyPaths,AuthorityEpochRoot:epoch}).map(([k,v])=>k+" = '"+v.replaceAll("'","''")+"'").join('; ')+' }');
30
+ const pointer={schema:'deadbyte.active-release.v1',...release.parent,release_root:path.join(state,'releases',release.parent.release_id),generation_root:gen,
31
+ launcher_sha256:H('launcher'),config_path:configPath};
32
+ const pointerBytes=Buffer.from(JSON.stringify(pointer));
33
+ await writeFile(path.join(state,'active-release.json'),pointerBytes);
34
+ const disarmed={configured:true,armed:false,reason:'disarmed'};
35
+ const observation={schema:'deadbyte.controller-observation.v1',state:'ONLINE',local_ready:true,
36
+ bridge:{alive:true,reason:'verified',pid:111},core:{alive:true,reason:'verified',pid:112},
37
+ cloud:{alive:true,reason:'verified',pid:113},supervisor:{running:true},
38
+ authority:Object.fromEntries(Object.keys(configFields).map(plane=>[plane,disarmed]))};
39
+ const observed=path.join(state,'observed.json');await writeFile(observed,JSON.stringify(observation));
40
+ const ps="param([string]$Command,[switch]$Json)\nif($Command -ne 'status' -or -not $Json){throw 'unexpected mutation'}\nGet-Content -Raw -LiteralPath '"+observed.replaceAll("'","''")+"'\n";
41
+ await writeFile(path.join(bin,'DEADBYTE-MCP.ps1'),ps);
42
+ const result=spawnSync(process.execPath,[path.join(src,'scripts','deploy-r48.mjs'),'--preflight'],{
43
+ env:{...process.env,DEADBYTE_STATE_ROOT:state},cwd:src,encoding:'utf8',timeout:30000,windowsHide:true});
44
+ assert.equal(result.status,0,result.stderr);
45
+ const preflight=JSON.parse(result.stdout.trim());
46
+ assert.equal(preflight.state,'ONLINE_READY');
47
+ assert.equal(preflight.authority_continuity,'NOT_APPLICABLE');
48
+ // The same exact release may execute from a writable developer tree
49
+ // or from an R89-protected immutable installation. The decision must
50
+ // follow OS ACL trust, not the test file's assumed extraction location.
51
+ const {inspectTrustedInstallation,privilegedEpochInstallFiles}=await import('../src/privileged-install-trust-r89.mjs');
52
+ let stageTrusted=false;
53
+ try {
54
+ const trust=await inspectTrustedInstallation(privilegedEpochInstallFiles(src,process.execPath));
55
+ stageTrusted=trust.trusted===true;
56
+ } catch {stageTrusted=false;}
57
+ assert.equal(preflight.safe_to_activate,stageTrusted);
58
+ assert.equal(preflight.activation_entrypoint_state,stageTrusted?'TRUSTED_READY':'REJECTED');
59
+ assert.equal(preflight.protected_activation_entrypoint,stageTrusted);
60
+ if(stageTrusted)assert.equal(preflight.activation_entrypoint_reason,null);
61
+ else assert.match(preflight.activation_entrypoint_reason,/R89|ACL|protected/i);
62
+ assert.equal(H(await readFile(path.join(state,'active-release.json'))),H(pointerBytes));
63
+ await assert.rejects(readdir(path.join(state,'evidence','updates')),e=>e?.code==='ENOENT');
64
+ } finally {await rm(root,{recursive:true,force:true});}
65
+ });