deadbyte-mcp 0.13.0 → 0.14.0

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 (67) hide show
  1. package/.gitattributes +7 -0
  2. package/AGENTS.md +25 -0
  3. package/CONTEXT.md +3 -3
  4. package/MANIFEST.SHA256 +66 -40
  5. package/R42-PARENT.json +19 -0
  6. package/README.txt +2 -2
  7. package/bin/appcontainer-stage.obj +0 -0
  8. package/bin/bootstrap-advapi32.obj +0 -0
  9. package/bin/bootstrap-exitcode.obj +0 -0
  10. package/bin/bootstrap-kernel32.obj +0 -0
  11. package/bin/child-control-probe.obj +0 -0
  12. package/bin/child-control-stage.obj +0 -0
  13. package/bin/contained-reverse-worker.obj +0 -0
  14. package/bin/contained-transform-worker.obj +0 -0
  15. package/bin/containment-probe.obj +0 -0
  16. package/bin/deadbyte-contain.obj +0 -0
  17. package/bin/deadbyte-exec.obj +0 -0
  18. package/bin/deadbyte-process-host.obj +0 -0
  19. package/bin/deadbyte-tunnel-host.obj +0 -0
  20. package/controller/README.TXT +1 -1
  21. package/controller/deadbyte-controller.ps1 +1 -1
  22. package/controller/deadbyte-desktop-policy.json +5 -5
  23. package/controller/deadbyte-process-policy.json +4 -4
  24. package/docs/ARCHITECTURE.md +1 -1
  25. package/harness/r42-agent-evals.json +48 -0
  26. package/harness/task-contract.schema.json +33 -0
  27. package/package.json +9 -7
  28. package/proof/CONTAINMENT-BUILD.txt +6 -6
  29. package/scripts/agent-eval-r42.mjs +46 -0
  30. package/scripts/deferred-slot-operation-r42.mjs +126 -0
  31. package/scripts/final-closure-r42.mjs +116 -0
  32. package/scripts/final-closure-verify-r42.mjs +223 -0
  33. package/scripts/gate-windows-r42.ps1 +54 -0
  34. package/scripts/release-parity-r42.mjs +235 -0
  35. package/scripts/release-parity-tests-r42.ps1 +6 -0
  36. package/scripts/verify-r42-parent.mjs +101 -0
  37. package/scripts/windows-gate-evidence-r42.mjs +64 -0
  38. package/src/agent-eval-r42.mjs +73 -0
  39. package/src/agent-eval-runner-r42.mjs +138 -0
  40. package/src/agent-governance-r42.mjs +142 -0
  41. package/src/autonomous-context-engine.mjs +2 -0
  42. package/src/autonomous-loop-state.mjs +10 -0
  43. package/src/autonomous-mcp-tools.mjs +21 -6
  44. package/src/autonomous-output-contracts.mjs +18 -2
  45. package/src/autonomous-planner-contracts.mjs +3 -0
  46. package/src/autonomous-planner.mjs +46 -6
  47. package/src/autonomous-policy.mjs +10 -2
  48. package/src/autonomous-runtime.mjs +116 -16
  49. package/src/autonomous-supervisor.mjs +1 -1
  50. package/src/evidence-publisher-r42.mjs +76 -0
  51. package/src/mcp-server.mjs +1 -1
  52. package/src/provider-circuit.mjs +4 -4
  53. package/src/version.mjs +1 -1
  54. package/test/agent-eval-r42.test.mjs +39 -0
  55. package/test/agent-eval-runner-r42.test.mjs +61 -0
  56. package/test/agent-governance-r42.test.mjs +77 -0
  57. package/test/autonomous-r34-e2e.test.mjs +2 -1
  58. package/test/cli-entrypoint.test.mjs +1 -1
  59. package/test/core.test.mjs +1 -1
  60. package/test/evidence-publisher-r42.test.mjs +53 -0
  61. package/test/human-clarification-r42.test.mjs +53 -0
  62. package/test/provider-responses-r42.test.mjs +90 -0
  63. package/test/r33-closeout-regression.test.mjs +27 -12
  64. package/test/r33-finalization.test.mjs +3 -3
  65. package/test/r42-finalization.test.mjs +38 -0
  66. package/test/release-version.test.mjs +13 -13
  67. package/test/task-contract-r42.test.mjs +41 -0
