deadbyte-mcp 0.15.41 → 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.
- package/DEADBYTE-MCP.cmd +8 -4
- package/MANIFEST.SHA256 +84 -41
- package/PROVENANCE.json +53 -15
- package/README.txt +27 -18
- package/RELEASE.json +43 -15
- package/SBOM.cdx.json +2 -2
- package/TEST-MATRIX.json +106 -14
- package/bridge/package.json +1 -1
- package/controller/deadbyte-controller.ps1 +132 -12
- package/controller/deadbyte-process-policy.json +4 -4
- package/docs/R65-AUTHORITY-CONTINUITY-DESIGN.json +27 -0
- package/docs/R65-REFERENCE-GAP-MATRIX.json +22 -0
- package/package.json +5 -4
- package/scripts/deploy-r48.mjs +123 -7
- package/scripts/gate-windows-r65-prepublish.ps1 +65 -0
- package/scripts/npm-publication-r65.mjs +139 -0
- package/scripts/npm-release-r48.mjs +56 -37
- package/scripts/r65-canonical-full.mjs +45 -0
- package/scripts/r65-focused.mjs +37 -0
- package/scripts/verify-r65-parent-source.mjs +75 -0
- package/src/activation-continuity-engine-r65.mjs +225 -0
- package/src/activation-lock-r65.mjs +155 -0
- package/src/activation-preflight-r65.mjs +197 -0
- package/src/authority-continuity-r65.mjs +541 -0
- package/src/authority-epoch-cli-r65.mjs +10 -0
- package/src/autonomous-policy.mjs +7 -3
- package/src/coding-plane.mjs +12 -3
- package/src/desktop-policy-r40.mjs +6 -3
- package/src/doctor-transactions-r58.mjs +1 -1
- package/src/host-plane.mjs +9 -3
- package/src/process-policy.mjs +7 -4
- package/src/remote-authority.mjs +10 -1
- package/src/runtime-update.mjs +15 -5
- package/src/version.mjs +1 -1
- package/test/audit-context.test.mjs +15 -4
- package/test/autonomous-local-supervisor.test.mjs +7 -6
- package/test/autonomous-supervisor-integration.test.mjs +8 -7
- package/test/capability-resolver.test.mjs +11 -5
- package/test/codex-autonomous-r44.test.mjs +7 -6
- package/test/coding-observation.test.mjs +4 -3
- package/test/commander-real-parity-r47.test.mjs +5 -4
- package/test/commander-torture-r47.test.mjs +5 -4
- package/test/desktop-policy-r40.test.mjs +6 -4
- package/test/desktop-runtime-r40.test.mjs +8 -3
- package/test/host-inline-r45.test.mjs +4 -3
- package/test/machine-fs-runtime.test.mjs +4 -3
- package/test/process-longrun-r36.test.mjs +3 -2
- package/test/process-policy.test.mjs +10 -6
- package/test/process-runtime.test.mjs +9 -6
- package/test/r52-host-revocation.test.mjs +1 -0
- package/test/r59-tool-surface-compat.test.mjs +1 -1
- package/test/r64-release-contract.test.mjs +2 -1
- package/test/r65-activation-lock-recovery.test.mjs +72 -0
- package/test/r65-activation-lock.test.mjs +59 -0
- package/test/r65-activation-orchestration.test.mjs +179 -0
- package/test/r65-activation-preflight.test.mjs +35 -0
- package/test/r65-authority-continuity-decision.test.mjs +58 -0
- package/test/r65-authority-durable-policy-binding.test.mjs +34 -0
- package/test/r65-authority-epoch-cli.test.mjs +125 -0
- package/test/r65-authority-epoch-races.test.mjs +87 -0
- package/test/r65-authority-epoch-recovery.test.mjs +82 -0
- package/test/r65-authority-epoch-store.test.mjs +94 -0
- package/test/r65-authority-fixture.mjs +41 -0
- package/test/r65-authority-grant-capture.test.mjs +37 -0
- package/test/r65-authority-observation-epoch.test.mjs +25 -0
- package/test/r65-authority-policy-envelope.test.mjs +46 -0
- package/test/r65-authority-restored-safe.test.mjs +75 -0
- package/test/r65-authority-runtime-epoch.test.mjs +115 -0
- package/test/r65-authority-runtime-policy-binding.test.mjs +29 -0
- package/test/r65-authority-test-trust.mjs +20 -0
- package/test/r65-cli-invocation.test.mjs +38 -0
- package/test/r65-controller-authority-epoch-live.test.mjs +100 -0
- package/test/r65-controller-authority-epoch.test.mjs +37 -0
- package/test/r65-deploy-preflight.test.mjs +55 -0
- package/test/r65-epoch-native-activation-integration.test.mjs +141 -0
- package/test/r65-epoch-native-continuity-engine.test.mjs +112 -0
- package/test/r65-epoch-native-cross-plane.test.mjs +95 -0
- package/test/r65-legacy-authority-migration.test.mjs +63 -0
- package/test/r65-legacy-auto-restore-rejection.test.mjs +17 -0
- package/test/r65-npm-publication.test.mjs +114 -0
- package/test/r65-parent-source-verifier.test.mjs +63 -0
- package/test/r65-release-contract.test.mjs +74 -0
- package/test/r65-transaction-precondition.test.mjs +36 -0
- package/test/remote-session-cli.test.mjs +6 -6
- package/test/standing-grants.test.mjs +20 -4
|
@@ -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
|
+
}
|