deadbyte-mcp 0.15.47 → 0.15.49

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 (112) hide show
  1. package/MANIFEST.SHA256 +111 -48
  2. package/PROVENANCE.json +1 -1
  3. package/README.txt +18 -18
  4. package/RELEASE.json +3 -3
  5. package/SBOM.cdx.json +2 -2
  6. package/TEST-MATRIX.json +2 -2
  7. package/bench/r121-epoch-readhead.mjs +54 -0
  8. package/bench/r124-epoch-predecessor.mjs +53 -0
  9. package/bin/deadbyte-epoch-lock-r85.node +0 -0
  10. package/controller/deadbyte-process-policy.json +4 -4
  11. package/docs/HARNESS2-ADAPTATION-20261020.md +24 -0
  12. package/docs/R128-RELEASE-CANDIDATE.md +26 -0
  13. package/docs/R75-RECOVERY-HANDOFF.md +16 -0
  14. package/docs/R85-EPOCH-LOCK-BINARY.json +13 -0
  15. package/native/deadbyte-epoch-lock-r85.cpp +241 -0
  16. package/package.json +1 -1
  17. package/scripts/build-epoch-lock-r85.ps1 +34 -0
  18. package/scripts/deploy-r48.mjs +3 -1
  19. package/scripts/npm-release-r48.mjs +18 -4
  20. package/scripts/r75-npm-bin-integrity-gate.mjs +33 -0
  21. package/scripts/release-manifest.mjs +1 -1
  22. package/scripts/verify-authority-epoch-history.mjs +38 -0
  23. package/scripts/verify-r70-full-regression.ps1 +12 -2
  24. package/src/activation-authority-proof-r75.mjs +67 -0
  25. package/src/activation-continuity-engine-r65.mjs +17 -10
  26. package/src/activation-preflight-r65.mjs +13 -0
  27. package/src/agent-eval-r42.mjs +30 -0
  28. package/src/authority-continuity-r65.mjs +442 -29
  29. package/src/autonomous-local-supervisor.mjs +77 -47
  30. package/src/deadbyte-cli.mjs +73 -46
  31. package/src/epoch-lock-r85.mjs +48 -0
  32. package/src/foreground-marker-cas-win32.mjs +284 -0
  33. package/src/foreground-process-identity.mjs +3 -3
  34. package/src/privileged-install-trust-r89.mjs +196 -0
  35. package/src/remote-live-log.mjs +15 -8
  36. package/src/remote-log-decode-r60.mjs +65 -0
  37. package/src/remote-session-guardian.mjs +13 -12
  38. package/src/runtime-update.mjs +5 -22
  39. package/src/version.mjs +1 -1
  40. package/src/windows-powershell-environment.mjs +24 -0
  41. package/test/autonomous-local-supervisor.test.mjs +1 -1
  42. package/test/cli-entrypoint.test.mjs +1 -1
  43. package/test/harness2-eval-context-isolation.test.mjs +90 -0
  44. package/test/helpers/r75-authority-proof.mjs +9 -0
  45. package/test/r100-posix-owned-lock-race.test.mjs +72 -0
  46. package/test/r101-acl-probe-environment.test.mjs +51 -0
  47. package/test/r106-trusted-powershell-spawn.test.mjs +53 -0
  48. package/test/r107-updater-powershell-path.test.mjs +77 -0
  49. package/test/r108-remote-powershell-path.test.mjs +59 -0
  50. package/test/r110-supervisor-powershell-path.test.mjs +28 -0
  51. package/test/r111-supervisor-marker-cas.test.mjs +116 -0
  52. package/test/r112-supervisor-claim-cas.test.mjs +63 -0
  53. package/test/r113-supervisor-cleanup-terminality.test.mjs +100 -0
  54. package/test/r114-supervisor-absence-proof.test.mjs +45 -0
  55. package/test/r115-posix-continuity-entrypoint.test.mjs +17 -0
  56. package/test/r116-authority-crash-matrix.test.mjs +83 -0
  57. package/test/r117-concurrent-orphan-recovery.test.mjs +54 -0
  58. package/test/r118-cross-process-orphan-recovery.test.mjs +99 -0
  59. package/test/r119-recovery-crash-after-commit.test.mjs +91 -0
  60. package/test/r120-authority-history-audit.test.mjs +103 -0
  61. package/test/r121-signed-transition-invariant.test.mjs +132 -0
  62. package/test/r122-epoch-bounded-read.test.mjs +58 -0
  63. package/test/r123-recovery-bounded-read.test.mjs +64 -0
  64. package/test/r124-live-log-integrity.test.mjs +66 -0
  65. package/test/r124-live-log-tail-boundaries.test.mjs +57 -0
  66. package/test/r124-signed-predecessor-shape.test.mjs +66 -0
  67. package/test/r125-restore-binding-types.test.mjs +63 -0
  68. package/test/r126-restore-policy-envelope.test.mjs +89 -0
  69. package/test/r127-restore-append-policy-boundary.test.mjs +25 -0
  70. package/test/r33-closeout-regression.test.mjs +2 -1
  71. package/test/r54-offline-predecessor-self-exclusion.test.mjs +2 -2
  72. package/test/r55-offline-predecessor-guardian-family.test.mjs +2 -2
  73. package/test/r56-rollback-launcher-restore.test.mjs +2 -2
  74. package/test/r57-core-startup-race.test.mjs +2 -2
  75. package/test/r58-concurrent-recovery.test.mjs +10 -7
  76. package/test/r58-stale-owner.test.mjs +5 -6
  77. package/test/r59-tool-surface-compat.test.mjs +1 -1
  78. package/test/r65-activation-orchestration.test.mjs +2 -1
  79. package/test/r65-activation-preflight.test.mjs +7 -6
  80. package/test/r65-authority-epoch-recovery.test.mjs +3 -1
  81. package/test/r65-authority-epoch-store.test.mjs +9 -6
  82. package/test/r65-authority-restored-safe.test.mjs +2 -1
  83. package/test/r65-deploy-preflight.test.mjs +13 -14
  84. package/test/r65-epoch-native-activation-integration.test.mjs +5 -4
  85. package/test/r65-legacy-authority-migration.test.mjs +2 -1
  86. package/test/r67-npm-cross-volume.test.mjs +9 -2
  87. package/test/r71-full-verifier-artifact.test.mjs +21 -15
  88. package/test/r71-isolated-slot-rollback-restore.test.mjs +3 -1
  89. package/test/r71-release-identity.test.mjs +3 -1
  90. package/test/r74-kernel-lock.test.mjs +12 -6
  91. package/test/r74-prepublish-contract.test.mjs +3 -1
  92. package/test/r75-activation-authority-proof.test.mjs +46 -0
  93. package/test/r75-authority-evidence.test.mjs +77 -0
  94. package/test/r76-pinned-marker-cas.test.mjs +78 -0
  95. package/test/r77-epoch-grant-cas.test.mjs +51 -0
  96. package/test/r78-parent-junction-cas.test.mjs +62 -0
  97. package/test/r79-orphan-revocation-reconcile.test.mjs +88 -0
  98. package/test/r79-windows-fsync-regression.test.mjs +45 -0
  99. package/test/r80-durable-epoch-commit.test.mjs +76 -0
  100. package/test/r82-epoch-lock-owned-cas.test.mjs +93 -0
  101. package/test/r83-epoch-lock-fileid-cas.test.mjs +92 -0
  102. package/test/r84-epoch-lock-created-fileid.test.mjs +112 -0
  103. package/test/r85-epoch-lock-release-lifetime.test.mjs +25 -0
  104. package/test/r85-epoch-repeat-append.test.mjs +30 -0
  105. package/test/r86-epoch-cleanup-and-loader.test.mjs +126 -0
  106. package/test/r87-crashed-orphan-revoke-reconcile.test.mjs +110 -0
  107. package/test/r88-native-disposition-failure.test.mjs +35 -0
  108. package/test/r89-privileged-install-boundary.test.mjs +123 -0
  109. package/test/r92-acl-ace-applicability.test.mjs +45 -0
  110. package/test/r94-win32-propagation-enum.test.mjs +51 -0
  111. package/test/r99-privileged-import-closure.test.mjs +45 -0
  112. package/test/remote-session-cli.test.mjs +69 -9