@@ -0,0 +1,223 @@
1
+ import { createHash, createPublicKey, verify as cryptoVerify } from 'node:crypto';
2
+ import { lstat, readFile, readdir } from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { readAndVerifyR42EvalEvidence } from '../src/agent-eval-runner-r42.mjs';
7
+
8
+ const HEX64=/^[0-9a-f]{64}$/;
9
+ const UPDATE_DOMAIN=Buffer.from('DEADBYTE-R27-SLOT-UPDATE-V1\0','utf8');
10
+ const CLOSURE_DOMAIN=Buffer.from('DEADBYTE-R42-FINAL-CLOSURE-V1\0','utf8');
11
+ const PING_DOMAIN=Buffer.from('DEADBYTE-MACHINE-PING-V1\0','utf8');
12
+ const R42_PREDECESSOR_RELEASE_ID='v0.13.0-3255be10de4daf08';
13
+ const R42_PREDECESSOR_MANIFEST='3255be10de4daf0837d67d1ab1913b785b8b8215bc7405823c2ff46968c4b98f';
14
+ const R40_FULL_TOOL_COUNT=80;
15
+ const R40_COMPACT_TOOL_COUNT=42;
16
+ const REQUIRED_PARITY_KEYS=['tree_read','precondition_mutation','search','owned_process','observation','coding_loop','autonomy','interrupted_recovery','evidence_verification','compact_closure','full_surface','desktop_readonly','desktop_guarded_input','deterministic_memory','model_eval'];
17
+ const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
18
+ const canonical=value=>Array.isArray(value)?value.map(canonical):value&&typeof value==='object'
19
+ ?Object.fromEntries(Object.keys(value).sort().map(key=>[key,canonical(value[key])])):value;
20
+ const canonicalJson=value=>JSON.stringify(canonical(value));
21
+ const same=(a,b)=>canonicalJson(a)===canonicalJson(b);
22
+ function insist(ok,msg){if(!ok) throw new Error(msg);}
23
+ function samePath(a,b){return path.resolve(String(a)).toLowerCase()===path.resolve(String(b)).toLowerCase();}
24
+ function isCandidateIdentity(value,manifest){
25
+ return value?.version==='0.14.0'&&value?.manifest_sha256===manifest&&value?.release_id===`v0.14.0-${manifest.slice(0,16)}`;
26
+ }
27
+ function isR41PredecessorIdentity(value){
28
+ return value?.version==='0.13.0'&&value?.manifest_sha256===R42_PREDECESSOR_MANIFEST&&value?.release_id===R42_PREDECESSOR_RELEASE_ID;
29
+ }
30
+
31
+ function parseManifest(text){
32
+ const out=new Map();
33
+ for(const [i,line] of text.split(/\r?\n/).entries()){
34
+ if(!line) continue;
35
+ const m=/^([0-9a-f]{64}) ([^\0]+)$/.exec(line);insist(m,`manifest line ${i+1} malformed`);
36
+ insist(!path.posix.isAbsolute(m[2])&&!m[2].split('/').includes('..')&&!out.has(m[2]),`unsafe/duplicate manifest path ${m[2]}`);
37
+ out.set(m[2],m[1]);
38
+ }
39
+ return out;
40
+ }
41
+ async function walk(root,rel=''){
42
+ const dir=path.join(root,...(rel?rel.split('/'):[]));
43
+ const names=(await readdir(dir)).sort((a,b)=>a.localeCompare(b,'en'));
44
+ const files=[];
45
+ for(const name of names){
46
+ const childRel=rel?`${rel}/${name}`:name;
47
+ const full=path.join(root,...childRel.split('/'));
48
+ const st=await lstat(full);insist(!st.isSymbolicLink(),`symlink forbidden: ${childRel}`);
49
+ if(st.isDirectory()) files.push(...await walk(root,childRel));
50
+ else{insist(st.isFile(),`non-file forbidden: ${childRel}`);files.push(childRel);}
51
+ }
52
+ return files;
53
+ }
54
+ async function verifyTree(root,manifestName,expectedDigest){
55
+ const manifestBytes=await readFile(path.join(root,manifestName));
56
+ insist(sha256(manifestBytes)===expectedDigest,`${manifestName} digest mismatch`);
57
+ const entries=parseManifest(manifestBytes.toString('utf8'));
58
+ const actual=(await walk(root)).filter(rel=>rel!==manifestName).sort((a,b)=>a.localeCompare(b,'en'));
59
+ const expected=[...entries.keys()].sort((a,b)=>a.localeCompare(b,'en'));
60
+ insist(same(actual,expected),`${manifestName} exact tree mismatch`);
61
+ for(const [rel,digest] of entries) insist(sha256(await readFile(path.join(root,...rel.split('/'))))===digest,`${manifestName} file hash mismatch: ${rel}`);
62
+ return entries.size;
63
+ }
64
+ function publicKeyInfo(publicPem){
65
+ const key=createPublicKey(publicPem);insist(key.asymmetricKeyType==='ed25519','public key must be Ed25519');
66
+ const der=Buffer.from(key.export({type:'spki',format:'der'}));
67
+ return {key,key_id:sha256(der),spki_base64:der.toString('base64')};
68
+ }
69
+ function verifyUpdateEnvelope(env,keyInfo){
70
+ insist(env?.body&&env?.attestation,'update envelope malformed');
71
+ const bodyBytes=Buffer.from(canonicalJson(env.body),'utf8');
72
+ insist(sha256(bodyBytes)===env.body_sha256,'update body hash mismatch');
73
+ const {receipt_sha256,...unsigned}=env;
74
+ insist(sha256(Buffer.from(canonicalJson(unsigned),'utf8'))===receipt_sha256,'update receipt hash mismatch');
75
+ insist(env.attestation.algorithm==='ed25519'&&env.attestation.domain==='DEADBYTE-R27-SLOT-UPDATE-V1','update attestation contract mismatch');
76
+ insist(env.attestation.key_id===keyInfo.key_id,'update signer mismatch');
77
+ insist(cryptoVerify(null,Buffer.concat([UPDATE_DOMAIN,bodyBytes]),keyInfo.key,Buffer.from(env.attestation.signature_base64,'base64')),'update signature invalid');
78
+ return true;
79
+ }
80
+ function verifyPing(ping,status,pointer){
81
+ insist(ping?.status==='ok'&&ping.schema==='deadbyte.machine-ping.v1','machine ping malformed');
82
+ insist(status?.status==='ok'&&typeof status.public_key_spki_base64==='string','machine status malformed');
83
+ const der=Buffer.from(status.public_key_spki_base64,'base64');
84
+ insist(der.toString('base64')===status.public_key_spki_base64,'machine SPKI base64 non-canonical');
85
+ const machineKey=createPublicKey({key:der,format:'der',type:'spki'});insist(machineKey.asymmetricKeyType==='ed25519','machine key must be Ed25519');
86
+ const machineId=sha256(der);
87
+ insist(status.machine_id===machineId&&ping.machine_id===machineId&&ping.attestation?.key_id===machineId,'machine id/key mismatch');
88
+ insist(ping.release_id===pointer.release_id&&ping.release_manifest_sha256===pointer.manifest_sha256,'machine ping release binding mismatch');
89
+ insist(ping.generation_manifest_sha256===pointer.generation_manifest_sha256,'machine ping generation binding mismatch');
90
+ const {status:_s,attestation:_a,...body}=ping;
91
+ const bytes=Buffer.from(canonicalJson(body),'utf8');
92
+ insist(cryptoVerify(null,Buffer.concat([PING_DOMAIN,bytes]),machineKey,Buffer.from(ping.attestation.signature_base64,'base64')),'machine ping signature invalid');
93
+ }
94
+
95
+ export async function verifyFinalClosureObject(envelope,{stateRoot=path.join(os.homedir(),'.deadbyte-mcp')}={}){
96
+ insist(envelope?.body?.schema==='deadbyte.r42-final-closure.v1','closure schema mismatch');
97
+ insist(envelope.body.version==='0.14.0','closure version mismatch');
98
+ insist(envelope.body.release_label==='R42 AGENTIC GOVERNANCE BASELINE','closure release label mismatch');
99
+ const keyInfo=publicKeyInfo(await readFile(path.join(stateRoot,'trust','ed25519-public.pem')));
100
+ const bodyBytes=Buffer.from(canonicalJson(envelope.body),'utf8');
101
+ insist(sha256(bodyBytes)===envelope.body_sha256,'closure body hash mismatch');
102
+ const {closure_sha256,...unsigned}=envelope;
103
+ insist(sha256(Buffer.from(canonicalJson(unsigned),'utf8'))===closure_sha256,'closure envelope hash mismatch');
104
+ insist(envelope.attestation?.algorithm==='ed25519'&&envelope.attestation?.domain==='DEADBYTE-R42-FINAL-CLOSURE-V1','closure attestation contract mismatch');
105
+ insist(envelope.attestation.key_id===keyInfo.key_id,'closure signer mismatch');
106
+ insist(cryptoVerify(null,Buffer.concat([CLOSURE_DOMAIN,bodyBytes]),keyInfo.key,Buffer.from(envelope.attestation.signature_base64,'base64')),'closure signature invalid');
107
+
108
+ const pointer=JSON.parse(await readFile(path.join(stateRoot,'active-release.json'),'utf8'));
109
+ insist(same(pointer,envelope.body.active_pointer),'active pointer drift');
110
+ insist(pointer.version==='0.14.0','active pointer version mismatch');
111
+ insist(isCandidateIdentity(pointer,pointer.manifest_sha256),'release id/content address mismatch');
112
+ const releaseFiles=await verifyTree(pointer.release_root,'MANIFEST.SHA256',pointer.manifest_sha256);
113
+ const generationFiles=await verifyTree(pointer.generation_root,'GENERATION.SHA256',pointer.generation_manifest_sha256);
114
+ insist(sha256(await readFile(path.join(stateRoot,'bin','DEADBYTE-MCP.ps1')))===pointer.launcher_sha256,'launcher hash mismatch');
115
+
116
+ const predecessor=envelope.body.predecessor;
117
+ insist(isR41PredecessorIdentity(predecessor),'closure predecessor is not exact sealed R40 predecessor');
118
+ const immutable=envelope.body.immutable_slot;
119
+ insist(immutable?.protected===true,'closure immutable-slot protection missing');
120
+ insist(samePath(immutable.release_root,pointer.release_root),'closure immutable release_root mismatch');
121
+ insist(!samePath(immutable.development_root,immutable.release_root),'closure development_root aliases immutable release_root');
122
+
123
+ const surfaces=envelope.body.surfaces;
124
+ insist(surfaces?.local_full?.status==='passed'&&surfaces.local_full.tool_count===R40_FULL_TOOL_COUNT&&surfaces.local_full.strict_output_schemas===true,'closure local full 80-tool proof invalid');
125
+ insist(HEX64.test(surfaces.local_full.catalog_sha256??''),'closure local full catalog hash missing');
126
+ insist(surfaces?.public_compact?.status==='passed'&&surfaces.public_compact.tool_count===R40_COMPACT_TOOL_COUNT&&surfaces.public_compact.capability_closure===true,'closure public compact capability proof invalid');
127
+ insist(surfaces.public_compact.coding_armed===false&&surfaces.public_compact.autonomous_armed===false&&surfaces.public_compact.desktop_armed===false,'closure compact authority is not DISARMED');
128
+ insist(surfaces.public_compact.desktop_observation_receipt_verified===true&&surfaces.public_compact.desktop_grounding_receipt_verified===true,'closure Desktop read-only proof invalid');
129
+ insist(HEX64.test(surfaces.public_compact.catalog_sha256??'')&&HEX64.test(surfaces.public_compact.ledger_sha256??''),'closure compact catalog/ledger hash missing');
130
+
131
+ const evidence=envelope.body.evidence;
132
+ insist(evidence&&evidence.parity&&evidence.activation&&evidence.rollback&&evidence.restore&&evidence.windows_gate&&evidence.model_eval,'closure evidence set incomplete');
133
+ for(const [name,item] of Object.entries(evidence)){
134
+ insist(item?.path&&HEX64.test(item.sha256??''),`${name} evidence identity malformed`);
135
+ insist(sha256(await readFile(item.path))===item.sha256,`${name} evidence hash mismatch`);
136
+ }
137
+
138
+ const parity=JSON.parse(await readFile(evidence.parity.path,'utf8'));
139
+ insist(parity.schema==='deadbyte.r42-parity.v1'&&parity.status==='passed','R40 parity evidence invalid');
140
+ insist(parity.rdc_operation_count===0&&parity.execution_provider==='deadbyte_mcp','R40 parity execution provider mismatch');
141
+ insist(isCandidateIdentity(parity.candidate,pointer.manifest_sha256),'R40 parity candidate binding mismatch');
142
+ insist(isCandidateIdentity(parity.successor,pointer.manifest_sha256),'R40 parity successor binding mismatch');
143
+ insist(isR41PredecessorIdentity(parity.predecessor),'R40 parity predecessor binding mismatch');
144
+ insist(parity.local_full?.status==='passed'&&parity.local_full.tool_count===R40_FULL_TOOL_COUNT&&parity.local_full.strict_output_schemas===true,'R40 parity local full proof invalid');
145
+ insist(parity.local_full.catalog_sha256===surfaces.local_full.catalog_sha256,'R36 local full catalog drift between parity and closure');
146
+ insist(parity.public_compact?.status==='passed'&&parity.public_compact.tool_count===R40_COMPACT_TOOL_COUNT&&parity.public_compact.capability_closure===true&&parity.public_compact.gateway_count===6&&parity.public_compact.desktop_armed===false&&parity.public_compact.desktop_observation_receipt_verified===true&&parity.public_compact.desktop_grounding_receipt_verified===true,'R40 parity public compact/Desktop proof invalid');
147
+ insist(parity.desktop_guarded?.status==='passed'&&parity.desktop_guarded.native_injected===true&&parity.desktop_guarded.replay_performed===false&&parity.desktop_guarded.action_receipts_verified===3,'R40 parity guarded Desktop proof invalid');
148
+ insist(parity.deterministic_memory?.status==='passed'&&parity.deterministic_memory.goal_count>=1&&parity.deterministic_memory.snapshot_count>=1&&parity.deterministic_memory.index_count>=1,'R41 deterministic memory proof invalid');
149
+ insist(same(surfaces.deterministic_memory,parity.deterministic_memory),'R41 closure deterministic memory binding mismatch');
150
+ insist(parity.model_eval?.status==='passed'&&parity.model_eval.case_count>=1&&HEX64.test(parity.model_eval.evidence_sha256??''),'R42 model-backed eval proof invalid');
151
+ insist(same(surfaces.model_eval,parity.model_eval),'R42 closure model-eval binding mismatch');
152
+ insist(parity.successor_disarmed?.status==='passed'&&parity.successor_disarmed.tool_count===R40_COMPACT_TOOL_COUNT&&parity.successor_disarmed.capability_closure===true&&parity.successor_disarmed.coding_armed===false&&parity.successor_disarmed.autonomous_armed===false&&parity.successor_disarmed.desktop_armed===false,'R40 parity successor disarmed proof invalid');
153
+ insist(parity.successor_disarmed.catalog_sha256===surfaces.public_compact.catalog_sha256,'R36 compact catalog drift between restore and closure');
154
+ insist(parity.successor_disarmed.ledger_sha256===surfaces.public_compact.ledger_sha256,'R36 capability ledger drift between restore and closure');
155
+ insist(parity.immutable_slot?.protected===true,'R40 parity immutable-slot proof missing');
156
+ insist(samePath(parity.immutable_slot.release_root,pointer.release_root),'R40 parity immutable release_root mismatch');
157
+ insist(samePath(parity.immutable_slot.development_root,immutable.development_root),'R40 parity/closure development_root mismatch');
158
+ insist(!samePath(parity.immutable_slot.development_root,pointer.release_root),'R36 mutable development_root aliases immutable release slot');
159
+ for(const key of REQUIRED_PARITY_KEYS) insist(parity.requirements?.[key]===true,`R40 parity requirement missing ${key}`);
160
+ const verifiedModelEval=await readAndVerifyR42EvalEvidence(evidence.model_eval.path,{
161
+ subjectManifestSha256:pointer.manifest_sha256,suiteSha256:parity.model_eval.suite_sha256
162
+ });
163
+ insist(verifiedModelEval.evidence_sha256===parity.model_eval.evidence_sha256,'R42 model-eval evidence hash mismatch');
164
+ insist(verifiedModelEval.payload.case_count===parity.model_eval.case_count,'R42 model-eval case count mismatch');
165
+
166
+ const activation=JSON.parse(await readFile(evidence.activation.path,'utf8'));
167
+ const rollback=JSON.parse(await readFile(evidence.rollback.path,'utf8'));
168
+ const restore=JSON.parse(await readFile(evidence.restore.path,'utf8'));
169
+ verifyUpdateEnvelope(activation,keyInfo);verifyUpdateEnvelope(rollback,keyInfo);verifyUpdateEnvelope(restore,keyInfo);
170
+ insist(activation.body.schema==='deadbyte.r27-slot-update-receipt.v1'&&activation.body.rollback_performed===false,'R40 activation receipt invalid');
171
+ insist(activation.body.release_version==='0.14.0'&&activation.body.candidate_manifest_sha256===pointer.manifest_sha256,'R40 activation candidate identity invalid');
172
+ insist(isCandidateIdentity(activation.body.active_pointer,pointer.manifest_sha256),'R40 activation active pointer invalid');
173
+ insist(isR41PredecessorIdentity(activation.body.prior_pointer),'R41 activation predecessor is not exact R40 predecessor');
174
+ insist(samePath(activation.body.development_root,immutable.development_root),'R40 activation development_root mismatch');
175
+ insist(!samePath(activation.body.development_root,activation.body.active_pointer.release_root),'R40 activation development_root aliases release slot');
176
+ insist(activation.body.authority?.final?.desktop_armed===false,'R40 activation restored Desktop authority unexpectedly');
177
+
178
+ insist(rollback.body.schema==='deadbyte.r31-slot-rollback-receipt.v1'&&rollback.body.rollback_performed===true,'R40 rollback receipt invalid');
179
+ insist(isCandidateIdentity(rollback.body.from_pointer,pointer.manifest_sha256),'R40 rollback source is not exact candidate');
180
+ insist(isR41PredecessorIdentity(rollback.body.active_pointer),'R41 rollback target is not exact R40 predecessor');
181
+ insist(rollback.body.activation_receipt_sha256===activation.receipt_sha256,'R40 rollback not bound to activation receipt');
182
+
183
+ insist(restore.body.schema==='deadbyte.r27-slot-update-receipt.v1'&&restore.body.rollback_performed===false,'R40 restore receipt invalid');
184
+ insist(restore.body.release_version==='0.14.0'&&restore.body.candidate_manifest_sha256===pointer.manifest_sha256,'R40 restore candidate identity invalid');
185
+ insist(isR41PredecessorIdentity(restore.body.prior_pointer),'R41 restore predecessor is not exact R40 predecessor');
186
+ insist(isCandidateIdentity(restore.body.active_pointer,pointer.manifest_sha256)&&same(restore.body.active_pointer,pointer),'R40 restore/current pointer mismatch');
187
+ insist(samePath(restore.body.development_root,immutable.development_root),'R40 restore development_root mismatch');
188
+ insist(!samePath(restore.body.development_root,restore.body.active_pointer.release_root),'R40 restore development_root aliases release slot');
189
+ insist(restore.body.authority?.final?.desktop_armed===false,'R40 restore restored Desktop authority unexpectedly');
190
+
191
+ const windowsGate=JSON.parse(await readFile(evidence.windows_gate.path,'utf8'));
192
+ insist(windowsGate.schema==='deadbyte.r42-windows-gate.v1'&&windowsGate.status==='passed'&&windowsGate.exit_code===0,'R40 Windows gate evidence invalid');
193
+ insist(windowsGate.version==='0.14.0'&&windowsGate.manifest_sha256===pointer.manifest_sha256,'R40 Windows gate manifest/version binding mismatch');
194
+ insist(windowsGate.marker==='DEADBYTE V0.14.0 / R42 WINDOWS BATCH GATE: PASS','R40 Windows gate PASS marker mismatch');
195
+
196
+ const machine=envelope.body.machine;
197
+ insist(machine?.status?.release_id===pointer.release_id&&machine.status.release_manifest_sha256===pointer.manifest_sha256&&machine.status.generation_manifest_sha256===pointer.generation_manifest_sha256,'machine status binding mismatch');
198
+ verifyPing(machine.ping,machine.status,pointer);
199
+ insist(machine.ping.nonce===machine.nonce,'machine ping nonce binding mismatch');
200
+
201
+ const grantNames=['process-grant.json','coding-grant.json','autonomous-grant.json','desktop-grant.json','host-grant.json'];
202
+ insist(envelope.body.authority?.all_disarmed===true,'closure authority not disarmed');
203
+ for(const name of grantNames){
204
+ let exists=true;try{await lstat(path.join(stateRoot,'runtime',name));}catch(error){if(error?.code==='ENOENT') exists=false;else throw error;}
205
+ insist(!exists,`authority grant still present: ${name}`);
206
+ insist(envelope.body.authority.grants_absent?.[name]===true,`closure grant absence not recorded: ${name}`);
207
+ }
208
+ return {ok:true,status:'passed',release_id:pointer.release_id,manifest_sha256:pointer.manifest_sha256,
209
+ generation_manifest_sha256:pointer.generation_manifest_sha256,release_files:releaseFiles,generation_files:generationFiles,
210
+ machine_id:machine.status.machine_id,parity_sha256:evidence.parity.sha256,closure_sha256:envelope.closure_sha256,
211
+ model_eval_evidence_sha256:verifiedModelEval.evidence_sha256,
212
+ full_tool_count:R40_FULL_TOOL_COUNT,compact_tool_count:surfaces.public_compact.tool_count};
213
+ }
214
+
215
+ const invoked=process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url);
216
+ if(invoked){
217
+ const file=process.argv[2];
218
+ if(!file) throw new Error('usage: node scripts/final-closure-verify-r42.mjs <closure.json>');
219
+ try{
220
+ const envelope=JSON.parse(await readFile(path.resolve(file),'utf8'));
221
+ console.log(JSON.stringify(await verifyFinalClosureObject(envelope),null,2));
222
+ }catch(error){console.error(error instanceof Error?error.stack:String(error));process.exitCode=1;}
223
+ }
@@ -0,0 +1,54 @@
1
+ $ErrorActionPreference = 'Stop'
2
+ Set-StrictMode -Version 2.0
3
+
4
+ function Invoke-GateStep {
5
+ param(
6
+ [Parameter(Mandatory = $true)][string]$Name,
7
+ [Parameter(Mandatory = $true)][string[]]$NpmArgs
8
+ )
9
+ Write-Host "==== $Name ===="
10
+ & npm.cmd @NpmArgs
11
+ if ($LASTEXITCODE -ne 0) {
12
+ throw "DEADBYTE V0.14.0 / R42 gate failed at $Name with exit code $LASTEXITCODE"
13
+ }
14
+ }
15
+
16
+ Invoke-GateStep -Name 'r42-parent-verify' -NpmArgs @('run', 'r42:parent:verify')
17
+ Invoke-GateStep -Name 'containment-build' -NpmArgs @('run', 'containment:build')
18
+ Invoke-GateStep -Name 'process-policy-refresh' -NpmArgs @('run', 'process:policy:refresh')
19
+ Invoke-GateStep -Name 'desktop-policy-refresh' -NpmArgs @('run', 'desktop:policy:refresh')
20
+ Invoke-GateStep -Name 'release-manifest-write' -NpmArgs @('run', 'manifest:write')
21
+ Invoke-GateStep -Name 'release-manifest' -NpmArgs @('run', 'manifest:verify')
22
+
23
+ Write-Host '==== r42-focused ===='
24
+ & node.exe --test test\provider-responses-r42.test.mjs test\task-contract-r42.test.mjs test\human-clarification-r42.test.mjs test\agent-governance-r42.test.mjs test\evidence-publisher-r42.test.mjs test\agent-eval-r42.test.mjs test\agent-eval-runner-r42.test.mjs test\r42-finalization.test.mjs
25
+ if ($LASTEXITCODE -ne 0) { throw "DEADBYTE V0.14.0 / R42 gate failed at r42-focused with exit code $LASTEXITCODE" }
26
+
27
+ Write-Host '==== r41-memory-regression ===='
28
+ & node.exe --test test\memory-snapshot-r41.test.mjs test\memory-projections-r41.test.mjs test\memory-retrieval-r41.test.mjs test\memory-history-r41.test.mjs test\memory-autonomous-integration-r41.test.mjs
29
+ if ($LASTEXITCODE -ne 0) { throw "DEADBYTE V0.14.0 / R42 gate failed at r41-memory-regression with exit code $LASTEXITCODE" }
30
+
31
+ Invoke-GateStep -Name 'r42-model-backed-eval' -NpmArgs @('run', 'r42:eval')
32
+ Invoke-GateStep -Name 'tests' -NpmArgs @('test')
33
+ Invoke-GateStep -Name 'mcp-smoke' -NpmArgs @('run', 'mcp:smoke')
34
+ Invoke-GateStep -Name 'mcp-agent-smoke' -NpmArgs @('run', 'mcp:agent:smoke')
35
+ Invoke-GateStep -Name 'mcp-coding-smoke' -NpmArgs @('run', 'mcp:coding:smoke')
36
+ Invoke-GateStep -Name 'mcp-machine-fs-smoke' -NpmArgs @('run', 'mcp:machine-fs:smoke')
37
+ Invoke-GateStep -Name 'mcp-observation-smoke' -NpmArgs @('run', 'mcp:observation:smoke')
38
+ Invoke-GateStep -Name 'mcp-process-smoke' -NpmArgs @('run', 'mcp:process:smoke')
39
+ Invoke-GateStep -Name 'mcp-autonomous-smoke' -NpmArgs @('run', 'mcp:autonomous:smoke')
40
+ Invoke-GateStep -Name 'tunnel-stdio-compat-smoke' -NpmArgs @('run', 'mcp:tunnel-compat:smoke')
41
+ Invoke-GateStep -Name 'mcp-host-smoke' -NpmArgs @('run', 'mcp:host:smoke')
42
+ Invoke-GateStep -Name 'authority-smoke' -NpmArgs @('run', 'authority:smoke')
43
+ Invoke-GateStep -Name 'containment-smoke' -NpmArgs @('run', 'containment:smoke')
44
+ Invoke-GateStep -Name 'contained-smoke' -NpmArgs @('run', 'contained:smoke')
45
+ Invoke-GateStep -Name 'mcp-contained-smoke' -NpmArgs @('run', 'mcp:contained:smoke')
46
+ Invoke-GateStep -Name 'release-manifest-final' -NpmArgs @('run', 'manifest:verify')
47
+
48
+ Write-Host '==== windows-gate-evidence ===='
49
+ & node.exe (Join-Path $PSScriptRoot 'windows-gate-evidence-r42.mjs')
50
+ if ($LASTEXITCODE -ne 0) {
51
+ throw "DEADBYTE V0.14.0 / R42 gate failed at windows-gate-evidence with exit code $LASTEXITCODE"
52
+ }
53
+
54
+ Write-Host '==== DEADBYTE V0.14.0 / R42 WINDOWS BATCH GATE: PASS ===='
@@ -0,0 +1,235 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { mkdir, readFile, realpath, writeFile } from 'node:fs/promises';
3
+ import { loadPowerShellDataFile } from '../src/runtime-update.mjs';
4
+ import os from 'node:os';
5
+ import path from 'node:path';
6
+ import { spawn } from 'node:child_process';
7
+ import { fileURLToPath } from 'node:url';
8
+ import { probeR40FullSurface } from '../src/r40-full-surface-probe.mjs';
9
+ import { runR40CompactParity } from '../src/remote-mcp-r40-parity-client.mjs';
10
+ import { probeR40CompactDisarmed } from '../src/r40-compact-disarmed-probe.mjs';
11
+ import { probeR36CompactDisarmed } from '../src/r36-compact-disarmed-probe.mjs';
12
+ import { runR40DesktopGuardedSmoke } from '../src/remote-mcp-desktop-r40-smoke-client.mjs';
13
+ import { verifyR41Memory } from './verify-memory-r41.mjs';
14
+ import { canonicalJson } from '../src/canonical-json.mjs';
15
+ import { readAndVerifyR42EvalEvidence } from '../src/agent-eval-runner-r42.mjs';
16
+
17
+ const here=path.dirname(fileURLToPath(import.meta.url));
18
+ const root=path.resolve(here,'..');
19
+ const stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
20
+ const deferred=path.join(root,'scripts','deferred-slot-operation-r42.mjs');
21
+ const ps='C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe';
22
+ const launcher=path.join(stateRoot,'bin','DEADBYTE-MCP.ps1');
23
+ const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));
24
+ const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
25
+
26
+ export const R42_PREDECESSOR_RELEASE_ID='v0.13.0-3255be10de4daf08';
27
+ export const R42_PREDECESSOR_MANIFEST='3255be10de4daf0837d67d1ab1913b785b8b8215bc7405823c2ff46968c4b98f';
28
+
29
+ function assert(condition,message){if(!condition) throw new Error(message);}
30
+ function parseFrozenManifest(text){
31
+ const entries=[];const seen=new Set();
32
+ for(const [index,line] of text.split(/\r?\n/).entries()){
33
+ if(!line) continue;
34
+ const match=/^([0-9a-f]{64}) ([^\0]+)$/.exec(line);
35
+ assert(match,`frozen manifest line ${index+1} malformed`);
36
+ const rel=match[2];
37
+ assert(!path.posix.isAbsolute(rel)&&!rel.split('/').includes('..')&&!seen.has(rel),`unsafe/duplicate frozen manifest path: ${rel}`);
38
+ seen.add(rel);entries.push({sha256:match[1],path:rel});
39
+ }
40
+ return entries;
41
+ }
42
+ // Restore the mutable development stage from the immutable active release after live parity work may drift it.
43
+ export async function restoreFrozenStage({developmentRoot,releaseRoot,expectedManifestSha256}){
44
+ const dev=path.resolve(developmentRoot);const release=path.resolve(releaseRoot);
45
+ const manifestBytes=await readFile(path.join(release,'MANIFEST.SHA256'));
46
+ const manifestSha256=sha256(manifestBytes);
47
+ assert(manifestSha256===expectedManifestSha256,`immutable release manifest drift: ${manifestSha256}`);
48
+ const entries=parseFrozenManifest(manifestBytes.toString('utf8'));
49
+ for(const entry of entries){
50
+ const source=path.join(release,...entry.path.split('/'));const bytes=await readFile(source);
51
+ assert(sha256(bytes)===entry.sha256,`immutable release file drift: ${entry.path}`);
52
+ const destination=path.join(dev,...entry.path.split('/'));await mkdir(path.dirname(destination),{recursive:true});
53
+ await writeFile(destination,bytes);assert(sha256(await readFile(destination))===entry.sha256,`development restore verification failed: ${entry.path}`);
54
+ }
55
+ await writeFile(path.join(dev,'MANIFEST.SHA256'),manifestBytes);
56
+ assert(sha256(await readFile(path.join(dev,'MANIFEST.SHA256')))===expectedManifestSha256,'development manifest restore verification failed');
57
+ return {status:'restored',file_count:entries.length,manifest_sha256:manifestSha256};
58
+ }
59
+ function parseJsonOutput(text,label){
60
+ const trimmed=String(text).trim();const starts=[...trimmed.matchAll(/\{/g)].map(match=>match.index);
61
+ for(const start of starts){try{return JSON.parse(trimmed.slice(start));}catch{}}
62
+ throw new Error(`${label} did not emit JSON`);
63
+ }
64
+ function run(command,args,{timeoutMs=900000,env=process.env,cwd=root}={}){
65
+ return new Promise((resolve,reject)=>{
66
+ const child=spawn(command,args,{cwd,shell:false,windowsHide:true,env,stdio:['ignore','pipe','pipe']});
67
+ const out=[],err=[];const timer=setTimeout(()=>{child.kill();reject(new Error(`command timeout: ${path.basename(command)}`));},timeoutMs);
68
+ child.stdout.on('data',chunk=>out.push(Buffer.from(chunk)));child.stderr.on('data',chunk=>err.push(Buffer.from(chunk)));
69
+ child.on('error',error=>{clearTimeout(timer);reject(error);});child.on('exit',code=>{
70
+ clearTimeout(timer);const stdout=Buffer.concat(out).toString('utf8');const stderr=Buffer.concat(err).toString('utf8');
71
+ if(code!==0) reject(new Error(`command failed exit=${code}: ${stderr||stdout}`));else resolve({stdout,stderr,exitCode:code});
72
+ });
73
+ });
74
+ }
75
+ async function publicUrl(){
76
+ const value=(await readFile(path.join(stateRoot,'bridge','mcp-url.txt'),'utf8')).trim();const url=new URL(value);
77
+ if(url.protocol!=='https:') throw new Error('public MCP URL must be HTTPS');return value;
78
+ }
79
+ async function pointer(){return JSON.parse(await readFile(path.join(stateRoot,'active-release.json'),'utf8'));}
80
+ async function disarmAll(){
81
+ for(const command of ['disarmdesktop','disarmautonomous','disarmcoding','disarmprocess','disarmhost']){
82
+ await run(ps,['-NoLogo','-NoProfile','-ExecutionPolicy','Bypass','-File',launcher,command],{timeoutMs:60000});
83
+ }
84
+ }
85
+ async function waitDeferred(statePath,timeoutMs=180000){
86
+ const deadline=Date.now()+timeoutMs;
87
+ while(Date.now()<deadline){const state=JSON.parse(await readFile(statePath,'utf8'));if(state.state==='completed') return state;if(state.state==='failed') throw new Error(`deferred ${state.mode} failed: ${state.error}`);await sleep(500);}
88
+ throw new Error(`deferred operation timeout: ${statePath}`);
89
+ }
90
+ async function scheduleDeferred(mode,value,{bridgeRoot=null,bridgeScriptSha256=null}={}){
91
+ if((bridgeRoot===null)!==(bridgeScriptSha256===null)) throw new Error('deferred bridge override requires exact root + SHA pair');
92
+ const args=[deferred,mode,value];
93
+ if(bridgeRoot!==null) args.push('--bridge-root',bridgeRoot,'--bridge-script-sha256',bridgeScriptSha256);
94
+ const scheduled=parseJsonOutput((await run(process.execPath,args,{timeoutMs:30000})).stdout,`deferred ${mode}`);
95
+ assert(scheduled.status==='scheduled',`deferred ${mode} was not scheduled`);
96
+ assert(scheduled.execution_provider==='deadbyte_mcp'&&scheduled.rdc_operation_count===0,'deferred operation provider mismatch');
97
+ return {scheduled,completed:await waitDeferred(scheduled.state_path)};
98
+ }
99
+ async function verifyR42ModelEval(candidateManifest){
100
+ const suite=JSON.parse(await readFile(path.join(root,'harness','r42-agent-evals.json'),'utf8'));
101
+ const suiteSha256=sha256(Buffer.from(canonicalJson(suite),'utf8'));
102
+ const evidenceId=`r42-${candidateManifest.slice(0,16)}-${suiteSha256.slice(0,16)}`;
103
+ const file=path.join(stateRoot,'evidence','release','r42-agent-evals','agent_eval',`${evidenceId}.json`);
104
+ const verified=await readAndVerifyR42EvalEvidence(file,{subjectManifestSha256:candidateManifest,suiteSha256});
105
+ return {status:'passed',path:file,evidence_sha256:verified.evidence_sha256,payload_sha256:verified.payload_sha256,
106
+ suite_sha256:suiteSha256,case_count:verified.payload.case_count};
107
+ }
108
+
109
+ async function publicR40PredecessorDisarmed(url){
110
+ const result=await probeR36CompactDisarmed(url);
111
+ assert(result.status==='passed'&&result.tool_count<=42&&result.capability_closure===true,'R40 predecessor public compact catalog mismatch');
112
+ assert(result.release_id===R42_PREDECESSOR_RELEASE_ID&&result.release_manifest_sha256===R42_PREDECESSOR_MANIFEST,'R40 predecessor machine binding mismatch');
113
+ assert(result.coding_armed===false&&result.autonomous_armed===false,'R40 predecessor authority remained armed');
114
+ return result;
115
+ }
116
+ async function mutableCore(pointerValue){
117
+ const policy=JSON.parse(await readFile(path.join(pointerValue.generation_root,'coding-policy.json'),'utf8'));
118
+ const raw=policy?.roots?.core?.path??policy?.roots?.core?.real_path;
119
+ assert(typeof raw==='string'&&raw,'R40 generation missing coding core root');
120
+ const core=path.resolve(raw);const release=path.resolve(pointerValue.release_root);
121
+ assert(core.toLowerCase()!==release.toLowerCase(),'R40 coding core must not point at immutable active release slot');
122
+ return core;
123
+ }
124
+
125
+ export function validateParityEvidence(value){
126
+ assert(value?.schema==='deadbyte.r42-parity.v1','R40 parity schema mismatch');
127
+ assert(value.status==='passed','R40 parity status is not passed');
128
+ assert(value.rdc_operation_count===0&&value.execution_provider==='deadbyte_mcp','R40 parity used non-DEADBYTE execution');
129
+ assert(value.candidate?.version==='0.14.0'&&/^[0-9a-f]{64}$/.test(value.candidate?.manifest_sha256??''),'R40 candidate identity missing');
130
+ assert(value.local_full?.status==='passed'&&value.local_full?.tool_count===80&&value.local_full?.strict_output_schemas===true,'R40 local full 80-tool proof missing');
131
+ assert(value.public_compact?.status==='passed'&&value.public_compact?.tool_count===42&&value.public_compact?.capability_closure===true&&value.public_compact?.gateway_count===6&&value.public_compact?.desktop_armed===false&&value.public_compact?.desktop_observation_receipt_verified===true&&value.public_compact?.desktop_grounding_receipt_verified===true,'R40 public compact/Desktop closure missing');
132
+ assert(value.desktop_guarded?.status==='passed'&&value.desktop_guarded?.native_injected===true&&value.desktop_guarded?.replay_performed===false&&
133
+ Number.isInteger(value.desktop_guarded?.predispatch_retry_count)&&value.desktop_guarded.predispatch_retry_count>=0&&value.desktop_guarded.predispatch_retry_count<=2&&
134
+ value.desktop_guarded?.observation_receipts_verified===value.desktop_guarded.predispatch_retry_count+1&&value.desktop_guarded?.action_receipts_verified===3,
135
+ 'R40 guarded Desktop proof missing');
136
+ assert(value.autonomous?.status==='passed'&&value.autonomous?.signed_release_verified===true,'R40 autonomous live proof missing');
137
+ assert(value.deterministic_memory?.status==='passed'&&value.deterministic_memory?.goal_count>=1&&value.deterministic_memory?.snapshot_count>=1&&value.deterministic_memory?.index_count>=1,'R41 deterministic memory proof missing');
138
+ assert(value.model_eval?.status==='passed'&&value.model_eval?.case_count>=1&&/^[0-9a-f]{64}$/.test(value.model_eval?.evidence_sha256??''),'R42 model-backed eval proof missing');
139
+ assert(value.before_rollback_disarmed?.status==='passed'&&value.before_rollback_disarmed?.capability_closure===true&&value.before_rollback_disarmed?.coding_armed===false&&value.before_rollback_disarmed?.autonomous_armed===false&&value.before_rollback_disarmed?.desktop_armed===false,'R40 pre-rollback disarm proof missing');
140
+ assert(value.rollback?.state==='completed'&&value.restore?.state==='completed','R40 rollback/restore not completed');
141
+ assert(value.stage_restore?.status==='restored'&&value.stage_restore?.manifest_sha256===value.candidate.manifest_sha256,'R40 stage restore proof missing');
142
+ assert(value.predecessor?.release_id===R42_PREDECESSOR_RELEASE_ID&&value.predecessor?.manifest_sha256===R42_PREDECESSOR_MANIFEST&&value.predecessor?.version==='0.13.0','R40 exact predecessor identity mismatch');
143
+ assert(value.predecessor_disarmed?.status==='passed'&&value.predecessor_disarmed?.tool_count<=42&&value.predecessor_disarmed?.capability_closure===true,'R40 predecessor public proof missing');
144
+ assert(value.successor?.version==='0.14.0'&&value.successor?.manifest_sha256===value.candidate.manifest_sha256,'R40 exact successor restore identity mismatch');
145
+ assert(value.successor_disarmed?.status==='passed'&&value.successor_disarmed?.capability_closure===true&&value.successor_disarmed?.coding_armed===false&&value.successor_disarmed?.autonomous_armed===false&&value.successor_disarmed?.desktop_armed===false,'R40 successor disarmed proof missing');
146
+ assert(value.immutable_slot?.protected===true&&value.immutable_slot?.development_root!==value.immutable_slot?.release_root,'R40 immutable-slot separation missing');
147
+ for(const key of ['tree_read','precondition_mutation','search','owned_process','observation','coding_loop','autonomy','interrupted_recovery','evidence_verification','compact_closure','full_surface','desktop_readonly','desktop_guarded_input','deterministic_memory','model_eval']) assert(value.requirements?.[key]===true,`R41 parity requirement not proven: ${key}`);
148
+ return true;
149
+ }
150
+
151
+ export async function runReleaseParity(activationReceiptPath){
152
+ const active=await pointer();const candidateManifest=sha256(await readFile(path.join(root,'MANIFEST.SHA256')));
153
+ assert(active.version==='0.14.0','R41 parity requires active 0.14.0 candidate');
154
+ assert(active.manifest_sha256===candidateManifest,'active release is not canonical R40 candidate');
155
+ const activeConfig=await loadPowerShellDataFile(active.config_path);
156
+ const successorBridgeRootRaw=activeConfig?.Bridge?.WorkingDirectory;
157
+ const successorBridgeConfiguredSha=activeConfig?.Bridge?.ScriptSha256;
158
+ assert(typeof successorBridgeRootRaw==='string'&&path.isAbsolute(successorBridgeRootRaw),'R40 active bridge root missing');
159
+ assert(typeof successorBridgeConfiguredSha==='string'&&/^[0-9a-f]{64}$/.test(successorBridgeConfiguredSha),'R40 active bridge SHA missing');
160
+ const successorBridgeRoot=await realpath(path.resolve(successorBridgeRootRaw));
161
+ const successorBridgeActualSha=sha256(await readFile(path.join(successorBridgeRoot,'src','bridge.mjs')));
162
+ assert(successorBridgeActualSha===successorBridgeConfiguredSha,'R40 active bridge bytes do not match generation pin');
163
+ const successorBridge={root:successorBridgeRoot,sha256:successorBridgeActualSha};
164
+ const developmentRoot=await mutableCore(active);
165
+ const localFull=await probeR40FullSurface({packageRoot:active.release_root,generationRoot:active.generation_root,stateRoot});
166
+ const url=await publicUrl();
167
+ let publicCompact,autonomous,desktopGuarded;
168
+ try{
169
+ publicCompact=await runR40CompactParity(url);
170
+ autonomous=parseJsonOutput((await run(process.execPath,[path.join(root,'src','remote-mcp-autonomous-smoke-client.mjs'),url],{timeoutMs:900000})).stdout,'R40 autonomous compact parity');
171
+ assert(autonomous.status==='passed'&&autonomous.signed_release_verified===true,'R40 autonomous compact parity failed');
172
+ await run(ps,['-NoLogo','-NoProfile','-ExecutionPolicy','Bypass','-File',launcher,'armdesktop'],{timeoutMs:60000});
173
+ try{desktopGuarded=await runR40DesktopGuardedSmoke(url);}
174
+ finally{await run(ps,['-NoLogo','-NoProfile','-ExecutionPolicy','Bypass','-File',launcher,'disarmdesktop'],{timeoutMs:60000}).catch(()=>{});}
175
+ assert(desktopGuarded.status==='passed'&&desktopGuarded.native_injected===true&&desktopGuarded.action_receipts_verified===3,'R40 guarded Desktop public smoke failed');
176
+ }catch(error){await disarmAll().catch(()=>{});throw error;}
177
+ const deterministicMemory=await verifyR41Memory({memoryRoot:path.join(stateRoot,'evidence','autonomous','memory-r41',candidateManifest),
178
+ journalRoot:path.join(stateRoot,'evidence','autonomous','goals'),sourceReleaseManifest:candidateManifest,
179
+ publicKeyPath:path.join(stateRoot,'trust','ed25519-public.pem')});
180
+ assert(deterministicMemory.goal_count>=1&&deterministicMemory.snapshot_count>=1&&deterministicMemory.index_count>=1,'R41 live deterministic memory evidence missing');
181
+ const modelEval=await verifyR42ModelEval(candidateManifest);
182
+ assert(modelEval.status==='passed'&&modelEval.case_count>=1,'R42 model-backed eval evidence missing');
183
+
184
+ await disarmAll();
185
+ const beforeRollback=await probeR40CompactDisarmed(url);
186
+ const rollbackPair=await scheduleDeferred('rollback',path.resolve(activationReceiptPath));
187
+ const predecessor=await pointer();
188
+ assert(predecessor.release_id===R42_PREDECESSOR_RELEASE_ID&&predecessor.manifest_sha256===R42_PREDECESSOR_MANIFEST&&predecessor.version==='0.13.0','rollback did not reach exact sealed R40 predecessor');
189
+ const predecessorDisarmed=await publicR40PredecessorDisarmed(url);
190
+ const stageRestore=await restoreFrozenStage({developmentRoot,releaseRoot:active.release_root,expectedManifestSha256:candidateManifest});
191
+ const restorePair=await scheduleDeferred('activate',candidateManifest,{bridgeRoot:successorBridge.root,bridgeScriptSha256:successorBridge.sha256});
192
+ const successor=await pointer();
193
+ assert(successor.version==='0.14.0'&&successor.manifest_sha256===candidateManifest,'restore did not return exact R40 candidate');
194
+ const successorDisarmed=await probeR40CompactDisarmed(url);
195
+ await disarmAll();
196
+
197
+ const evidence={
198
+ schema:'deadbyte.r42-parity.v1',status:'passed',completed_at_utc:new Date().toISOString(),execution_provider:'deadbyte_mcp',rdc_operation_count:0,
199
+ candidate:{release_id:active.release_id,version:active.version,manifest_sha256:candidateManifest},
200
+ immutable_slot:{protected:true,release_root:path.resolve(active.release_root),development_root:developmentRoot},
201
+ local_full:localFull,public_compact:publicCompact,autonomous,deterministic_memory:deterministicMemory,model_eval:modelEval,desktop_guarded:desktopGuarded,before_rollback_disarmed:beforeRollback,
202
+ rollback:{...rollbackPair.completed,scheduled_operation_id:rollbackPair.scheduled.operation_id},
203
+ predecessor:{release_id:predecessor.release_id,version:predecessor.version,manifest_sha256:predecessor.manifest_sha256},predecessor_disarmed:predecessorDisarmed,
204
+ stage_restore:stageRestore,
205
+ restore:{...restorePair.completed,scheduled_operation_id:restorePair.scheduled.operation_id},
206
+ successor:{release_id:successor.release_id,version:successor.version,manifest_sha256:successor.manifest_sha256},successor_disarmed:successorDisarmed,
207
+ requirements:{
208
+ tree_read:publicCompact.tree_entries>=0&&publicCompact.coding_stat_verified===true,
209
+ precondition_mutation:publicCompact.machine_fs_receipts_verified>=3,
210
+ search:publicCompact.coding_search_result_count>=1&&publicCompact.observation_search_result_count>=1,
211
+ owned_process:typeof publicCompact.process_session_id==='string'&&publicCompact.process_output_bytes>0,
212
+ observation:publicCompact.observation_receipts_verified>=2,
213
+ coding_loop:publicCompact.coding_receipts_verified===2,
214
+ autonomy:autonomous.signed_release_verified===true&&autonomous.observed_failure_before_replan===true,
215
+ interrupted_recovery:rollbackPair.completed.state==='completed'&&restorePair.completed.state==='completed',
216
+ evidence_verification:publicCompact.machine_fs_receipts_verified>=3&&autonomous.signed_release_verified===true,
217
+ compact_closure:publicCompact.capability_closure===true&&successorDisarmed.capability_closure===true,
218
+ full_surface:localFull.tool_count===80&&localFull.strict_output_schemas===true,
219
+ desktop_readonly:publicCompact.desktop_armed===false&&publicCompact.desktop_observation_receipt_verified===true&&publicCompact.desktop_grounding_receipt_verified===true,
220
+ desktop_guarded_input:desktopGuarded.native_injected===true&&desktopGuarded.replay_performed===false&&desktopGuarded.action_receipts_verified===3,
221
+ deterministic_memory:deterministicMemory.status==='passed'&&deterministicMemory.goal_count>=1&&deterministicMemory.snapshot_count>=1,
222
+ model_eval:modelEval.status==='passed'&&modelEval.case_count>=1
223
+ }
224
+ };
225
+ validateParityEvidence(evidence);
226
+ const evidenceDir=path.join(stateRoot,'evidence','release');await mkdir(evidenceDir,{recursive:true});
227
+ const evidencePath=path.join(evidenceDir,`r42-parity-${candidateManifest.slice(0,16)}.json`);
228
+ const bytes=Buffer.from(`${JSON.stringify(evidence,null,2)}\n`,'utf8');await writeFile(evidencePath,bytes);
229
+ return {evidence,evidence_path:evidencePath,evidence_sha256:sha256(bytes)};
230
+ }
231
+
232
+ if(process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url)){
233
+ const receipt=process.argv[2];if(!receipt) throw new Error('usage: node scripts/release-parity-r42.mjs <activation-receipt.json>');
234
+ runReleaseParity(receipt).then(result=>console.log(JSON.stringify({status:'passed',...result},null,2))).catch(error=>{console.error(error instanceof Error?error.stack:String(error));process.exitCode=1;});
235
+ }
@@ -0,0 +1,6 @@
1
+ $ErrorActionPreference='Stop'
2
+ Set-StrictMode -Version 2.0
3
+ & node.exe --test test\provider-responses-r42.test.mjs test\task-contract-r42.test.mjs test\human-clarification-r42.test.mjs test\agent-governance-r42.test.mjs test\evidence-publisher-r42.test.mjs test\agent-eval-r42.test.mjs test\agent-eval-runner-r42.test.mjs test\r42-finalization.test.mjs
4
+ if($LASTEXITCODE -ne 0){exit $LASTEXITCODE}
5
+ & node.exe --test test\memory-snapshot-r41.test.mjs test\memory-projections-r41.test.mjs test\memory-retrieval-r41.test.mjs test\memory-history-r41.test.mjs test\memory-autonomous-integration-r41.test.mjs
6
+ exit $LASTEXITCODE