deadbyte-mcp 0.15.39 → 0.15.42

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 (100) hide show
  1. package/DEADBYTE-MCP.cmd +8 -4
  2. package/MANIFEST.SHA256 +99 -45
  3. package/PROVENANCE.json +90 -20
  4. package/README.txt +39 -18
  5. package/RELEASE.json +85 -20
  6. package/SBOM.cdx.json +2 -2
  7. package/TEST-MATRIX.json +134 -34
  8. package/bridge/package.json +1 -1
  9. package/controller/deadbyte-controller.ps1 +132 -12
  10. package/controller/deadbyte-process-policy.json +4 -4
  11. package/docs/R64-EVIDENCE.json +95 -0
  12. package/docs/R64-REFERENCE-GAP-MATRIX.json +98 -0
  13. package/docs/R64-SCOPE.json +41 -0
  14. package/docs/R65-AUTHORITY-CONTINUITY-DESIGN.json +27 -0
  15. package/docs/R65-REFERENCE-GAP-MATRIX.json +22 -0
  16. package/package.json +7 -4
  17. package/scripts/deploy-r48.mjs +123 -7
  18. package/scripts/gate-windows-r63-prepublish.ps1 +45 -0
  19. package/scripts/gate-windows-r64-prepublish.ps1 +68 -0
  20. package/scripts/gate-windows-r65-prepublish.ps1 +65 -0
  21. package/scripts/npm-publication-r65.mjs +139 -0
  22. package/scripts/npm-release-r48.mjs +62 -37
  23. package/scripts/r64-predecessor-reproducer.mjs +32 -0
  24. package/scripts/r64-read-benchmark.mjs +84 -0
  25. package/scripts/r65-canonical-full.mjs +45 -0
  26. package/scripts/r65-focused.mjs +37 -0
  27. package/scripts/verify-r65-parent-source.mjs +75 -0
  28. package/src/activation-continuity-engine-r65.mjs +225 -0
  29. package/src/activation-lock-r65.mjs +155 -0
  30. package/src/activation-preflight-r65.mjs +197 -0
  31. package/src/authority-continuity-r65.mjs +541 -0
  32. package/src/authority-epoch-cli-r65.mjs +10 -0
  33. package/src/autonomous-policy.mjs +7 -3
  34. package/src/coding-plane.mjs +12 -3
  35. package/src/compact-gateway-mcp-tools.mjs +1 -1
  36. package/src/deadbyte-cli.mjs +16 -2
  37. package/src/desktop-policy-r40.mjs +6 -3
  38. package/src/doctor-transactions-r58.mjs +1 -1
  39. package/src/host-plane.mjs +9 -3
  40. package/src/machine-fs-mcp-tools.mjs +1 -1
  41. package/src/machine-fs.mjs +7 -4
  42. package/src/process-policy.mjs +7 -4
  43. package/src/remote-authority.mjs +20 -1
  44. package/src/runtime-update.mjs +15 -5
  45. package/src/version.mjs +1 -1
  46. package/test/audit-context.test.mjs +15 -4
  47. package/test/autonomous-local-supervisor.test.mjs +7 -6
  48. package/test/autonomous-supervisor-integration.test.mjs +8 -7
  49. package/test/capability-resolver.test.mjs +11 -5
  50. package/test/codex-autonomous-r44.test.mjs +7 -6
  51. package/test/coding-observation.test.mjs +4 -3
  52. package/test/commander-real-parity-r47.test.mjs +5 -4
  53. package/test/commander-torture-r47.test.mjs +5 -4
  54. package/test/desktop-policy-r40.test.mjs +6 -4
  55. package/test/desktop-runtime-r40.test.mjs +8 -3
  56. package/test/host-inline-r45.test.mjs +4 -3
  57. package/test/machine-fs-runtime.test.mjs +4 -3
  58. package/test/process-longrun-r36.test.mjs +3 -2
  59. package/test/process-policy.test.mjs +10 -6
  60. package/test/process-runtime.test.mjs +9 -6
  61. package/test/r52-host-revocation.test.mjs +1 -0
  62. package/test/r59-tool-surface-compat.test.mjs +14 -4
  63. package/test/r62-release-contract.test.mjs +2 -1
  64. package/test/r63-one-shot-coherence.test.mjs +38 -0
  65. package/test/r63-release-contract.test.mjs +59 -0
  66. package/test/r64-machine-fs-large-read.test.mjs +136 -0
  67. package/test/r64-release-contract.test.mjs +52 -0
  68. package/test/r65-activation-lock-recovery.test.mjs +72 -0
  69. package/test/r65-activation-lock.test.mjs +59 -0
  70. package/test/r65-activation-orchestration.test.mjs +179 -0
  71. package/test/r65-activation-preflight.test.mjs +35 -0
  72. package/test/r65-authority-continuity-decision.test.mjs +58 -0
  73. package/test/r65-authority-durable-policy-binding.test.mjs +34 -0
  74. package/test/r65-authority-epoch-cli.test.mjs +125 -0
  75. package/test/r65-authority-epoch-races.test.mjs +87 -0
  76. package/test/r65-authority-epoch-recovery.test.mjs +82 -0
  77. package/test/r65-authority-epoch-store.test.mjs +94 -0
  78. package/test/r65-authority-fixture.mjs +41 -0
  79. package/test/r65-authority-grant-capture.test.mjs +37 -0
  80. package/test/r65-authority-observation-epoch.test.mjs +25 -0
  81. package/test/r65-authority-policy-envelope.test.mjs +46 -0
  82. package/test/r65-authority-restored-safe.test.mjs +75 -0
  83. package/test/r65-authority-runtime-epoch.test.mjs +115 -0
  84. package/test/r65-authority-runtime-policy-binding.test.mjs +29 -0
  85. package/test/r65-authority-test-trust.mjs +20 -0
  86. package/test/r65-cli-invocation.test.mjs +38 -0
  87. package/test/r65-controller-authority-epoch-live.test.mjs +100 -0
  88. package/test/r65-controller-authority-epoch.test.mjs +37 -0
  89. package/test/r65-deploy-preflight.test.mjs +55 -0
  90. package/test/r65-epoch-native-activation-integration.test.mjs +141 -0
  91. package/test/r65-epoch-native-continuity-engine.test.mjs +112 -0
  92. package/test/r65-epoch-native-cross-plane.test.mjs +95 -0
  93. package/test/r65-legacy-authority-migration.test.mjs +63 -0
  94. package/test/r65-legacy-auto-restore-rejection.test.mjs +17 -0
  95. package/test/r65-npm-publication.test.mjs +114 -0
  96. package/test/r65-parent-source-verifier.test.mjs +63 -0
  97. package/test/r65-release-contract.test.mjs +74 -0
  98. package/test/r65-transaction-precondition.test.mjs +36 -0
  99. package/test/remote-session-cli.test.mjs +13 -11
  100. package/test/standing-grants.test.mjs +20 -4