@@ -0,0 +1,63 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {createHash, generateKeyPairSync, randomBytes, sign} from 'node:crypto';
4
+ import {mkdtemp, mkdir, 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 {createAuthorityEpochStore} from '../src/authority-continuity-r65.mjs';
9
+
10
+ const sha = bytes => createHash('sha256').update(bytes).digest('hex');
11
+ const domain = Buffer.from('DEADBYTE-AUTHORITY-DURABLE-EPOCH-R65-V1\0');
12
+ const eventName = (seq, hash) => `${String(seq).padStart(16, '0')}-${hash}.json`;
13
+
14
+ test('R125 hot read rejects signed restore predecessor with array-valued SHA binding', async () => {
15
+ const root = await mkdtemp(path.join(os.tmpdir(), 'deadbyte-r125-binding-'));
16
+ try {
17
+ const runtimeDir = path.join(root, 'runtime');
18
+ const trust = path.join(root, 'trust');
19
+ const dir = path.join(runtimeDir, 'authority-epochs', 'process');
20
+ await mkdir(path.join(dir, 'events'), {recursive:true});
21
+ await mkdir(trust);
22
+ const keys = generateKeyPairSync('ed25519');
23
+ await writeFile(path.join(trust, 'ed25519-public.pem'), keys.publicKey.export({type:'spki', format:'pem'}));
24
+ const keyId = sha(keys.publicKey.export({type:'spki', format:'der'}));
25
+ const signEvent = body => {
26
+ const signature = sign(null, Buffer.concat([domain, Buffer.from(canonicalJson(body))]), keys.privateKey);
27
+ const event = {...body, attestation:{algorithm:'ed25519', domain:'DEADBYTE-AUTHORITY-DURABLE-EPOCH-R65-V1', key_id:keyId, signature_base64:signature.toString('base64')}};
28
+ const bytes = Buffer.from(canonicalJson(event));
29
+ return {bytes, hash:sha(bytes), event};
30
+ };
31
+ const nonce1 = randomBytes(32).toString('hex');
32
+ const nonce2 = randomBytes(32).toString('hex');
33
+ const nonce3 = randomBytes(32).toString('hex');
34
+ const oldGrant = sha(Buffer.from('old'));
35
+ const restoredGrant = sha(Buffer.from('restored'));
36
+ const currentGrantBytes = Buffer.from('current');
37
+ const common = {schema:'deadbyte.authority-epoch-event.r65.v1', plane:'process', recorded_at_utc:new Date().toISOString()};
38
+ const one = signEvent({...common, seq:1, action:'grant', update_id:null,
39
+ grant_sha256:oldGrant, grant_instance_nonce:nonce1, restore_binding:null, previous_event_sha256:null});
40
+ const two = signEvent({...common, seq:2, action:'transaction_revoke', update_id:'r125-update',
41
+ grant_sha256:oldGrant, grant_instance_nonce:nonce1, restore_binding:null, previous_event_sha256:one.hash});
42
+ const binding = {prior_grant_sha256:[oldGrant], prior_grant_instance_nonce:nonce1,
43
+ predecessor_policy_envelope_sha256:'1'.repeat(64), successor_policy_envelope_sha256:'2'.repeat(64),
44
+ candidate_manifest_sha256:'3'.repeat(64), continuity_subject_sha256:'4'.repeat(64)};
45
+ const three = signEvent({...common, seq:3, action:'transaction_restore', update_id:'r125-update',
46
+ grant_sha256:restoredGrant, grant_instance_nonce:nonce2, restore_binding:binding, previous_event_sha256:two.hash});
47
+ const fourBody = {...common, seq:4, action:'grant', update_id:null,
48
+ grant_sha256:sha(currentGrantBytes), grant_instance_nonce:nonce3, restore_binding:null,
49
+ previous_event_sha256:three.hash};
50
+ const four = signEvent(fourBody);
51
+ for (const [seq, signed] of [[1,one],[2,two],[3,three],[4,four]])
52
+ await writeFile(path.join(dir, 'events', eventName(seq, signed.hash)), signed.bytes);
53
+ await writeFile(path.join(dir, 'head.json'), Buffer.from(canonicalJson({
54
+ schema:'deadbyte.authority-epoch-head.r65.v1', plane:'process', seq:4, action:'grant', update_id:null,
55
+ grant_sha256:fourBody.grant_sha256, grant_instance_nonce:nonce3, restore_binding:null,
56
+ previous_event_sha256:three.hash, event_sha256:four.hash, event_file:eventName(4,four.hash)})));
57
+ const store = createAuthorityEpochStore({runtimeDir});
58
+ await assert.rejects(store.readHead({plane:'process'}), /authority epoch transaction restore binding invalid/);
59
+ assert.equal((await store.verifyGrant({plane:'process', grantBytes:currentGrantBytes, grantInstanceNonce:nonce3})).trusted, false);
60
+ } finally {
61
+ await rm(root, {recursive:true, force:true, maxRetries:8, retryDelay:100});
62
+ }
63
+ });
@@ -0,0 +1,89 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {createHash, generateKeyPairSync, randomBytes, sign} from 'node:crypto';
4
+ import {mkdtemp, mkdir, 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 {createAuthorityEpochStore} from '../src/authority-continuity-r65.mjs';
9
+
10
+ const sha = bytes => createHash('sha256').update(bytes).digest('hex');
11
+ const domain = Buffer.from('DEADBYTE-AUTHORITY-DURABLE-EPOCH-R65-V1\0');
12
+ const eventName = (seq, hash) => `${String(seq).padStart(16, '0')}-${hash}.json`;
13
+
14
+ async function signedRestoreFixture(bindingOverride) {
15
+ const root = await mkdtemp(path.join(os.tmpdir(), 'deadbyte-r126-envelope-'));
16
+ const runtimeDir = path.join(root, 'runtime');
17
+ const trustDir = path.join(root, 'trust');
18
+ const eventDir = path.join(runtimeDir, 'authority-epochs', 'process', 'events');
19
+ await mkdir(eventDir, {recursive:true});
20
+ await mkdir(trustDir);
21
+ const keys = generateKeyPairSync('ed25519');
22
+ await writeFile(path.join(trustDir, 'ed25519-public.pem'), keys.publicKey.export({type:'spki', format:'pem'}));
23
+ const keyId = sha(keys.publicKey.export({type:'spki', format:'der'}));
24
+ const signEvent = body => {
25
+ const signature = sign(null, Buffer.concat([domain, Buffer.from(canonicalJson(body))]), keys.privateKey);
26
+ const event = {...body, attestation:{algorithm:'ed25519', domain:'DEADBYTE-AUTHORITY-DURABLE-EPOCH-R65-V1', key_id:keyId, signature_base64:signature.toString('base64')}};
27
+ const bytes = Buffer.from(canonicalJson(event));
28
+ return {bytes, hash:sha(bytes)};
29
+ };
30
+ const oldNonce = randomBytes(32).toString('hex');
31
+ const newNonce = randomBytes(32).toString('hex');
32
+ const oldGrantSha = sha(Buffer.from('old-grant'));
33
+ const newGrantBytes = Buffer.from('new-grant');
34
+ const priorEnvelope = '1'.repeat(64);
35
+ const nextEnvelope = '2'.repeat(64);
36
+ const common = {schema:'deadbyte.authority-epoch-event.r65.v1', plane:'process', recorded_at_utc:new Date().toISOString()};
37
+ const one = signEvent({...common, seq:1, action:'grant', update_id:null, grant_sha256:oldGrantSha,
38
+ grant_instance_nonce:oldNonce, restore_binding:null, previous_event_sha256:null,
39
+ policy_sha256:'a'.repeat(64), policy_envelope_sha256:priorEnvelope});
40
+ const two = signEvent({...common, seq:2, action:'transaction_revoke', update_id:'r126-update',
41
+ grant_sha256:oldGrantSha, grant_instance_nonce:oldNonce, restore_binding:null,
42
+ previous_event_sha256:one.hash, policy_sha256:'a'.repeat(64), policy_envelope_sha256:priorEnvelope});
43
+ const restoreBinding = {prior_grant_sha256:oldGrantSha, prior_grant_instance_nonce:oldNonce,
44
+ predecessor_policy_envelope_sha256:priorEnvelope, successor_policy_envelope_sha256:nextEnvelope,
45
+ candidate_manifest_sha256:'3'.repeat(64), continuity_subject_sha256:'4'.repeat(64),
46
+ ...bindingOverride};
47
+ const threeBody = {...common, seq:3, action:'transaction_restore', update_id:'r126-update',
48
+ grant_sha256:sha(newGrantBytes), grant_instance_nonce:newNonce, restore_binding:restoreBinding,
49
+ previous_event_sha256:two.hash, policy_sha256:'b'.repeat(64), policy_envelope_sha256:nextEnvelope};
50
+ const three = signEvent(threeBody);
51
+ for (const [seq, signed] of [[1,one],[2,two],[3,three]])
52
+ await writeFile(path.join(eventDir, eventName(seq, signed.hash)), signed.bytes);
53
+ await writeFile(path.join(runtimeDir, 'authority-epochs', 'process', 'head.json'), Buffer.from(canonicalJson({
54
+ schema:'deadbyte.authority-epoch-head.r65.v1', plane:'process', seq:3,
55
+ action:threeBody.action, update_id:threeBody.update_id,
56
+ grant_sha256:threeBody.grant_sha256, grant_instance_nonce:newNonce,
57
+ restore_binding:restoreBinding, previous_event_sha256:two.hash,
58
+ policy_sha256:threeBody.policy_sha256, policy_envelope_sha256:nextEnvelope,
59
+ event_sha256:three.hash, event_file:eventName(3,three.hash)
60
+ })));
61
+ return {root, runtimeDir, newGrantBytes, newNonce};
62
+ }
63
+
64
+ for (const [name, override] of [
65
+ ['predecessor policy envelope', {predecessor_policy_envelope_sha256:'f'.repeat(64)}],
66
+ ['successor policy envelope', {successor_policy_envelope_sha256:'e'.repeat(64)}]
67
+ ]) test(`R126 signed restore rejects wrong ${name} despite valid signature`, async () => {
68
+ const fixture = await signedRestoreFixture(override);
69
+ try {
70
+ const store = createAuthorityEpochStore({runtimeDir:fixture.runtimeDir});
71
+ await assert.rejects(store.readHead({plane:'process'}), /authority epoch transition invalid/);
72
+ assert.equal((await store.verifyGrant({plane:'process', grantBytes:fixture.newGrantBytes,
73
+ grantInstanceNonce:fixture.newNonce})).trusted, false);
74
+ } finally {
75
+ await rm(fixture.root, {recursive:true, force:true, maxRetries:8, retryDelay:100});
76
+ }
77
+ });
78
+
79
+ test('R126 correctly bound signed restore stays readable', async () => {
80
+ const fixture = await signedRestoreFixture({});
81
+ try {
82
+ const store = createAuthorityEpochStore({runtimeDir:fixture.runtimeDir});
83
+ assert.equal((await store.readHead({plane:'process'})).action, 'transaction_restore');
84
+ assert.equal((await store.verifyGrant({plane:'process', grantBytes:fixture.newGrantBytes,
85
+ grantInstanceNonce:fixture.newNonce})).trusted, true);
86
+ } finally {
87
+ await rm(fixture.root, {recursive:true, force:true, maxRetries:8, retryDelay:100});
88
+ }
89
+ });
@@ -0,0 +1,25 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {createHash} from 'node:crypto';
4
+ import {mkdtemp,rm} from 'node:fs/promises';
5
+ import os from 'node:os';
6
+ import path from 'node:path';
7
+ import {createAuthorityEpochStore} from '../src/authority-continuity-r65.mjs';
8
+
9
+ const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
10
+ test('R127 wrong signed successor policy envelope fails before native lock or event write',async()=>{
11
+ const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r127-binding-'));
12
+ try{
13
+ const policy=Buffer.from(JSON.stringify({schema:'deadbyte.coding-policy.v1',enabled:false}));
14
+ const nonce='a'.repeat(64);
15
+ const grant=Buffer.from(JSON.stringify({instance_nonce:nonce,policy_sha256:sha(policy)}));
16
+ const binding={prior_grant_sha256:sha(grant),prior_grant_instance_nonce:'b'.repeat(64),
17
+ predecessor_policy_envelope_sha256:'c'.repeat(64),
18
+ successor_policy_envelope_sha256:'d'.repeat(64),
19
+ candidate_manifest_sha256:'e'.repeat(64),continuity_subject_sha256:'f'.repeat(64)};
20
+ const store=createAuthorityEpochStore({runtimeDir:path.join(root,'runtime'),policyBytes:policy});
21
+ await assert.rejects(store.append({plane:'coding',action:'transaction_restore',grantBytes:grant,
22
+ grantInstanceNonce:nonce,updateId:'r127',expectedHeadSha256:'1'.repeat(64),restoreBinding:binding}),
23
+ /successor policy envelope mismatch/);
24
+ }finally{await rm(root,{recursive:true,force:true});}
25
+ });
@@ -4,13 +4,14 @@ import { createHash } from 'node:crypto';
4
4
  import { mkdtemp, mkdir, readFile, rm, writeFile, readdir } from 'node:fs/promises';
5
5
  import os from 'node:os';
6
6
  import path from 'node:path';
7
+ import {fileURLToPath} from 'node:url';
7
8
  import { spawn } from 'node:child_process';
8
9
  import * as parity from '../scripts/release-parity-r39.mjs';
9
10
  import { createToolAudit } from '../src/tool-audit.mjs';
10
11
  import { verifyAuditChain } from '../src/audit-verify.mjs';
11
12
  import { generateTrustKeypair } from '../src/trust.mjs';
12
13
 
13
- const root = path.resolve(new URL('../', import.meta.url).pathname.replace(/^\/(?:([A-Za-z]:))/,'$1'));
14
+ const root = path.resolve(fileURLToPath(new URL('../', import.meta.url)));
14
15
  const sha256 = bytes => createHash('sha256').update(bytes).digest('hex');
15
16
  const temp = prefix => mkdtemp(path.join(os.tmpdir(), prefix));
16
17
  const run = (command,args,options={}) => new Promise((resolve,reject)=>{
@@ -1,11 +1,11 @@
1
1
  import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
- import { pathToFileURL } from 'node:url';
3
+ import { fileURLToPath,pathToFileURL } from 'node:url';
4
4
  import path from 'node:path';
5
5
 
6
6
  const target=process.env.R54_RUNTIME_UPDATE_PATH
7
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)));
8
+ : fileURLToPath(new URL('../src/runtime-update.mjs',import.meta.url));
9
9
  const runtimeUpdate=await import(pathToFileURL(target).href+'?r54='+Date.now());
10
10
 
11
11
  test('R54 exposes behavior-testable offline recovery blocker selection',()=>{
@@ -1,11 +1,11 @@
1
1
  import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
- import { pathToFileURL } from 'node:url';
3
+ import { fileURLToPath,pathToFileURL } from 'node:url';
4
4
  import path from 'node:path';
5
5
 
6
6
  const target=process.env.R55_RUNTIME_UPDATE_PATH
7
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)));
8
+ : fileURLToPath(new URL('../src/runtime-update.mjs',import.meta.url));
9
9
  const runtimeUpdate=await import(pathToFileURL(target).href+'?r55='+Date.now());