@@ -0,0 +1,225 @@
1
+ import {createHash,randomBytes} from 'node:crypto';
2
+ import {open,readFile,rm} from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import {canonicalJson} from './canonical-json.mjs';
5
+ import {
6
+ captureStandingGrant,compareSecurityEnvelopes,createAuthorityEpochStore,deriveSecurityEnvelope
7
+ } from './authority-continuity-r65.mjs';
8
+
9
+ const PLANES=Object.freeze(['process','coding','autonomous','desktop','host']);
10
+ const REVOKE_ORDER=Object.freeze(['host','desktop','autonomous','coding','process']);
11
+ const RESTORE_ORDER=Object.freeze(['process','coding','autonomous','desktop','host']);
12
+ const HEX64=/^[0-9a-f]{64}$/;
13
+ const GRANT_PATH_FIELD=Object.freeze({
14
+ process:'grant_file',coding:'lease_file',autonomous:'lease_file',desktop:'grant_file',host:'arm_file'
15
+ });
16
+ const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
17
+ const plain=value=>value&&typeof value==='object'&&!Array.isArray(value);
18
+
19
+ function parseJson(bytes,label){
20
+ try{return JSON.parse(bytes.toString('utf8'));}
21
+ catch{throw new Error(`${label} JSON invalid`);}
22
+ }
23
+ function inside(root,target){
24
+ const rel=path.relative(path.resolve(root),path.resolve(target));
25
+ return rel===''||(!rel.startsWith('..'+path.sep)&&rel!=='..'&&!path.isAbsolute(rel));
26
+ }
27
+ function grantPath(policy,plane,stateRoot){
28
+ const field=GRANT_PATH_FIELD[plane],raw=policy?.[field];
29
+ if(typeof raw!=='string'||!path.isAbsolute(raw))throw new Error(`${plane} grant path missing`);
30
+ const resolved=path.resolve(raw),runtimeRoot=path.join(path.resolve(stateRoot),'runtime');
31
+ if(!inside(runtimeRoot,resolved))throw new Error(`${plane} grant path escapes runtime state`);
32
+ return resolved;
33
+ }
34
+ async function readOptional(file){
35
+ try{return await readFile(file);}catch(error){if(error?.code==='ENOENT')return null;throw error;}
36
+ }
37
+ async function writeExclusive(file,bytes){
38
+ const handle=await open(file,'wx',0o600);
39
+ try{await handle.writeFile(bytes);await handle.sync();}
40
+ finally{await handle.close();}
41
+ }
42
+ async function removeIfExact(file,expectedSha256){
43
+ const current=await readOptional(file);
44
+ if(current===null)return {removed:false,reason:'absent'};
45
+ if(sha(current)!==expectedSha256)return {removed:false,reason:'replacement'};
46
+ await rm(file,{force:true});
47
+ return {removed:true,reason:'matched'};
48
+ }
49
+ function validateCapture(capture){
50
+ if(!plain(capture)||typeof capture.update_id!=='string'||!Array.isArray(capture.planes)||!plain(capture.records))throw new Error('authority continuity capture invalid');
51
+ for(const plane of capture.planes)if(!PLANES.includes(plane)||!capture.records[plane])throw new Error('authority continuity capture plane invalid');
52
+ }
53
+ function scopePermitted(plane,scope,policy){
54
+ if(plane==='process')return Array.isArray(scope.root_ids)&&Array.isArray(scope.profile_ids)&&
55
+ scope.root_ids.every(id=>Object.hasOwn(policy.roots??{},id))&&
56
+ scope.profile_ids.every(id=>Object.hasOwn(policy.profiles??{},id)&&
57
+ Array.isArray(policy.profiles[id]?.root_ids)&&policy.profiles[id].root_ids.every(rootId=>scope.root_ids.includes(rootId)));
58
+ if(plane==='coding')return Array.isArray(scope.root_ids)&&scope.root_ids.every(id=>Object.hasOwn(policy.roots??{},id));
59
+ if(plane==='autonomous')return Array.isArray(scope.root_ids)&&scope.root_ids.every(id=>(policy.root_ids??[]).includes(id));
60
+ if(plane==='desktop')return Array.isArray(scope.action_kinds)&&scope.action_kinds.every(id=>(policy.allowed_actions??[]).includes(id));
61
+ return plane==='host';
62
+ }
63
+ function buildSuccessorGrant({plane,record,successorPolicyBytes,successorPolicy}){
64
+ const policySha256=sha(successorPolicyBytes),instanceNonce=randomBytes(32).toString('hex'),grantedAt=new Date().toISOString();
65
+ let grant;
66
+ if(plane==='process')grant={schema:record.grant_schema,policy_sha256:policySha256,instance_nonce:instanceNonce,
67
+ profile_ids:[...record.granted_scope.profile_ids],root_ids:[...record.granted_scope.root_ids],granted_at_utc:grantedAt};
68
+ else if(plane==='coding')grant={schema:record.grant_schema,policy_sha256:policySha256,instance_nonce:instanceNonce,
69
+ root_ids:[...record.granted_scope.root_ids],granted_at_utc:grantedAt};
70
+ else if(plane==='autonomous')grant={schema:record.grant_schema,policy_sha256:policySha256,
71
+ coding_policy_sha256:successorPolicy.coding_policy_sha256,instance_nonce:instanceNonce,
72
+ root_ids:[...record.granted_scope.root_ids],granted_at_utc:grantedAt};
73
+ else if(plane==='desktop')grant={schema:record.grant_schema,policy_sha256:policySha256,instance_nonce:instanceNonce,
74
+ action_kinds:[...record.granted_scope.action_kinds],granted_at_utc:grantedAt};
75
+ else if(plane==='host')grant={schema:record.grant_schema,policy_sha256:policySha256,instance_nonce:instanceNonce,granted_at_utc:grantedAt};
76
+ else throw new Error('authority continuity plane invalid');
77
+ return {grant,bytes:Buffer.from(canonicalJson(grant),'utf8'),instanceNonce};
78
+ }
79
+ function classifyConflict(head,record,updateId){
80
+ if(!head)return 'REAUTH_REQUIRED';
81
+ if(head.action==='user_revoke')return 'REVOKED_DURING_UPDATE';
82
+ if((head.action==='grant'||head.action==='transaction_restore')&&
83
+ (head.grant_sha256!==record.grant_sha256||head.grant_instance_nonce!==record.grant_instance_nonce))return 'REPLACED';
84
+ if(head.action==='transaction_revoke'&&head.update_id===updateId&&
85
+ head.grant_sha256===record.grant_sha256&&head.grant_instance_nonce===record.grant_instance_nonce)return null;
86
+ return 'REAUTH_REQUIRED';
87
+ }
88
+
89
+ export function createEpochNativeContinuityEngine({stateRoot,predecessorPolicyPaths,successorPolicyPaths,updateId}={}){
90
+ const state=path.resolve(String(stateRoot??''));
91
+ if(!stateRoot||!plain(predecessorPolicyPaths)||typeof successorPolicyPaths!=='function'||
92
+ typeof updateId!=='string'||!/^[A-Za-z0-9._-]{1,96}$/.test(updateId))
93
+ throw new Error('authority continuity engine configuration invalid');
94
+
95
+ return Object.freeze({
96
+ async capture({observation,subject_sha256,pointer,expectedParent,candidate,expectedCandidate}){
97
+ if(!HEX64.test(String(subject_sha256))||!plain(observation?.authority))throw new Error('authority continuity capture subject invalid');
98
+ if(expectedParent?.release_id!==pointer?.release_id||expectedParent?.generation_manifest_sha256!==pointer?.generation_manifest_sha256||
99
+ expectedCandidate?.version!==candidate?.version||expectedCandidate?.manifest_sha256!==candidate?.manifest_sha256)
100
+ throw new Error('authority continuity lineage mismatch');
101
+ const records={},planes=[];
102
+ for(const plane of PLANES){
103
+ const authority=observation.authority[plane];
104
+ if(!authority?.armed)continue;
105
+ if(!Number.isSafeInteger(authority.epoch_seq)||authority.epoch_seq<1||!HEX64.test(String(authority.epoch_sha256)))
106
+ throw new Error(`${plane} standing authority is legacy or epoch identity is incomplete`);
107
+ const policyPath=predecessorPolicyPaths[plane];
108
+ if(typeof policyPath!=='string'||!path.isAbsolute(policyPath))throw new Error(`${plane} predecessor policy path unavailable`);
109
+ const policyBytes=await readFile(policyPath),policy=parseJson(policyBytes,`${plane} predecessor policy`);
110
+ const file=grantPath(policy,plane,state),grantBytes=await readFile(file),grant=parseJson(grantBytes,`${plane} predecessor grant`);
111
+ const store=createAuthorityEpochStore({runtimeDir:path.dirname(file),policyBytes});
112
+ const verified=await store.verifyGrant({plane,grantBytes,grantInstanceNonce:grant.instance_nonce,policyBytes});
113
+ const head=await store.readHead({plane});
114
+ if(!verified.trusted||!head||head.action!=='grant'&&head.action!=='transaction_restore'||
115
+ head.seq!==authority.epoch_seq||head.event_sha256!==authority.epoch_sha256)
116
+ throw new Error(`${plane} observed standing authority does not match durable epoch`);
117
+ const record=captureStandingGrant({plane,policyBytes,grantBytes,predecessor:expectedParent,candidate:expectedCandidate,updateId});
118
+ records[plane]=Object.freeze({record,policy_path:policyPath,grant_file:file,prior_policy_bytes:policyBytes,
119
+ prior_grant_bytes:grantBytes,captured_head:Object.freeze({...head})});
120
+ planes.push(plane);
121
+ }
122
+ if(planes.length===0)throw new Error('epoch-native continuity capture has no armed planes');
123
+ return Object.freeze({schema:'deadbyte.activation-authority-capture.r65.v1',update_id:updateId,subject_sha256,
124
+ planes:Object.freeze(planes),records:Object.freeze(records)});
125
+ },
126
+
127
+ async revoke(capture){
128
+ validateCapture(capture);
129
+ const outcomes={};
130
+ for(const plane of REVOKE_ORDER){
131
+ const item=capture.records[plane];
132
+ if(!item)continue;
133
+ const {record,prior_policy_bytes:policyBytes,prior_grant_bytes:grantBytes,grant_file:file,captured_head:capturedHead}=item;
134
+ const store=createAuthorityEpochStore({runtimeDir:path.dirname(file),policyBytes});
135
+ const current=await store.readHead({plane});
136
+ if(!current||current.event_sha256!==capturedHead.event_sha256||current.seq!==capturedHead.seq)
137
+ throw new Error(`${plane} authority changed before transaction revoke`);
138
+ const revoked=await store.append({plane,action:'transaction_revoke',grantBytes,
139
+ grantInstanceNonce:record.grant_instance_nonce,updateId:capture.update_id,expectedHeadSha256:capturedHead.event_sha256});
140
+ let observed=await store.readHead({plane});
141
+ if(!observed||observed.event_sha256!==revoked.event_sha256)
142
+ throw new Error(`${plane} authority changed during transaction revoke`);
143
+ const sentinel=await readOptional(file);
144
+ if(sentinel===null)throw new Error(`${plane} grant disappeared during transaction revoke`);
145
+ if(sha(sentinel)!==record.grant_sha256)throw new Error(`${plane} replacement grant appeared during transaction revoke`);
146
+ observed=await store.readHead({plane});
147
+ if(!observed||observed.event_sha256!==revoked.event_sha256){
148
+ const conflict=classifyConflict(observed,record,capture.update_id);
149
+ throw new Error(`${plane} authority changed after transaction revoke: ${conflict??'unknown'}`);
150
+ }
151
+ const verification=await store.verifyGrant({plane,grantBytes,grantInstanceNonce:record.grant_instance_nonce,policyBytes});
152
+ if(verification.trusted)throw new Error(`${plane} remained trusted after transaction revoke`);
153
+ outcomes[plane]='TRANSACTION_REVOKED';
154
+ }
155
+ return Object.freeze(outcomes);
156
+ },
157
+
158
+ async restore({capture,successor_observation,activation,candidate,expectedCandidate,subject_sha256}){
159
+ validateCapture(capture);
160
+ if(capture.subject_sha256!==subject_sha256||expectedCandidate?.version!==candidate?.version||
161
+ expectedCandidate?.manifest_sha256!==candidate?.manifest_sha256||activation?.verified!==true)
162
+ throw new Error('authority continuity restore subject invalid');
163
+ const paths=await successorPolicyPaths();
164
+ if(!plain(paths))throw new Error('successor authority policy paths unavailable');
165
+ const outcomes=Object.fromEntries(PLANES.map(plane=>[plane,capture.records[plane]?'REAUTH_REQUIRED':'NOT_APPLICABLE']));
166
+ const reauth=[],restoredNonces={};
167
+ let codingRestored=!capture.records.coding;
168
+ for(const plane of RESTORE_ORDER){
169
+ const item=capture.records[plane];
170
+ if(!item)continue;
171
+ const {record,prior_policy_bytes:priorPolicyBytes,prior_grant_bytes:priorGrantBytes,grant_file:file}=item;
172
+ if(plane==='autonomous'&&!codingRestored){outcomes[plane]='REAUTH_REQUIRED';reauth.push(plane);continue;}
173
+ const policyPath=paths[plane];
174
+ if(typeof policyPath!=='string'||!path.isAbsolute(policyPath)){outcomes[plane]='REAUTH_REQUIRED';reauth.push(plane);continue;}
175
+ let successorPolicyBytes,successorPolicy,priorPolicy;
176
+ try{
177
+ successorPolicyBytes=await readFile(policyPath);
178
+ successorPolicy=parseJson(successorPolicyBytes,`${plane} successor policy`);
179
+ priorPolicy=parseJson(priorPolicyBytes,`${plane} predecessor policy`);
180
+ }catch{outcomes[plane]='REAUTH_REQUIRED';reauth.push(plane);continue;}
181
+ const priorEnvelope=deriveSecurityEnvelope(plane,priorPolicy),successorEnvelope=deriveSecurityEnvelope(plane,successorPolicy);
182
+ const relation=compareSecurityEnvelopes(plane,priorEnvelope,successorEnvelope).relation;
183
+ if(relation==='WIDER'){outcomes[plane]='POLICY_WIDENED';reauth.push(plane);continue;}
184
+ if(relation==='UNVERIFIED'||!scopePermitted(plane,record.granted_scope,successorPolicy)){
185
+ outcomes[plane]='REAUTH_REQUIRED';reauth.push(plane);continue;
186
+ }
187
+ const successorGrantPath=grantPath(successorPolicy,plane,state);
188
+ if(successorGrantPath!==file){outcomes[plane]='REAUTH_REQUIRED';reauth.push(plane);continue;}
189
+ const store=createAuthorityEpochStore({runtimeDir:path.dirname(file),policyBytes:successorPolicyBytes});
190
+ const head=await store.readHead({plane}),conflict=classifyConflict(head,record,capture.update_id);
191
+ if(conflict){
192
+ if(conflict==='REVOKED_DURING_UPDATE')await removeIfExact(file,record.grant_sha256).catch(()=>{});
193
+ outcomes[plane]=conflict;reauth.push(plane);continue;
194
+ }
195
+ const existing=await readOptional(file);
196
+ if(existing===null){outcomes[plane]='REVOKED_DURING_UPDATE';reauth.push(plane);continue;}
197
+ if(sha(existing)!==record.grant_sha256){outcomes[plane]='REPLACED';reauth.push(plane);continue;}
198
+ await rm(file,{force:true});
199
+ const prepared=buildSuccessorGrant({plane,record,successorPolicyBytes,successorPolicy});
200
+ try{await writeExclusive(file,prepared.bytes);}
201
+ catch(error){if(error?.code==='EEXIST'){outcomes[plane]='REPLACED';reauth.push(plane);continue;}throw error;}
202
+ try{
203
+ const restoreBinding={prior_grant_sha256:record.grant_sha256,prior_grant_instance_nonce:record.grant_instance_nonce,
204
+ predecessor_policy_envelope_sha256:record.prior_policy_envelope_sha256,successor_policy_envelope_sha256:successorEnvelope.sha256,
205
+ candidate_manifest_sha256:expectedCandidate.manifest_sha256,continuity_subject_sha256:capture.subject_sha256};
206
+ const restored=await store.append({plane,action:'transaction_restore',grantBytes:prepared.bytes,
207
+ grantInstanceNonce:prepared.instanceNonce,updateId:capture.update_id,expectedHeadSha256:head.event_sha256,restoreBinding});
208
+ const verified=await store.verifyGrant({plane,grantBytes:prepared.bytes,grantInstanceNonce:prepared.instanceNonce,policyBytes:successorPolicyBytes});
209
+ if(!verified.trusted||verified.event_sha256!==restored.event_sha256)throw new Error(`${plane} restored grant did not verify`);
210
+ outcomes[plane]=relation==='NARROWER'?'RESTORED_SAFE':'RESTORED_EXACT';restoredNonces[plane]=prepared.instanceNonce;
211
+ if(plane==='coding')codingRestored=true;
212
+ }catch(error){
213
+ const current=await store.readHead({plane}).catch(()=>null);
214
+ const currentConflict=classifyConflict(current,record,capture.update_id);
215
+ const cleanup=await removeIfExact(file,sha(prepared.bytes)).catch(()=>({reason:'cleanup-failed'}));
216
+ if(currentConflict){outcomes[plane]=currentConflict;reauth.push(plane);continue;}
217
+ if(cleanup.reason==='replacement'){outcomes[plane]='REPLACED';reauth.push(plane);continue;}
218
+ throw error;
219
+ }
220
+ }
221
+ return Object.freeze({authority_outcomes:Object.freeze(outcomes),restored_nonces:Object.freeze(restoredNonces),
222
+ reauth_planes:Object.freeze([...new Set(reauth)])});
223
+ }
224
+ });
225
+ }
@@ -0,0 +1,155 @@
1
+ import {createPublicKey,randomBytes} from 'node:crypto';
2
+ import {mkdir,open,readFile,readdir,unlink} from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import {verifySlotUpdateEnvelope} from './runtime-update.mjs';
5
+
6
+ const HEX64=/^[0-9a-f]{64}$/;
7
+ const OP=/^[0-9a-f]{32}$/;
8
+ const LOCK_SCHEMA='deadbyte.r65-activation-claim.v1';
9
+ const OUTCOME_SCHEMA='deadbyte.r65-activation-outcome.v1';
10
+ const UPDATE_SCHEMA='deadbyte.r27-slot-update-receipt.v1';
11
+ const MAX_OUTCOME_SCAN=2048;
12
+
13
+ async function writeExclusive(file,value){
14
+ const handle=await open(file,'wx',0o600);
15
+ try{await handle.writeFile(JSON.stringify(value)+'\n');await handle.sync();}
16
+ finally{await handle.close();}
17
+ }
18
+
19
+ function validateLock(value){
20
+ if(!value||typeof value!=='object'||Array.isArray(value)||value.schema!==LOCK_SCHEMA||
21
+ !OP.test(String(value.operation_id??''))||!HEX64.test(String(value.subject_sha256??''))||
22
+ typeof value.created_at_utc!=='string'||!Number.isFinite(Date.parse(value.created_at_utc)))
23
+ throw new Error('activation claim lock invalid or corrupt');
24
+ return value;
25
+ }
26
+
27
+ async function readLock(lockPath){
28
+ let text;
29
+ try{text=await readFile(lockPath,'utf8');}
30
+ catch(error){if(error?.code==='ENOENT')return null;throw error;}
31
+ let value;
32
+ try{value=JSON.parse(text);}catch{throw new Error('activation claim lock corrupt');}
33
+ return validateLock(value);
34
+ }
35
+
36
+ function outcomeMatchesLock(outcome,lock){
37
+ return !!outcome&&typeof outcome==='object'&&!Array.isArray(outcome)&&outcome.schema===OUTCOME_SCHEMA&&
38
+ outcome.claim_operation_id===lock.operation_id&&outcome.preflight_subject_sha256===lock.subject_sha256;
39
+ }
40
+
41
+ function isSafePreMutationReject(outcome,lock){
42
+ return outcomeMatchesLock(outcome,lock)&&outcome?.outcome?.state==='ACTIVATION_REJECTED'&&
43
+ outcome.update_id===null&&outcome.state_path===null;
44
+ }
45
+
46
+ function pointerIdentity(value){
47
+ if(!value||typeof value!=='object'||Array.isArray(value))return null;
48
+ const result={
49
+ release_id:value.release_id,version:value.version,manifest_sha256:value.manifest_sha256,
50
+ generation_manifest_sha256:value.generation_manifest_sha256
51
+ };
52
+ if(typeof result.release_id!=='string'||typeof result.version!=='string'||
53
+ !HEX64.test(String(result.manifest_sha256??''))||!HEX64.test(String(result.generation_manifest_sha256??'')))return null;
54
+ return result;
55
+ }
56
+
57
+ function samePointerIdentity(a,b){
58
+ const left=pointerIdentity(a),right=pointerIdentity(b);
59
+ return !!left&&!!right&&left.release_id===right.release_id&&left.version===right.version&&
60
+ left.manifest_sha256===right.manifest_sha256&&left.generation_manifest_sha256===right.generation_manifest_sha256;
61
+ }
62
+
63
+ async function isSafeTerminalActivation(outcome,lock,stateRoot){
64
+ if(!outcomeMatchesLock(outcome,lock)||outcome?.outcome?.state!=='ACTIVATED')return false;
65
+ if(typeof outcome.update_id!=='string'||outcome.update_id.length<1||
66
+ typeof outcome.state_path!=='string'||!path.isAbsolute(outcome.state_path)||
67
+ typeof outcome.candidate_version!=='string'||!HEX64.test(String(outcome.candidate_manifest_sha256??''))||
68
+ typeof outcome.predecessor_release_id!=='string')return false;
69
+ const statePath=path.resolve(outcome.state_path),updatesRoot=path.join(path.resolve(stateRoot),'evidence','updates');
70
+ const rel=path.relative(updatesRoot,statePath);
71
+ if(rel.startsWith('..'+path.sep)||rel==='..'||path.isAbsolute(rel))return false;
72
+ const receiptPath=path.join(path.dirname(statePath),'receipt.json');
73
+ let receipt,publicKey,active;
74
+ try{
75
+ receipt=JSON.parse(await readFile(receiptPath,'utf8'));
76
+ publicKey=createPublicKey(await readFile(path.join(path.resolve(stateRoot),'trust','ed25519-public.pem')));
77
+ active=JSON.parse(await readFile(path.join(path.resolve(stateRoot),'active-release.json'),'utf8'));
78
+ }catch{return false;}
79
+ if(publicKey.asymmetricKeyType!=='ed25519'||!verifySlotUpdateEnvelope(receipt,publicKey))return false;
80
+ const body=receipt.body;
81
+ if(body?.schema!==UPDATE_SCHEMA||body.rollback_performed!==false||body.update_id!==outcome.update_id||
82
+ body.release_version!==outcome.candidate_version||body.candidate_manifest_sha256!==outcome.candidate_manifest_sha256||
83
+ body.prior_pointer?.release_id!==outcome.predecessor_release_id)return false;
84
+ if(!samePointerIdentity(body.active_pointer,active))return false;
85
+ return true;
86
+ }
87
+
88
+ async function findTerminalOutcome(updatesDir,lock,stateRoot){
89
+ const names=(await readdir(updatesDir)).filter(name=>/^r65-activation-outcome-.*\.json$/.test(name)).sort();
90
+ if(names.length>MAX_OUTCOME_SCAN)throw new Error('activation outcome inventory exceeds safe scan budget');
91
+ let matched=false,foreign=false,unknown=false;
92
+ for(const name of names){
93
+ let value;
94
+ try{value=JSON.parse(await readFile(path.join(updatesDir,name),'utf8'));}
95
+ catch{continue;}
96
+ if(value?.claim_operation_id!==lock.operation_id)continue;
97
+ if(value?.preflight_subject_sha256!==lock.subject_sha256){foreign=true;continue;}
98
+ if(isSafePreMutationReject(value,lock)||await isSafeTerminalActivation(value,lock,stateRoot))matched=true;
99
+ else unknown=true;
100
+ }
101
+ return {matched,foreign,unknown};
102
+ }
103
+
104
+ export function createActivationClaimManager({stateRoot}={}){
105
+ if(typeof stateRoot!=='string'||stateRoot.length<1)throw new Error('activation claim state root invalid');
106
+ const state=path.resolve(stateRoot),updatesDir=path.join(state,'evidence','updates');
107
+ const lockPath=path.join(updatesDir,'r65-activation.lock');
108
+
109
+ async function create(subjectSha256){
110
+ if(!HEX64.test(String(subjectSha256??'')))throw new Error('activation claim subject invalid');
111
+ const claim={schema:LOCK_SCHEMA,operation_id:randomBytes(16).toString('hex'),subject_sha256:subjectSha256,created_at_utc:new Date().toISOString()};
112
+ await writeExclusive(lockPath,claim);
113
+ return claim;
114
+ }
115
+
116
+ async function releaseOwned(claim){
117
+ const current=await readLock(lockPath);
118
+ if(!current)throw new Error('activation claim ownership missing at release');
119
+ if(current.operation_id!==claim.operation_id||current.subject_sha256!==claim.subject_sha256)
120
+ throw new Error('activation claim changed before release');
121
+ await unlink(lockPath);
122
+ }
123
+
124
+ return Object.freeze({
125
+ async claim(subjectSha256){
126
+ if(!HEX64.test(String(subjectSha256??'')))throw new Error('activation claim subject invalid');
127
+ await mkdir(updatesDir,{recursive:true});
128
+ try{
129
+ const claim=await create(subjectSha256);
130
+ return Object.freeze({...claim,release:async()=>releaseOwned(claim)});
131
+ }catch(error){
132
+ if(error?.code!=='EEXIST')throw error;
133
+ }
134
+
135
+ const existing=await readLock(lockPath);
136
+ if(!existing)throw new Error('activation claim disappeared during reconciliation');
137
+ const evidence=await findTerminalOutcome(updatesDir,existing,state);
138
+ if(!evidence.matched||evidence.foreign||evidence.unknown)
139
+ throw new Error(evidence.foreign?'activation claim subject mismatch or unresolved owner':'activation claim unresolved or in progress');
140
+
141
+ const current=await readLock(lockPath);
142
+ if(!current||current.operation_id!==existing.operation_id||current.subject_sha256!==existing.subject_sha256)
143
+ throw new Error('activation claim changed during terminal reconciliation');
144
+ await unlink(lockPath);
145
+
146
+ try{
147
+ const claim=await create(subjectSha256);
148
+ return Object.freeze({...claim,release:async()=>releaseOwned(claim)});
149
+ }catch(error){
150
+ if(error?.code==='EEXIST')throw new Error('activation claim acquired concurrently during reconciliation');
151
+ throw error;
152
+ }
153
+ }
154
+ });
155
+ }
@@ -0,0 +1,197 @@
1
+ import {createHash} from 'node:crypto';
2
+
3
+ const PLANES=['process','coding','autonomous','desktop','host'];
4
+ const HEX64=/^[0-9a-f]{64}$/;
5
+ const canonical=value=>Array.isArray(value)?value.map(canonical):value&&typeof value==='object'
6
+ ?Object.fromEntries(Object.keys(value).sort().map(key=>[key,canonical(value[key])])):value;
7
+ const digest=value=>createHash('sha256').update(JSON.stringify(canonical(value))).digest('hex');
8
+ const vector=observation=>Object.fromEntries(PLANES.map(plane=>{
9
+ const entry=observation?.authority?.[plane];return [plane,typeof entry==='boolean'?entry:entry?.armed];
10
+ }));
11
+
12
+ export function classifyAuthorityContinuity(observation){
13
+ const armed=[],legacy=[],epoch=[];
14
+ for(const plane of PLANES){
15
+ const entry=observation?.authority?.[plane];
16
+ const isArmed=typeof entry==='boolean'?entry:entry?.armed;
17
+ if(typeof isArmed!=='boolean')return Object.freeze({state:'UNVERIFIED',armed_planes:[],reauth_planes:[],epoch_planes:[],reason:`${plane} authority observation incomplete`});
18
+ if(!isArmed)continue;
19
+ armed.push(plane);
20
+ if(typeof entry==='boolean'){legacy.push(plane);continue;}
21
+ const hasSeq=entry.epoch_seq!==undefined&&entry.epoch_seq!==null;
22
+ const hasSha=entry.epoch_sha256!==undefined&&entry.epoch_sha256!==null;
23
+ if(hasSeq!==hasSha)return Object.freeze({state:'UNVERIFIED',armed_planes:armed,reauth_planes:armed,epoch_planes:epoch,reason:`${plane} epoch observation incomplete`});
24
+ if(!hasSeq){legacy.push(plane);continue;}
25
+ if(!Number.isSafeInteger(entry.epoch_seq)||entry.epoch_seq<1||typeof entry.epoch_sha256!=='string'||!HEX64.test(entry.epoch_sha256))
26
+ return Object.freeze({state:'UNVERIFIED',armed_planes:armed,reauth_planes:armed,epoch_planes:epoch,reason:`${plane} epoch observation invalid`});
27
+ epoch.push(plane);
28
+ }
29
+ if(armed.length===0)return Object.freeze({state:'NOT_APPLICABLE',armed_planes:[],reauth_planes:[],epoch_planes:[]});
30
+ if(legacy.length===armed.length)return Object.freeze({state:'LEGACY_REAUTH_REQUIRED',armed_planes:armed,reauth_planes:armed,epoch_planes:[]});
31
+ if(epoch.length===armed.length)return Object.freeze({state:'EPOCH_NATIVE',armed_planes:armed,reauth_planes:[],epoch_planes:epoch});
32
+ return Object.freeze({state:'MIXED_REAUTH_REQUIRED',armed_planes:armed,reauth_planes:armed,epoch_planes:epoch,legacy_planes:legacy});
33
+ }
34
+
35
+ export function authorityTransitionPlan(authority){
36
+ if(!authority||PLANES.some(plane=>typeof authority[plane]!=='boolean'))throw new Error('activation authority vector incomplete');
37
+ if(authority.autonomous&&!authority.coding)throw new Error('activation authority vector inconsistent');
38
+ return Object.freeze({
39
+ before:Object.freeze(['desktop','host'].filter(plane=>authority[plane]).map(plane=>`disarm${plane}`)),
40
+ after:Object.freeze(['desktop','host'].filter(plane=>authority[plane]).map(plane=>`arm${plane}`))
41
+ });
42
+ }
43
+
44
+ export function classifyActivationPreflight({pointer,expectedParent,candidate,expectedCandidate,observation}){
45
+ if(!expectedParent||!expectedCandidate||!candidate||!pointer)throw new Error('activation preflight subject missing');
46
+ const authority=vector(observation);
47
+ if(PLANES.some(plane=>typeof authority[plane]!=='boolean'))return Object.freeze({state:'UNKNOWN',safe_to_activate:false,reason:'authority observation incomplete'});
48
+ const subject={pointer,expectedParent,candidate,expectedCandidate,observation};
49
+ const bound={subject_sha256:digest(subject),authority:Object.freeze(authority)};
50
+ if(PLANES.some(plane=>!HEX64.test(String(observation?.policy_sha256?.[plane]))))
51
+ return Object.freeze({state:'UNKNOWN',safe_to_activate:false,reason:'policy hash observation incomplete',...bound});
52
+ if(pointer.release_id!==expectedParent.release_id||pointer.version!==expectedParent.version||
53
+ pointer.manifest_sha256!==expectedParent.manifest_sha256||pointer.generation_manifest_sha256!==expectedParent.generation_manifest_sha256)
54
+ return Object.freeze({state:'POINTER_DRIFT',safe_to_activate:false,...bound});
55
+ if(observation.active_release_id!==pointer.release_id||observation.active_manifest_sha256!==pointer.manifest_sha256||
56
+ observation.active_generation_manifest_sha256!==pointer.generation_manifest_sha256)
57
+ return Object.freeze({state:'POINTER_DRIFT',safe_to_activate:false,...bound});
58
+ if(candidate.version!==expectedCandidate.version||candidate.manifest_sha256!==expectedCandidate.manifest_sha256)
59
+ return Object.freeze({state:'CANDIDATE_DRIFT',safe_to_activate:false,...bound});
60
+ if(authority.autonomous&&!authority.coding)return Object.freeze({state:'RUNTIME_DRIFT',safe_to_activate:false,...bound});
61
+ if(observation?.state==='PARKED')return Object.freeze({state:'PARKED_DIRTY',safe_to_activate:false,...bound});
62
+ if(observation?.state==='OFFLINE'){
63
+ const clean=!observation.bridge?.alive&&!observation.core?.alive&&!observation.cloud?.alive&&!observation.supervisor?.running&&
64
+ PLANES.every(plane=>!authority[plane]);
65
+ return Object.freeze({state:clean?'OFFLINE_CLEAN':'OFFLINE_DIRTY',safe_to_activate:clean,...bound});
66
+ }
67
+ if(observation?.state!=='ONLINE')return Object.freeze({state:'UNKNOWN',safe_to_activate:false,...bound});
68
+ if(observation.local_ready!==true||['bridge','core','cloud'].some(name=>observation[name]?.alive!==true||observation[name]?.reason!=='verified'||
69
+ !Number.isSafeInteger(observation[name]?.pid)||observation[name].pid<1)||observation.supervisor?.running!==true)
70
+ return Object.freeze({state:'RUNTIME_DRIFT',safe_to_activate:false,...bound});
71
+ if(authority.host)return Object.freeze({state:'ONLINE_HOST_ARMED',safe_to_activate:false,...bound});
72
+ return Object.freeze({state:'ONLINE_READY',safe_to_activate:true,...bound});
73
+ }
74
+
75
+ export async function orchestrateActivation({pointer,expectedParent,candidate,expectedCandidate,observe,command,activate,claim=null,continuityEngine=null,recordOutcome=null}){
76
+ if([observe,command,activate].some(fn=>typeof fn!=='function'))throw new Error('activation orchestrator callbacks invalid');
77
+ const input={pointer,expectedParent,candidate,expectedCandidate};
78
+ const firstObservation=await observe();
79
+ const initial=classifyActivationPreflight({...input,observation:firstObservation});
80
+ if(!['ONLINE_READY','ONLINE_HOST_ARMED','PARKED_DIRTY','OFFLINE_CLEAN'].includes(initial.state))
81
+ return Object.freeze({state:'ACTIVATION_REJECTED',preflight:initial.state,subject_sha256:initial.subject_sha256??null});
82
+ const continuity=classifyAuthorityContinuity(firstObservation);
83
+ if(continuity.state==='UNVERIFIED')
84
+ return Object.freeze({state:'ACTIVATION_REJECTED',preflight:'AUTHORITY_CONTINUITY_UNVERIFIED',reason:continuity.reason??null,
85
+ subject_sha256:initial.subject_sha256??null});
86
+ if(continuity.state==='EPOCH_NATIVE'&&(!continuityEngine||
87
+ ['capture','revoke','restore'].some(name=>typeof continuityEngine[name]!=='function')))
88
+ return Object.freeze({state:'ACTIVATION_REJECTED',preflight:'AUTHORITY_CONTINUITY_ENGINE_REQUIRED',
89
+ reason:'epoch-native standing authority requires transaction continuity proof before activation',
90
+ subject_sha256:initial.subject_sha256??null,authority_continuity:'UNVERIFIED',epoch_planes:continuity.epoch_planes});
91
+ const captured=initial.authority;
92
+ let releaseClaim=null;
93
+ if(claim){
94
+ try{releaseClaim=await claim(initial.subject_sha256);}
95
+ catch(error){return Object.freeze({state:'ACTIVATION_REJECTED',preflight:'CONCURRENT_ACTIVATION',reason:String(error?.message??error).slice(0,256)});}
96
+ }
97
+ let dispatched=false;
98
+ let transitionAttempted=false;
99
+ let continuityCapture=null;
100
+ const outcome=await (async()=>{
101
+ try{
102
+ const requiresReauth=continuity.state==='LEGACY_REAUTH_REQUIRED'||continuity.state==='MIXED_REAUTH_REQUIRED';
103
+ const epochNative=continuity.state==='EPOCH_NATIVE';
104
+ if(epochNative){
105
+ continuityCapture=await continuityEngine.capture({observation:firstObservation,subject_sha256:initial.subject_sha256,
106
+ pointer,expectedParent,candidate,expectedCandidate});
107
+ if(!continuityCapture||typeof continuityCapture!=='object')
108
+ throw new Error('authority continuity capture invalid');
109
+ transitionAttempted=true;
110
+ await continuityEngine.revoke(continuityCapture);
111
+ }
112
+ if(requiresReauth){
113
+ for(const plane of ['host','desktop','autonomous','coding','process']){
114
+ if(!captured[plane])continue;
115
+ transitionAttempted=true;
116
+ await command(`disarm${plane}`);
117
+ }
118
+ }
119
+ if(initial.state==='PARKED_DIRTY'){
120
+ transitionAttempted=true;
121
+ await command('supervisorstop');
122
+ await command('stop');
123
+ }
124
+ const ready=classifyActivationPreflight({...input,observation:await observe()});
125
+ if(!ready.safe_to_activate)
126
+ return Object.freeze({state:transitionAttempted?'ACTIVATION_OUTCOME_UNKNOWN':'ACTIVATION_REJECTED',
127
+ preflight:ready.state,subject_sha256:initial.subject_sha256});
128
+ if(PLANES.some(plane=>ready.authority[plane]!==false))
129
+ return Object.freeze({state:transitionAttempted?'ACTIVATION_OUTCOME_UNKNOWN':'ACTIVATION_REJECTED',
130
+ preflight:'AUTHORITY_NOT_REVOKED',subject_sha256:initial.subject_sha256});
131
+ transitionAttempted=true;
132
+ dispatched=true;
133
+ const activation=await activate();
134
+ if(activation?.verified!==true)throw new Error('activation returned without runtime and pointer verification');
135
+ const current=await observe();
136
+ if(current?.state!=='ONLINE'||current?.local_ready!==true||
137
+ ['bridge','core','cloud'].some(name=>current[name]?.alive!==true||current[name]?.reason!=='verified'))
138
+ throw new Error('successor runtime identity is not verified');
139
+ const beforeRestore=vector(current);
140
+ if(PLANES.some(plane=>typeof beforeRestore[plane]!=='boolean'))throw new Error('successor authority observation incomplete');
141
+ if(PLANES.some(plane=>beforeRestore[plane]!==false))
142
+ throw new Error('successor authority must remain disarmed until continuity restoration or explicit reauthorization');
143
+ if(continuity.state==='EPOCH_NATIVE'){
144
+ const restored=await continuityEngine.restore({capture:continuityCapture,successor_observation:current,activation,
145
+ pointer,expectedParent,candidate,expectedCandidate,subject_sha256:initial.subject_sha256});
146
+ if(!restored||typeof restored!=='object'||!restored.authority_outcomes||typeof restored.authority_outcomes!=='object')
147
+ throw new Error('authority continuity restore result invalid');
148
+ const afterRestore=await observe(),final=vector(afterRestore);
149
+ if(PLANES.some(plane=>typeof final[plane]!=='boolean'))throw new Error('restored successor authority observation incomplete');
150
+ const restoredStates=new Set(['RESTORED_EXACT','RESTORED_SAFE']);
151
+ const priorArmed=continuity.armed_planes??[];
152
+ for(const plane of priorArmed){
153
+ const planeOutcome=restored.authority_outcomes[plane];
154
+ if(typeof planeOutcome!=='string')throw new Error(`authority continuity outcome missing for ${plane}`);
155
+ if(restoredStates.has(planeOutcome)!==final[plane])
156
+ throw new Error(`authority continuity observation mismatch for ${plane}`);
157
+ }
158
+ for(const plane of PLANES){
159
+ if(!priorArmed.includes(plane)&&final[plane]!==false)
160
+ throw new Error(`authority continuity widened previously disarmed ${plane} plane`);
161
+ }
162
+ const authorityOutcome=!priorArmed.every(plane=>restoredStates.has(restored.authority_outcomes[plane]))?'REAUTH_REQUIRED':
163
+ priorArmed.some(plane=>restored.authority_outcomes[plane]==='RESTORED_SAFE')?'RESTORED_SAFE':'RESTORED_EXACT';
164
+ return Object.freeze({state:'ACTIVATED',runtime_activation:'ACTIVATED',authority_continuity:authorityOutcome,
165
+ authority_outcomes:Object.freeze({...restored.authority_outcomes}),subject_sha256:initial.subject_sha256,release_id:activation.release_id,
166
+ prior_authority:Object.freeze({...captured}),final_authority:Object.freeze({...final}),
167
+ reauth_planes:Object.freeze([...(restored.reauth_planes??[])])});
168
+ }
169
+ const final=beforeRestore;
170
+ const authorityOutcome=continuity.state==='NOT_APPLICABLE'?'NOT_APPLICABLE':'REAUTH_REQUIRED';
171
+ return Object.freeze({
172
+ state:'ACTIVATED',runtime_activation:'ACTIVATED',authority_continuity:authorityOutcome,
173
+ subject_sha256:initial.subject_sha256,release_id:activation.release_id,
174
+ prior_authority:Object.freeze({...captured}),final_authority:Object.freeze({...final}),
175
+ reauth_planes:Object.freeze([...(authorityOutcome==='REAUTH_REQUIRED'?continuity.reauth_planes:[])])
176
+ });
177
+ }catch(error){
178
+ return Object.freeze({state:transitionAttempted||dispatched?'ACTIVATION_OUTCOME_UNKNOWN':'ACTIVATION_REJECTED',
179
+ subject_sha256:initial.subject_sha256,reason:String(error?.message??error).slice(0,256)});
180
+ }
181
+ })();
182
+ if(releaseClaim&&recordOutcome!==null){
183
+ if(typeof recordOutcome!=='function')
184
+ return Object.freeze({state:'ACTIVATION_OUTCOME_UNKNOWN',reason:'activation outcome recorder invalid',subject_sha256:initial.subject_sha256});
185
+ try{await recordOutcome(outcome);}
186
+ catch(error){
187
+ return Object.freeze({state:'ACTIVATION_OUTCOME_UNKNOWN',
188
+ reason:`activation outcome persistence failed: ${String(error?.message??error).slice(0,128)}`,
189
+ subject_sha256:initial.subject_sha256});
190
+ }
191
+ }
192
+ if(releaseClaim&&(outcome.state==='ACTIVATED'||(!transitionAttempted&&outcome.state==='ACTIVATION_REJECTED'))){
193
+ try{await releaseClaim();}
194
+ catch(error){return Object.freeze({state:'ACTIVATION_OUTCOME_UNKNOWN',reason:`activation lock release failed: ${String(error?.message??error).slice(0,128)}`,subject_sha256:initial.subject_sha256});}
195
+ }
196
+ return outcome;
197
+ }