10
10
  const nonce='a'.repeat(64);
11
11
 
@@ -2,13 +2,13 @@ import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import { createHash } from 'node:crypto';
4
4
  import { readFile } from 'node:fs/promises';
5
- import { pathToFileURL } from 'node:url';
5
+ import { fileURLToPath,pathToFileURL } from 'node:url';
6
6
  import os from 'node:os';
7
7
  import path from 'node:path';
8
8
 
9
9
  const target=process.env.R56_RUNTIME_UPDATE_PATH
10
10
  ? path.resolve(process.env.R56_RUNTIME_UPDATE_PATH)
11
- : path.resolve(new URL('../src/runtime-update.mjs',import.meta.url).pathname.replace(/^\/(?:[A-Za-z]:)/,m=>m.slice(1)));
11
+ : fileURLToPath(new URL('../src/runtime-update.mjs',import.meta.url));
12
12
  const runtimeUpdate=await import(pathToFileURL(target).href+'?r56='+Date.now());
13
13
  const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
14
14
  const stateRoot=path.resolve(process.env.R56_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
@@ -1,12 +1,12 @@
1
1
  import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import { readFile } from 'node:fs/promises';
4
- import { pathToFileURL } from 'node:url';
4
+ import { fileURLToPath,pathToFileURL } from 'node:url';
5
5
  import path from 'node:path';
6
6
 
7
7
  const target=process.env.R57_RUNTIME_UPDATE_PATH
8
8
  ? path.resolve(process.env.R57_RUNTIME_UPDATE_PATH)
9
- : path.resolve(new URL('../src/runtime-update.mjs',import.meta.url).pathname.replace(/^\/(?:[A-Za-z]:)/,m=>m.slice(1)));
9
+ : fileURLToPath(new URL('../src/runtime-update.mjs',import.meta.url));
10
10
  const runtimeUpdate=await import(pathToFileURL(target).href+'?r57='+Date.now());
11
11
  const coreRoot='C:\\slot\\core';
12
12
  const bridge={pid:20396,component:'bridge',script_path:'C:\\slot\\bridge\\src\\bridge.mjs',script_sha256:'a'.repeat(64)};
@@ -6,7 +6,7 @@ import {fileURLToPath} from 'node:url';
6
6
  import {spawn} from 'node:child_process';
7
7
  import {setTimeout as delay} from 'node:timers/promises';
8
8
 
9
- test('R58 simultaneous stale recovery cannot both revoke the shared authority', {timeout:90000},async()=>{
9
+ test('R75 simultaneous owner-unverified recovery attempts both retain authority and marker', {timeout:30000},async()=>{
10
10
  const base='D:/Projects/deadbyte-mcp/testing/0.15.35/fixtures';await mkdir(base,{recursive:true});
11
11
  const root=await mkdtemp(path.join(base,'concurrent-recovery-'));await mkdir(path.join(root,'bin'));await mkdir(path.join(root,'runtime'));
12
12
  const trace=path.join(root,'trace.txt'),markerPath=path.join(root,'runtime','remote-session.json');
@@ -47,14 +47,17 @@ exit 0
47
47
  const c=spawn(process.execPath,[fileURLToPath(new URL('../src/deadbyte-cli.mjs',import.meta.url)),'remote'],{env:{...process.env,DEADBYTE_STATE_ROOT:root},stdio:['pipe','pipe','pipe'],windowsHide:true});
48
48
  const o={stdout:'',stderr:''};c.stdout.on('data',b=>{o.stdout+=b;});c.stderr.on('data',b=>{o.stderr+=b;});o.exit=new Promise(resolve=>c.once('exit',resolve));children.push(c);outputs.push(o);
49
49
  }
50
- const until=Date.now()+45000;let commands=[];
51
- while(Date.now()<until){try{commands=(await readFile(trace,'utf8')).trim().split(/\r?\n/);}catch{}if(outputs.some(o=>o.stdout.includes('[READY]')))break;await delay(50);}
52
- await writeFile(path.join(root,'observation.json'),JSON.stringify({commands,outputs:outputs.map(o=>({stdout:o.stdout,stderr:o.stderr})),simulation:'concurrent stale marker recovery with delayed second park'}),{flag:'wx'});
53
- assert.ok(outputs.some(o=>o.stdout.includes('[READY]')),'a recovered foreground must become ready');
54
- for(const cmd of ['disarmautonomous','disarmcoding','disarmprocess','disarmdesktop','disarmhost'])assert.equal(commands.filter(x=>x===cmd).length,1,`stale recovery must serialize ${cmd}`);
50
+ const exits=await Promise.race([Promise.all(outputs.map(o=>o.exit)),delay(15000,null,{ref:false}).then(()=>null)]);
51
+ assert.ok(exits,'both owner-unverified attempts must terminate');
52
+ const commands=await readFile(trace,'utf8').catch(error=>error.code==='ENOENT'?'':Promise.reject(error));
53
+ await writeFile(path.join(root,'observation.json'),JSON.stringify({commands,exits,outputs:outputs.map(o=>({stdout:o.stdout,stderr:o.stderr})),simulation:'concurrent owner-unverified stale marker'}),{flag:'wx'});
54
+ assert.ok(exits.every(code=>code!==0));
55
+ for(const output of outputs)assert.match(output.stderr,/ownership unverified.*marker retained|already claimed \(startup\/recovery lock\)/i);
56
+ assert.equal(commands,'','neither attempt may touch authority');
57
+ assert.equal(JSON.parse(await readFile(markerPath,'utf8')).pid,2147483000);
55
58
  }finally{
56
59
  for(const c of children)if(c.exitCode===null)c.stdin.end();
57
- await Promise.race([Promise.all(outputs.map(o=>o.exit)),delay(30000)]);
60
+ await Promise.race([Promise.all(outputs.map(o=>o.exit)),delay(30000,null,{ref:false})]);
58
61
  for(const c of children)if(c.exitCode===null&&c.signalCode===null)c.kill();
59
62
  }
60
63
  });
@@ -46,7 +46,7 @@ test('R58 live unrelated PID is not accepted as a remote foreground owner', {tim
46
46
  assert.notEqual(code,0);
47
47
  });
48
48
 
49
- test('R58 bound stale birth identity reconciles on the first invocation without killing a reused PID', {timeout:60000}, async()=>{
49
+ test('R75 bound stale birth identity retains marker without touching a reused PID or authority', {timeout:60000}, async()=>{
50
50
  const base='D:/Projects/deadbyte-mcp/testing/0.15.35/fixtures';
51
51
  await mkdir(base,{recursive:true});const root=await mkdtemp(path.join(base,'stale-birth-'));
52
52
  await mkdir(path.join(root,'runtime'));await mkdir(path.join(root,'bin'));
@@ -61,11 +61,10 @@ test('R58 bound stale birth identity reconciles on the first invocation without
61
61
  let stdout='',stderr='';child.stdout.on('data',b=>{stdout+=b;});child.stderr.on('data',b=>{stderr+=b;});
62
62
  const code=await new Promise(resolve=>child.once('close',resolve));
63
63
  await writeFile(path.join(root,'observation.json'),JSON.stringify({code,stdout,stderr,simulation:'birth identity drift at a live unrelated numeric PID'}),{flag:'wx'});
64
- assert.match(stdout,/Stale remote session/);
65
- assert.doesNotMatch(stderr,/already active|ownership unverified/);
66
- assert.deepEqual((await readFile(trace,'utf8')).trim().split(/\r?\n/).slice(0,7),['disarmautonomous','disarmcoding','disarmprocess','disarmdesktop','disarmhost','status','park']);
67
- assert.match(stderr,/without a verified ONLINE runtime/,'fixture deliberately has no real runtime; recovery must already have converged');
68
- await assert.rejects(readFile(markerPath),{code:'ENOENT'});
64
+ assert.notEqual(code,0);
65
+ assert.match(stderr,/owner identity mismatch; marker retained/i);
66
+ assert.equal(await readFile(trace,'utf8').catch(error=>error.code==='ENOENT'?'':Promise.reject(error)),'','identity drift must cause no authority commands');
67
+ assert.deepEqual(JSON.parse(await readFile(markerPath,'utf8')),marker);
69
68
  assert.equal(foregroundAlive(),true,'unrelated live process must not be killed');
70
69
  function foregroundAlive(){try{process.kill(process.pid,0);return true;}catch{return false;}}
71
70
  });
@@ -83,7 +83,7 @@ test('R72 compact baseline permits only R64 read offset and authorized coding-on
83
83
  assert.deepEqual(diff.added,[]);
84
84
  assert.deepEqual(diff.removed,[]);
85
85
  const packageVersion=JSON.parse(await readFile(path.join(repoRoot,'package.json'),'utf8')).version;
86
- if(['0.15.41','0.15.42','0.15.43','0.15.44','0.15.45','0.15.46','0.15.47'].includes(packageVersion)){
86
+ if(['0.15.41','0.15.42','0.15.43','0.15.44','0.15.45','0.15.46','0.15.47','0.15.48','0.15.49'].includes(packageVersion)){
87
87
  assert.deepEqual([...diff.schema_changed].sort(),['machine_fs','native_diff_preview']);
88
88
  assert.equal(diff.unchanged.length,41);
89
89
  const prior=baseline.tools.find(tool=>tool.name==='machine_fs');
@@ -1,6 +1,7 @@
1
1
  import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import {orchestrateActivation} from '../src/activation-preflight-r65.mjs';
4
+ import {withAuthorityProof} from './helpers/r75-authority-proof.mjs';
4
5
 
5
6
  const parent={release_id:'v0.15.41-63a78ad159ad3003',version:'0.15.41',manifest_sha256:'63a78ad159ad3003db3fefafcd468bef22599c829a867f4f10a46c7a20748b3e',generation_manifest_sha256:'19ae2efcdcde9f80c474f0e55851d4ada51c22813d3e05af03b11acb28c3fca5'};
6
7
  const candidate={version:'0.15.42',manifest_sha256:'a'.repeat(64)};
@@ -19,7 +20,7 @@ function fixture(initial={}){
19
20
  let current={state:'ONLINE',local_ready:true,...ids,supervisor:{running:true},authority:authorityEntries(initialVector,initial.epochNative===true),policy_sha256:policies,
20
21
  active_release_id:parent.release_id,active_manifest_sha256:parent.manifest_sha256,active_generation_manifest_sha256:parent.generation_manifest_sha256,...initial};
21
22
  if(initial.authority)current={...current,authority:authorityEntries(initial.authority,initial.epochNative===true)};
22
- return {calls,observe:async()=>current,command:async name=>{
23
+ return {calls,observe:async()=>withAuthorityProof(current),command:async name=>{
23
24
  calls.push(name);
24
25
  if(name.startsWith('disarm')){
25
26
  const plane=name.slice(6);
@@ -1,6 +1,7 @@
1
1
  import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import {classifyActivationPreflight,authorityTransitionPlan} from '../src/activation-preflight-r65.mjs';
4
+ import {withAuthorityProof} from './helpers/r75-authority-proof.mjs';
4
5
 
5
6
  const parent={release_id:'v0.15.41-63a78ad159ad3003',version:'0.15.41',manifest_sha256:'63a78ad159ad3003db3fefafcd468bef22599c829a867f4f10a46c7a20748b3e',generation_manifest_sha256:'19ae2efcdcde9f80c474f0e55851d4ada51c22813d3e05af03b11acb28c3fca5'};
6
7
  const candidate={version:'0.15.42',manifest_sha256:'a'.repeat(64)};
@@ -8,7 +9,7 @@ const authority={process:true,coding:true,autonomous:true,desktop:false,host:fal
8
9
  const policies={process:'1'.repeat(64),coding:'2'.repeat(64),autonomous:'3'.repeat(64),desktop:'4'.repeat(64),host:'5'.repeat(64)};
9
10
  const online={state:'ONLINE',local_ready:true,bridge:{alive:true,reason:'verified',pid:10},core:{alive:true,reason:'verified',pid:11},cloud:{alive:true,reason:'verified',pid:12},supervisor:{running:true},authority,policy_sha256:policies,
10
11
  active_release_id:parent.release_id,active_manifest_sha256:parent.manifest_sha256,active_generation_manifest_sha256:parent.generation_manifest_sha256};
11
- const input={pointer:parent,expectedParent:parent,candidate,expectedCandidate:candidate,observation:online};
12
+ const input={pointer:parent,expectedParent:parent,candidate,expectedCandidate:candidate,observation:withAuthorityProof(online)};
12
13
 
13
14
  test('preflight accepts exact online predecessor with full observed identity and authority vector',()=>{
14
15
  const result=classifyActivationPreflight(input);
@@ -19,7 +20,7 @@ test('preflight accepts exact online predecessor with full observed identity and
19
20
 
20
21
  test('host armed is not safe; plan only disarms Host and restores exact captured vector',()=>{
21
22
  const armed={...authority,host:true};
22
- const result=classifyActivationPreflight({...input,observation:{...online,authority:armed}});
23
+ const result=classifyActivationPreflight({...input,observation:withAuthorityProof({...online,authority:armed})});
23
24
  assert.equal(result.state,'ONLINE_HOST_ARMED');assert.equal(result.safe_to_activate,false);
24
25
  const plan=authorityTransitionPlan(result.authority);
25
26
  assert.deepEqual(plan.before,['disarmhost']);
@@ -27,9 +28,9 @@ test('host armed is not safe; plan only disarms Host and restores exact captured
27
28
  });
28
29
 
29
30
  test('parked dirty, generation drift and identity loss fail closed without an activation command',()=>{
30
- assert.equal(classifyActivationPreflight({...input,observation:{...online,state:'PARKED'}}).state,'PARKED_DIRTY');
31
+ assert.equal(classifyActivationPreflight({...input,observation:withAuthorityProof({...online,state:'PARKED'})}).state,'PARKED_DIRTY');
31
32
  assert.equal(classifyActivationPreflight({...input,pointer:{...parent,generation_manifest_sha256:'b'.repeat(64)}}).state,'POINTER_DRIFT');
32
- assert.equal(classifyActivationPreflight({...input,observation:{...online,active_release_id:'wrong'}}).state,'POINTER_DRIFT');
33
- assert.equal(classifyActivationPreflight({...input,observation:{...online,policy_sha256:{...policies,host:null}}}).state,'UNKNOWN');
34
- assert.equal(classifyActivationPreflight({...input,observation:{...online,cloud:{alive:false,reason:'missing'}}}).state,'RUNTIME_DRIFT');
33
+ assert.equal(classifyActivationPreflight({...input,observation:withAuthorityProof({...online,active_release_id:'wrong'})}).state,'POINTER_DRIFT');
34
+ assert.equal(classifyActivationPreflight({...input,observation:withAuthorityProof({...online,policy_sha256:{...policies,host:null}})}).state,'UNKNOWN');
35
+ assert.equal(classifyActivationPreflight({...input,observation:withAuthorityProof({...online,cloud:{alive:false,reason:'missing'}})}).state,'RUNTIME_DRIFT');
35
36
  });
@@ -19,7 +19,9 @@ test('dead-owner epoch lock is recovered but a live-owner lock is never stolen',
19
19
  const runtime=await prepareAuthorityTestTrust(root);
20
20
  const dir=path.join(runtime,'authority-epochs','coding');
21
21
  await mkdir(dir,{recursive:true});
22
- await writeFile(path.join(dir,'.lock'),JSON.stringify({schema:'deadbyte.authority-epoch-lock.r65.v1',pid:2147483647,token:'dead',created_at_utc:'2026-10-06T00:00:00Z'}));
22
+ await writeFile(path.join(dir,'.lock'),JSON.stringify({schema:'deadbyte.authority-epoch-lock.r65.v1',pid:2147483647,token:'dead',created_at_utc:'2026-10-06T00:00:00Z',
23
+ owner_identity:{schema:'deadbyte.foreground-process.v1',pid:2147483647,parent_pid:0,creation_utc:'2026-01-01T00:00:00Z',
24
+ executable_path:process.execPath,command_line_sha256:'0'.repeat(64)}}));
23
25
  const store=createAuthorityEpochStore({runtimeDir:runtime});
24
26
  const nonce='1'.repeat(64),grant=grantBytes(nonce);
25
27
  const head=await store.append({plane:'coding',action:'grant',grantBytes:grant,grantInstanceNonce:nonce,updateId:null});
@@ -4,7 +4,7 @@ import {createHash} from 'node:crypto';
4
4
  import {mkdtemp,mkdir,readFile,rm,writeFile} from 'node:fs/promises';
5
5
  import os from 'node:os';
6
6
  import path from 'node:path';
7
- import {createAuthorityEpochStore} from '../src/authority-continuity-r65.mjs';
7
+ import {createAuthorityEpochStore,deriveSecurityEnvelope} from '../src/authority-continuity-r65.mjs';
8
8
  import {prepareAuthorityTestTrust} from './r65-authority-test-trust.mjs';
9
9
 
10
10
  const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
@@ -32,9 +32,12 @@ async function fixture(run){
32
32
  }finally{await rm(root,{recursive:true,force:true});}
33
33
  }
34
34
 
35
- function restoreBinding(oldGrant,oldNonce){
35
+ function restoreBinding(oldGrant,oldNonce,policyBytes){
36
+ // A successful restore must describe the real signed policy envelope.
37
+ // This fixture keeps the same policy on both sides of the transaction.
38
+ const envelope=deriveSecurityEnvelope('process',JSON.parse(policyBytes)).sha256;
36
39
  return {prior_grant_sha256:sha(oldGrant),prior_grant_instance_nonce:oldNonce,
37
- predecessor_policy_envelope_sha256:'1'.repeat(64),successor_policy_envelope_sha256:'2'.repeat(64),
40
+ predecessor_policy_envelope_sha256:envelope,successor_policy_envelope_sha256:envelope,
38
41
  candidate_manifest_sha256:'3'.repeat(64),continuity_subject_sha256:'4'.repeat(64)};
39
42
  }
40
43
 
@@ -63,7 +66,7 @@ test('stale transaction CAS cannot overwrite a later user revoke',()=>fixture(as
63
66
  const nextNonce='e'.repeat(64),nextGrant=Buffer.from(JSON.stringify({...f.grant,instance_nonce:nextNonce}));
64
67
  await assert.rejects(()=>f.store.append({plane:'process',action:'transaction_restore',grantBytes:nextGrant,
65
68
  grantInstanceNonce:nextNonce,updateId:'r65-store-test',expectedHeadSha256:tx.event_sha256,
66
- restoreBinding:restoreBinding(f.grantBytes,f.grant.instance_nonce)}),/compare-and-swap conflict/);
69
+ restoreBinding:restoreBinding(f.grantBytes,f.grant.instance_nonce,f.policyBytes)}),/compare-and-swap conflict/);
67
70
  }));
68
71
 
69
72
  test('replaying an older signed head fails closed when a later event remains',()=>fixture(async f=>{
@@ -83,11 +86,11 @@ test('transaction restore requires a fresh nonce and becomes the trusted head',(
83
86
  grantInstanceNonce:f.grant.instance_nonce,updateId,expectedHeadSha256:granted.event_sha256});
84
87
  await assert.rejects(()=>f.store.append({plane:'process',action:'transaction_restore',grantBytes:f.grantBytes,
85
88
  grantInstanceNonce:f.grant.instance_nonce,updateId,expectedHeadSha256:revoked.event_sha256,
86
- restoreBinding:restoreBinding(f.grantBytes,f.grant.instance_nonce)}),/fresh nonce|resurrect/i);
89
+ restoreBinding:restoreBinding(f.grantBytes,f.grant.instance_nonce,f.policyBytes)}),/fresh nonce|resurrect/i);
87
90
  const newNonce='f'.repeat(64),newGrant=Buffer.from(JSON.stringify({...f.grant,instance_nonce:newNonce}));
88
91
  const restored=await f.store.append({plane:'process',action:'transaction_restore',grantBytes:newGrant,
89
92
  grantInstanceNonce:newNonce,updateId,expectedHeadSha256:revoked.event_sha256,
90
- restoreBinding:restoreBinding(f.grantBytes,f.grant.instance_nonce)});
93
+ restoreBinding:restoreBinding(f.grantBytes,f.grant.instance_nonce,f.policyBytes)});
91
94
  const verified=await f.store.verifyGrant({plane:'process',grantBytes:newGrant,grantInstanceNonce:newNonce,policyBytes:f.policyBytes});
92
95
  assert.equal(verified.trusted,true);
93
96
  assert.equal(verified.event_sha256,restored.event_sha256);
@@ -7,6 +7,7 @@ import path from 'node:path';
7
7
  import {orchestrateActivation} from '../src/activation-preflight-r65.mjs';
8
8
  import {createAuthorityEpochStore} from '../src/authority-continuity-r65.mjs';
9
9
  import {createEpochNativeContinuityEngine} from '../src/activation-continuity-engine-r65.mjs';
10
+ import {withAuthorityProof} from './helpers/r75-authority-proof.mjs';
10
11
 
11
12
  const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
12
13
  const parent={release_id:'v0.15.41-parent',version:'0.15.41',manifest_sha256:'a'.repeat(64),generation_manifest_sha256:'b'.repeat(64)};
@@ -26,7 +27,7 @@ test('orchestrator reports RESTORED_SAFE when all restored authority is safe but
26
27
  return {authority_outcomes:{process:'RESTORED_SAFE',coding:'NOT_APPLICABLE',autonomous:'NOT_APPLICABLE',desktop:'NOT_APPLICABLE',host:'NOT_APPLICABLE'},restored_nonces:{process:'8'.repeat(64)},reauth_planes:[]};}
27
28
  };
28
29
  const result=await orchestrateActivation({pointer:parent,expectedParent:parent,candidate,expectedCandidate:candidate,
29
- observe:async()=>current,command:async()=>{throw new Error('generic command forbidden');},
30
+ observe:async()=>withAuthorityProof(current),command:async()=>{throw new Error('generic command forbidden');},
30
31
  activate:async()=>({verified:true,release_id:'v0.15.42-candidate'}),continuityEngine});
31
32
  assert.equal(result.state,'ACTIVATED');
32
33
  assert.equal(result.authority_continuity,'RESTORED_SAFE');
@@ -11,8 +11,9 @@ const root=path.resolve(fileURLToPath(new URL('..',import.meta.url)));
11
11
  test('deploy dry preflight observes isolated authority without opening an update transaction', {skip:process.platform!=='win32'},async()=>{
12
12
  const isolated=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r65-deploy-preflight-'));
13
13
  try{
14
- const state=path.join(isolated,'state'),bin=path.join(state,'bin');
14
+ const state=path.join(isolated,'state'),bin=path.join(state,'bin'),runtime=path.join(state,'runtime');
15
15
  await mkdir(bin,{recursive:true});
16
+ await mkdir(runtime,{recursive:true});
16
17
  const release=JSON.parse(await readFile(path.join(root,'RELEASE.json'),'utf8'));
17
18
  const parent=release.parent;
18
19
  const generationRoot=path.join(state,'generations',`${parent.release_id}-fixture`);
@@ -20,9 +21,11 @@ test('deploy dry preflight observes isolated authority without opening an update
20
21
  await mkdir(generationRoot,{recursive:true});await mkdir(policyRoot,{recursive:true});
21
22
  const fields={process:'ProcessPolicyFile',coding:'CodingPolicyFile',autonomous:'AutonomousPolicyFile',desktop:'DesktopPolicyFile',host:'HostPolicyFile'};
22
23
  const policyLines=[];
24
+ const grantField={process:'grant_file',coding:'lease_file',autonomous:'lease_file',desktop:'grant_file',host:'arm_file'};
23
25
  for(const [plane,key] of Object.entries(fields)){
24
26
  const file=path.join(policyRoot,`${plane}.json`);
25
- await writeFile(file,JSON.stringify({schema:`fixture.${plane}`,enabled:true}));
27
+ await writeFile(file,JSON.stringify({schema:`deadbyte.${plane}-policy.v${plane==='host'?2:1}`,enabled:true,
28
+ [grantField[plane]]:path.join(runtime,`${plane}-grant.json`)}));
26
29
  policyLines.push(`${key} = '${file.replaceAll("'","''")}'`);
27
30
  }
28
31
  await writeFile(path.join(generationRoot,'controller-config.psd1'),`@{ ${policyLines.join('; ')} }\n`);
@@ -30,26 +33,22 @@ test('deploy dry preflight observes isolated authority without opening an update
30
33
  release_root:path.join(state,'releases',parent.release_id),generation_root:generationRoot,
31
34
  launcher_sha256:'a'.repeat(64),config_path:path.join(generationRoot,'controller-config.psd1')}));
32
35
  const ps1=`param([string]$Command,[switch]$Json)\nif($Command -ne 'status' -or -not $Json){throw 'unexpected mutating command'}\n@{schema='deadbyte.controller-observation.v1';state='ONLINE';local_ready=$true;bridge=@{alive=$true;reason='verified';pid=10};core=@{alive=$true;reason='verified';pid=11};cloud=@{alive=$true;reason='verified';pid=12};supervisor=@{running=$true};authority=@{process=@{armed=$true;configured=$true;reason='fixture'};coding=@{armed=$true;configured=$true;reason='fixture'};autonomous=@{armed=$true;configured=$true;reason='fixture'};desktop=@{armed=$false;configured=$true;reason='fixture'};host=@{armed=$false;configured=$true;reason='fixture'}}} | ConvertTo-Json -Depth 6 -Compress\n`;
33
- await writeFile(path.join(bin,'DEADBYTE-MCP.ps1'),ps1);
36
+ const cleanPs1=ps1.replaceAll('armed=$true','armed=$false').replaceAll("reason='fixture'","reason='disarmed'");
37
+ await writeFile(path.join(bin,'DEADBYTE-MCP.ps1'),cleanPs1);
34
38
  const run=spawnSync(process.execPath,[path.join(root,'scripts','deploy-r48.mjs'),'--preflight'],{
35
39
  env:{...process.env,DEADBYTE_STATE_ROOT:state},cwd:root,encoding:'utf8',timeout:20000,windowsHide:true});
36
40
  assert.equal(run.status,0,run.stderr);
37
41
  const result=JSON.parse(run.stdout.trim());
38
42
  assert.equal(result.state,'ONLINE_READY');
39
- assert.equal(result.authority_continuity,'REAUTH_REQUIRED');
40
- assert.deepEqual(result.reauth_planes,['process','coding','autonomous']);
41
- const hostOnly=ps1.replace('process=@{armed=$true','process=@{armed=$false')
42
- .replace('coding=@{armed=$true','coding=@{armed=$false')
43
- .replace('autonomous=@{armed=$true','autonomous=@{armed=$false')
44
- .replace('host=@{armed=$false','host=@{armed=$true');
45
- await writeFile(path.join(bin,'DEADBYTE-MCP.ps1'),hostOnly);
43
+ assert.equal(result.authority_continuity,'NOT_APPLICABLE');
44
+ assert.deepEqual(result.reauth_planes,[]);
45
+ const unverified=cleanPs1.replace("host=@{armed=$false;configured=$true;reason='disarmed'", "host=@{armed=$false;configured=$true;reason='unverified'");
46
+ await writeFile(path.join(bin,'DEADBYTE-MCP.ps1'),unverified);
46
47
  const hostRun=spawnSync(process.execPath,[path.join(root,'scripts','deploy-r48.mjs'),'--preflight'],{
47
48
  env:{...process.env,DEADBYTE_STATE_ROOT:state},cwd:root,encoding:'utf8',timeout:20000,windowsHide:true});
48
49
  assert.equal(hostRun.status,0,hostRun.stderr);
49
50
  const hostResult=JSON.parse(hostRun.stdout.trim());
50
- assert.equal(hostResult.state,'ONLINE_HOST_ARMED');
51
- assert.equal(hostResult.authority_continuity,'REAUTH_REQUIRED');
52
- assert.deepEqual(hostResult.reauth_planes,['host']);
53
- assert.deepEqual((await readdir(state)).sort(),['active-release.json','bin','generations','policies']);
51
+ assert.equal(hostResult.state,'AUTHORITY_UNVERIFIED');
52
+ assert.deepEqual((await readdir(state)).sort(),['active-release.json','bin','generations','policies','runtime']);
54
53
  }finally{await rm(isolated,{recursive:true,force:true});}
55
54
  });
@@ -7,6 +7,7 @@ import path from 'node:path';
7
7
  import {orchestrateActivation} from '../src/activation-preflight-r65.mjs';
8
8
  import {createAuthorityEpochStore} from '../src/authority-continuity-r65.mjs';
9
9
  import {createEpochNativeContinuityEngine} from '../src/activation-continuity-engine-r65.mjs';
10
+ import {withAuthorityProof} from './helpers/r75-authority-proof.mjs';
10
11
 
11
12
  const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
12
13
  const parent={release_id:'v0.15.41-parent',version:'0.15.41',manifest_sha256:'a'.repeat(64),generation_manifest_sha256:'b'.repeat(64)};
@@ -44,7 +45,7 @@ test('epoch-native orchestrator handles BOM-encoded process grant with transacti
44
45
  const grant=JSON.parse(new TextDecoder('utf-8',{fatal:true}).decode(bytes));
45
46
  armed=(await store.verifyGrant({plane:'process',grantBytes:bytes,grantInstanceNonce:grant.instance_nonce,policyBytes})).trusted;
46
47
  }
47
- return {state:'ONLINE',local_ready:true,...ids,supervisor:{running:true},authority:{
48
+ return withAuthorityProof({state:'ONLINE',local_ready:true,...ids,supervisor:{running:true},authority:{
48
49
  process:{configured:true,armed,reason:armed?'standing-grant':'disarmed',epoch_seq:armed?head.seq:null,epoch_sha256:armed?head.event_sha256:null},
49
50
  coding:{configured:true,armed:false,reason:'disarmed',epoch_seq:null,epoch_sha256:null},
50
51
  autonomous:{configured:true,armed:false,reason:'disarmed',epoch_seq:null,epoch_sha256:null},
@@ -53,7 +54,7 @@ test('epoch-native orchestrator handles BOM-encoded process grant with transacti
53
54
  },policy_sha256:{process:sha(policyBytes),...dummy},
54
55
  active_release_id:switched?'v0.15.42-candidate':parent.release_id,
55
56
  active_manifest_sha256:switched?candidate.manifest_sha256:parent.manifest_sha256,
56
- active_generation_manifest_sha256:switched?'9'.repeat(64):parent.generation_manifest_sha256};
57
+ active_generation_manifest_sha256:switched?'9'.repeat(64):parent.generation_manifest_sha256});
57
58
  };
58
59
  const engine=createEpochNativeContinuityEngine({stateRoot:state,
59
60
  predecessorPolicyPaths:{process:beforePath,coding:null,autonomous:null,desktop:null,host:null},
@@ -107,7 +108,7 @@ test('epoch-native explicit user revoke after transaction revoke wins over orche
107
108
  const grant=JSON.parse(new TextDecoder('utf-8',{fatal:true}).decode(bytes));
108
109
  armed=(await store.verifyGrant({plane:'process',grantBytes:bytes,grantInstanceNonce:grant.instance_nonce,policyBytes})).trusted;
109
110
  }
110
- return {state:'ONLINE',local_ready:true,...ids,supervisor:{running:true},authority:{
111
+ return withAuthorityProof({state:'ONLINE',local_ready:true,...ids,supervisor:{running:true},authority:{
111
112
  process:{configured:true,armed,reason:armed?'standing-grant':'disarmed',epoch_seq:armed?head.seq:null,epoch_sha256:armed?head.event_sha256:null},
112
113
  coding:{configured:true,armed:false,reason:'disarmed',epoch_seq:null,epoch_sha256:null},
113
114
  autonomous:{configured:true,armed:false,reason:'disarmed',epoch_seq:null,epoch_sha256:null},
@@ -116,7 +117,7 @@ test('epoch-native explicit user revoke after transaction revoke wins over orche
116
117
  },policy_sha256:{process:sha(policyBytes),...dummy},
117
118
  active_release_id:switched?'v0.15.42-candidate':parent.release_id,
118
119
  active_manifest_sha256:switched?candidate.manifest_sha256:parent.manifest_sha256,
119
- active_generation_manifest_sha256:switched?'9'.repeat(64):parent.generation_manifest_sha256};
120
+ active_generation_manifest_sha256:switched?'9'.repeat(64):parent.generation_manifest_sha256});
120
121
  };
121
122
  const engine=createEpochNativeContinuityEngine({stateRoot:state,
122
123
  predecessorPolicyPaths:{process:beforePath,coding:null,autonomous:null,desktop:null,host:null},
@@ -1,6 +1,7 @@
1
1
  import test from 'node:test';
2
2
  import assert from 'node:assert/strict';
3
3
  import {classifyAuthorityContinuity,orchestrateActivation} from '../src/activation-preflight-r65.mjs';
4
+ import {withAuthorityProof} from './helpers/r75-authority-proof.mjs';
4
5
 
5
6
  const parent={release_id:'v0.15.41-parent',version:'0.15.41',manifest_sha256:'1'.repeat(64),generation_manifest_sha256:'2'.repeat(64)};
6
7
  const candidate={version:'0.15.42',manifest_sha256:'3'.repeat(64)};
@@ -15,7 +16,7 @@ function fixture(vector){
15
16
  authority:Object.fromEntries(Object.entries(vector).map(([plane,armed])=>[plane,legacyEntry(armed)]))};
16
17
  return {
17
18
  calls,
18
- observe:async()=>observation,
19
+ observe:async()=>withAuthorityProof(observation),
19
20
  command:async command=>{
20
21
  calls.push(command);
21
22
  if(command.startsWith('disarm')){