deadbyte-mcp 0.12.0 → 0.13.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 (55) hide show
  1. package/MANIFEST.SHA256 +54 -36
  2. package/R41-PARENT.json +15 -0
  3. package/README.txt +2 -2
  4. package/bin/appcontainer-stage.obj +0 -0
  5. package/bin/bootstrap-advapi32.obj +0 -0
  6. package/bin/bootstrap-exitcode.obj +0 -0
  7. package/bin/bootstrap-kernel32.obj +0 -0
  8. package/bin/child-control-probe.obj +0 -0
  9. package/bin/child-control-stage.obj +0 -0
  10. package/bin/contained-reverse-worker.obj +0 -0
  11. package/bin/contained-transform-worker.obj +0 -0
  12. package/bin/containment-probe.obj +0 -0
  13. package/bin/deadbyte-contain.obj +0 -0
  14. package/bin/deadbyte-exec.obj +0 -0
  15. package/bin/deadbyte-process-host.obj +0 -0
  16. package/bin/deadbyte-tunnel-host.obj +0 -0
  17. package/controller/README.TXT +1 -1
  18. package/controller/deadbyte-controller.ps1 +1 -1
  19. package/controller/deadbyte-desktop-policy.json +5 -5
  20. package/controller/deadbyte-process-policy.json +4 -4
  21. package/docs/ARCHITECTURE.md +1 -1
  22. package/docs/superpowers/specs/2026-09-20-r41-deterministic-memory-design.md +132 -0
  23. package/package.json +8 -6
  24. package/proof/CONTAINMENT-BUILD.txt +6 -6
  25. package/scripts/build-containment.ps1 +24 -14
  26. package/scripts/build-desktop-r40.ps1 +15 -9
  27. package/scripts/deferred-slot-operation-r41.mjs +127 -0
  28. package/scripts/final-closure-r41.mjs +116 -0
  29. package/scripts/final-closure-verify-r41.mjs +215 -0
  30. package/scripts/gate-windows-r41.ps1 +48 -0
  31. package/scripts/init-desktop-policy-r40.ps1 +10 -4
  32. package/scripts/release-parity-r41.mjs +221 -0
  33. package/scripts/release-parity-tests-r41.ps1 +9 -0
  34. package/scripts/verify-memory-r41.mjs +88 -0
  35. package/scripts/verify-r41-parent.mjs +61 -0
  36. package/scripts/windows-gate-evidence-r41.mjs +53 -0
  37. package/src/autonomous-context-engine.mjs +2 -1
  38. package/src/autonomous-planner.mjs +2 -0
  39. package/src/autonomous-runtime.mjs +28 -9
  40. package/src/mcp-server.mjs +14 -1
  41. package/src/memory-r41.mjs +692 -0
  42. package/src/version.mjs +1 -1
  43. package/test/cli-entrypoint.test.mjs +1 -1
  44. package/test/controller-desktop-r40.test.mjs +2 -1
  45. package/test/core.test.mjs +1 -1
  46. package/test/helpers/autonomous-r34-fixture.mjs +3 -3
  47. package/test/memory-autonomous-integration-r41.test.mjs +31 -0
  48. package/test/memory-history-r41.test.mjs +126 -0
  49. package/test/memory-projections-r41.test.mjs +92 -0
  50. package/test/memory-retrieval-r41.test.mjs +124 -0
  51. package/test/memory-snapshot-r41.test.mjs +106 -0
  52. package/test/r33-closeout-regression.test.mjs +7 -7
  53. package/test/r33-finalization.test.mjs +4 -4
  54. package/test/r41-finalization.test.mjs +38 -0
  55. package/test/release-version.test.mjs +14 -13
package/src/version.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export const DEADBYTE_VERSION = '0.12.0';
1
+ export const DEADBYTE_VERSION = '0.13.0';
2
2
  export const MCP_PROTOCOL_VERSION = '2026-07-28';
3
3
  export const RECEIPT_SCHEMA_V1 = 'deadbyte.receipt.v1';
4
4
  export const RECEIPT_SCHEMA_V2 = 'deadbyte.receipt.v2';
@@ -21,7 +21,7 @@ test('npx CLI reports the canonical package version through --version, -v and ve
21
21
  for(const arg of ['--version','-v','version']){
22
22
  const result=spawnSync(process.execPath,[cliPath,arg],{cwd:root,encoding:'utf8',windowsHide:true});
23
23
  assert.equal(result.status,0,result.stderr);
24
- assert.equal(result.stdout.trim(),'0.12.0');
24
+ assert.equal(result.stdout.trim(),'0.13.0');
25
25
  }
26
26
  });
27
27
 
@@ -70,7 +70,8 @@ test('R40 policy initializer pins current native observer and input and starts D
70
70
  assert.match(source,/deadbyte-desktop-observer-r40\.exe/);
71
71
  assert.match(source,/deadbyte-desktop-input-r40\.exe/);
72
72
  assert.match(source,/deadbyte-desktop-uia-r40\.exe/);
73
- assert.match(source,/Get-FileHash/);
73
+ assert.match(source,/System\.Security\.Cryptography\.SHA256/);
74
+ assert.match(source,/Get-Sha256Hex -Path \$Observer/);
74
75
  assert.match(source,/Remove-Item -LiteralPath \$Grant/);
75
76
  assert.match(source,/grant_state='DISARMED'/);
76
77
  assert.match(source,/deadbyte\.desktop-policy\.v1/);
@@ -105,7 +105,7 @@ test('proof execution creates deterministic output and signed verifiable receipt
105
105
  assert.equal(result.receipt.request.schema, 'deadbyte.request.v1');
106
106
  assert.match(result.receipt.request.nonce, /^[0-9a-f]{64}$/);
107
107
  assert.match(result.receipt.request.sha256, /^[0-9a-f]{64}$/);
108
- assert.equal(result.receipt.runtime.package_version, '0.12.0');
108
+ assert.equal(result.receipt.runtime.package_version, '0.13.0');
109
109
  assert.match(result.receipt.runtime.mcp_ingress_adapter, /^(?:none|tunnel-stdio-probe-compat-v1)$/);
110
110
  assert.match(result.receipt.runtime.mcp_ingress_adapter_sha256, /^[0-9a-f]{64}$/);
111
111
  assert.match(result.receipt.runtime.mcp_ingress_mode_source_sha256, /^[0-9a-f]{64}$/);
@@ -12,7 +12,7 @@ import { createAutonomousRuntime } from '../../src/autonomous-runtime.mjs';
12
12
  const sha = bytes => createHash('sha256').update(bytes).digest('hex');
13
13
  const nonce = () => randomBytes(32).toString('hex');
14
14
 
15
- export async function createR34Fixture({authority='armed',withFailingProfile=false,withStatefulProfile=false,codingRuntimeFactory=null,nativeDiffRuntimeFactory=null,desktopMemoryProvider=null,desktopRuntime=null}={}) {
15
+ export async function createR34Fixture({authority='armed',withFailingProfile=false,withStatefulProfile=false,codingRuntimeFactory=null,nativeDiffRuntimeFactory=null,desktopMemoryProvider=null,memoryProvider=null,desktopRuntime=null}={}) {
16
16
  const root = await mkdtemp(path.join(os.tmpdir(),'deadbyte-r34-e2e-'));
17
17
  const project = path.join(root,'project');
18
18
  const trust = path.join(root,'trust');
@@ -73,8 +73,8 @@ export async function createR34Fixture({authority='armed',withFailingProfile=fal
73
73
  const machineFsRuntime = createMachineFsRuntime({policy:codingPolicy,signingKeyPath:keys.privateKeyPath,verifyKeyPath:keys.publicKeyPath});
74
74
  const baseNativeDiffRuntime = createNativeDiffRuntime({policy,codingRuntime,machineFsRuntime,signingKeyPath:keys.privateKeyPath,verifyKeyPath:keys.publicKeyPath});
75
75
  const nativeDiffRuntime = nativeDiffRuntimeFactory ? nativeDiffRuntimeFactory(baseNativeDiffRuntime) : baseNativeDiffRuntime;
76
- const createRuntime = ({codingRuntimeOverride=codingRuntime,nativeDiffRuntimeOverride=nativeDiffRuntime,desktopMemoryProviderOverride=desktopMemoryProvider,desktopRuntimeOverride=desktopRuntime}={}) => createAutonomousRuntime({policy,codingRuntime:codingRuntimeOverride,nativeDiffRuntime:nativeDiffRuntimeOverride,machineFsRuntime,
77
- desktopRuntime:desktopRuntimeOverride,desktopMemoryProvider:desktopMemoryProviderOverride,signingKeyPath:keys.privateKeyPath,verifyKeyPath:keys.publicKeyPath});
76
+ const createRuntime = ({codingRuntimeOverride=codingRuntime,nativeDiffRuntimeOverride=nativeDiffRuntime,desktopMemoryProviderOverride=desktopMemoryProvider,memoryProviderOverride=memoryProvider,desktopRuntimeOverride=desktopRuntime}={}) => createAutonomousRuntime({policy,codingRuntime:codingRuntimeOverride,nativeDiffRuntime:nativeDiffRuntimeOverride,machineFsRuntime,
77
+ desktopRuntime:desktopRuntimeOverride,desktopMemoryProvider:desktopMemoryProviderOverride,memoryProvider:memoryProviderOverride,signingKeyPath:keys.privateKeyPath,verifyKeyPath:keys.publicKeyPath});
78
78
  return {
79
79
  root,project,target,keys,codingPolicy,policy,baseCodingRuntime,codingRuntime,machineFsRuntime,nativeDiffRuntime,createRuntime,runtime:createRuntime(),
80
80
  initial_sha256:sha(await readFile(target)),arm,disarm,
@@ -0,0 +1,31 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import path from 'node:path';
4
+ import { createHash } from 'node:crypto';
5
+ import { createR34Fixture } from './helpers/autonomous-r34-fixture.mjs';
6
+ import { loadPrivateSigningKey,loadPublicVerifyKey } from '../src/trust.mjs';
7
+ import { createR41MemoryProvider } from '../src/memory-r41.mjs';
8
+
9
+ const sha=value=>createHash('sha256').update(String(value)).digest('hex');
10
+
11
+ test('R41 planner request binds verified bounded memory before a mutating decision',async()=>{
12
+ const f=await createR34Fixture();
13
+ try{
14
+ const signing=await loadPrivateSigningKey(f.keys.privateKeyPath);
15
+ const verify=await loadPublicVerifyKey(f.keys.publicKeyPath);
16
+ const provider=createR41MemoryProvider({memoryRoot:path.join(f.root,'memory'),sourceReleaseManifest:sha('r41-release'),
17
+ writerVersion:'0.13.0',privateKey:signing.privateKey,publicKey:verify.publicKey,keyId:signing.keyId,byteBudget:65536});
18
+ const runtime=f.createRuntime({memoryProviderOverride:provider});
19
+ const goal=await runtime.submit({submissionId:'r41-memory-binding',rootId:'project',title:'repair',goal:'repair x.txt',acceptance:'x is y'});
20
+ const run=await runtime.run({goalId:goal.goal_id,maxCycles:1});
21
+ assert.equal(run.status,'input_required');
22
+ assert.match(run.planner_request.prompt,/"long_term_memory"/);
23
+ assert.match(run.planner_request.prompt,/"working_memory_sha256":"[0-9a-f]{64}"/);
24
+ const journal=await runtime.events({goalId:goal.goal_id,fromSeq:1,limit:100});
25
+ const requested=journal.events.find(event=>event.type==='planner_requested');
26
+ assert.match(requested.payload.working_memory_sha256,/^[0-9a-f]{64}$/);
27
+ assert.match(requested.payload.memory_snapshot_sha256,/^[0-9a-f]{64}$/);
28
+ assert.match(requested.payload.memory_index_sha256,/^[0-9a-f]{64}$/);
29
+ assert.equal(requested.payload.memory_source_release_manifest,sha('r41-release'));
30
+ }finally{await f.cleanup();}
31
+ });
@@ -0,0 +1,126 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { createHash,generateKeyPairSync,sign as cryptoSign } from 'node:crypto';
4
+ import { mkdir,mkdtemp,rm,writeFile } from 'node:fs/promises';
5
+ import os from 'node:os';
6
+ import path from 'node:path';
7
+ import { canonicalJson } from '../src/canonical-json.mjs';
8
+ import { createR41MemoryProvider } from '../src/memory-r41.mjs';
9
+ import { verifyR41Memory } from '../scripts/verify-memory-r41.mjs';
10
+
11
+ const EVENT_DOMAIN=Buffer.from('DEADBYTE-AUTONOMOUS-EVENT-V1\0');
12
+ const GOAL_DOMAIN=Buffer.from('DEADBYTE-AUTONOMOUS-GOAL-V1\0');
13
+ const ZERO='0'.repeat(64);
14
+ const sha=value=>createHash('sha256').update(Buffer.from(typeof value==='string'?value:canonicalJson(value),'utf8')).digest('hex');
15
+ const {privateKey,publicKey}=generateKeyPairSync('ed25519');
16
+ const keyId=createHash('sha256').update(Buffer.from(publicKey.export({type:'spki',format:'der'}))).digest('hex');
17
+ const manifest=sha('r41-history-release');
18
+
19
+ function eventJournal(goalId,items){
20
+ const events=[];
21
+ for(const [index,[type,payload]] of items.entries()){
22
+ const body={schema:'deadbyte.autonomous-event.v1',seq:index+1,goal_id:goalId,
23
+ created_at_utc:`2026-09-20T08:00:${String(index).padStart(2,'0')}.000Z`,prev_sha256:events.at(-1)?.event_sha256??ZERO,type,payload};
24
+ const event_sha256=sha(body);const signed={...body,event_sha256};
25
+ events.push({...signed,attestation:{algorithm:'ed25519',key_id:keyId,
26
+ signature_base64:cryptoSign(null,Buffer.concat([EVENT_DOMAIN,Buffer.from(canonicalJson(signed),'utf8')]),privateKey).toString('base64')}});
27
+ }
28
+ return events;
29
+ }
30
+ function signedGoal(goalId,title){
31
+ const identity={schema:'deadbyte.autonomous-goal.v1',policy_sha256:sha('policy'),root_id:'core',submission_id:title,
32
+ title,goal:`repair ${title}`,acceptance:'tests pass',max_iterations:8};
33
+ const body={...identity,goal_sha256:sha(identity),goal_id:goalId};
34
+ return {...body,attestation:{algorithm:'ed25519',key_id:keyId,
35
+ signature_base64:cryptoSign(null,Buffer.concat([GOAL_DOMAIN,Buffer.from(canonicalJson(body),'utf8')]),privateKey).toString('base64')}};
36
+ }
37
+ async function writeHistory(root,goal,events){
38
+ const dir=path.join(root,goal.goal_id);await mkdir(path.join(dir,'events'),{recursive:true});
39
+ await writeFile(path.join(dir,'goal.json'),`${canonicalJson(goal)}\n`);
40
+ for(const event of events)await writeFile(path.join(dir,'events',`${String(event.seq).padStart(6,'0')}.json`),`${canonicalJson(event)}\n`);
41
+ }
42
+
43
+ test('R41 provider retrieves verified prior-goal memory and excludes cross-release journals',async()=>{
44
+ const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r41-history-'));
45
+ try{
46
+ const journalRoot=path.join(root,'goals');const memoryRoot=path.join(root,'memory');
47
+ const priorId=sha('prior-goal');const priorGoal=signedGoal(priorId,'ParserSymbol timeout');
48
+ const priorEvents=eventJournal(priorId,[
49
+ ['goal_created',{source_release_manifest:manifest}],
50
+ ['profile_completed',{profile_id:'test',passed:false,diagnostic_codes:['ERR_PARSER_TIMEOUT'],symbols:['ParserSymbol']}]
51
+ ]);
52
+ await writeHistory(journalRoot,priorGoal,priorEvents);
53
+ const foreignId=sha('foreign-goal');const foreignGoal=signedGoal(foreignId,'ParserSymbol foreign');
54
+ await writeHistory(journalRoot,foreignGoal,eventJournal(foreignId,[['goal_created',{source_release_manifest:sha('other-release')}]]));
55
+ const currentId=sha('current-goal');const signedCurrent=signedGoal(currentId,'ParserSymbol regression');
56
+ await writeHistory(journalRoot,signedCurrent,eventJournal(currentId,[['goal_created',{source_release_manifest:manifest}]]));
57
+ const currentGoal={...signedCurrent};delete currentGoal.attestation;
58
+ const currentEvents=eventJournal(currentId,[['goal_created',{source_release_manifest:manifest}]]);
59
+ const provider=createR41MemoryProvider({memoryRoot,journalRoot,sourceReleaseManifest:manifest,privateKey,publicKey,keyId,byteBudget:32768});
60
+ const result=await provider.refresh({goal:currentGoal,events:currentEvents,currentSymbols:['ParserSymbol']});
61
+ assert.equal(result.historical_goal_count,1);
62
+ assert.ok(result.planner_context.historical_memory.length>=1);
63
+ assert.equal(result.planner_context.historical_memory.some(item=>item.goal?.goal_id===foreignId||item.goal_id===foreignId),false);
64
+ assert.equal(result.planner_context.historical_archive_sha256,result.historical_archive_sha256);
65
+ const grownPriorEvents=eventJournal(priorId,[
66
+ ['goal_created',{source_release_manifest:manifest}],
67
+ ['profile_completed',{profile_id:'test',passed:false,diagnostic_codes:['ERR_PARSER_TIMEOUT'],symbols:['ParserSymbol']}],
68
+ ['planner_decision',{decision:{summary:'retry parser',action:'run_profile'}}],
69
+ ['profile_completed',{profile_id:'test',passed:true,symbols:['ParserSymbol']}],
70
+ ['release_completed',{receipt_sha256:sha('prior-release-grown')}]
71
+ ]);
72
+ await rm(path.join(journalRoot,priorId),{recursive:true,force:true});
73
+ await writeHistory(journalRoot,priorGoal,grownPriorEvents);
74
+ const refreshed=await provider.refresh({goal:currentGoal,events:currentEvents,currentSymbols:['ParserSymbol']});
75
+ assert.notEqual(refreshed.historical_archive_sha256,result.historical_archive_sha256);
76
+ const publicKeyPath=path.join(root,'public.pem');await writeFile(publicKeyPath,publicKey.export({type:'spki',format:'pem'}));
77
+ const verified=await verifyR41Memory({memoryRoot,journalRoot,sourceReleaseManifest:manifest,publicKeyPath});
78
+ assert.equal(verified.status,'passed');assert.equal(verified.goal_count,1);assert.equal(verified.archive_count,2);
79
+ }finally{await rm(root,{recursive:true,force:true});}
80
+ });
81
+
82
+ test('R41 provider fails closed on a poisoned same-release historical chain',async()=>{
83
+ const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r41-history-poison-'));
84
+ try{
85
+ const journalRoot=path.join(root,'goals');const goalId=sha('poisoned-goal');const historical=signedGoal(goalId,'poisoned');
86
+ const events=eventJournal(goalId,[['goal_created',{source_release_manifest:manifest}],['release_completed',{}]]);
87
+ events[1].prev_sha256=sha('forged');
88
+ await writeHistory(journalRoot,historical,events);
89
+ const currentId=sha('current-poison-check');const current={...signedGoal(currentId,'current')};delete current.attestation;
90
+ const provider=createR41MemoryProvider({memoryRoot:path.join(root,'memory'),journalRoot,sourceReleaseManifest:manifest,privateKey,publicKey,keyId});
91
+ await assert.rejects(provider.refresh({goal:current,events:eventJournal(currentId,[['goal_created',{source_release_manifest:manifest}]])}),/predecessor mismatch|hash mismatch/);
92
+ }finally{await rm(root,{recursive:true,force:true});}
93
+ });
94
+
95
+
96
+ test('R41 verifier accepts content-addressed indexes from earlier verified snapshot prefixes',async()=>{
97
+ const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r41-history-prefix-index-'));
98
+ try{
99
+ const journalRoot=path.join(root,'goals');const memoryRoot=path.join(root,'memory');
100
+ const goalId=sha('growing-goal');const signed=signedGoal(goalId,'growing journal');const goal={...signed};delete goal.attestation;
101
+ const firstEvents=eventJournal(goalId,[
102
+ ['goal_created',{source_release_manifest:manifest}],
103
+ ['profile_completed',{profile_id:'test',passed:false,diagnostic_codes:['ERR_FIRST']}]
104
+ ]);
105
+ await writeHistory(journalRoot,signed,firstEvents);
106
+ const provider=createR41MemoryProvider({memoryRoot,journalRoot,sourceReleaseManifest:manifest,privateKey,publicKey,keyId,byteBudget:32768});
107
+ const first=await provider.refresh({goal,events:firstEvents});
108
+ const grownEvents=eventJournal(goalId,[
109
+ ['goal_created',{source_release_manifest:manifest}],
110
+ ['profile_completed',{profile_id:'test',passed:false,diagnostic_codes:['ERR_FIRST']}],
111
+ ['planner_decision',{decision:{summary:'retry safely',action:'run_profile'}}],
112
+ ['profile_completed',{profile_id:'test',passed:true}],
113
+ ['release_completed',{receipt_sha256:sha('grown-release')}]
114
+ ]);
115
+ await rm(path.join(journalRoot,goalId),{recursive:true,force:true});
116
+ await writeHistory(journalRoot,signed,grownEvents);
117
+ const grown=await provider.refresh({goal,events:grownEvents});
118
+ assert.notEqual(first.memory_sha256,grown.memory_sha256);
119
+ assert.notEqual(first.index_sha256,grown.index_sha256);
120
+ const publicKeyPath=path.join(root,'public.pem');await writeFile(publicKeyPath,publicKey.export({type:'spki',format:'pem'}));
121
+ const verified=await verifyR41Memory({memoryRoot,journalRoot,sourceReleaseManifest:manifest,publicKeyPath});
122
+ assert.equal(verified.status,'passed');
123
+ assert.equal(verified.snapshot_count,2);
124
+ assert.equal(verified.index_count,2);
125
+ }finally{await rm(root,{recursive:true,force:true});}
126
+ });
@@ -0,0 +1,92 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { createHash, generateKeyPairSync, sign as cryptoSign } from 'node:crypto';
4
+ import { canonicalJson } from '../src/canonical-json.mjs';
5
+ import {
6
+ deriveEpisodicMemory,verifyEpisode,
7
+ deriveDecisionMemory,verifyDecisionMemory,
8
+ deriveIncidentMemory,verifyIncidentMemory
9
+ } from '../src/memory-r41.mjs';
10
+
11
+ const DOMAIN=Buffer.from('DEADBYTE-AUTONOMOUS-EVENT-V1\0');
12
+ const ZERO='0'.repeat(64);
13
+ const sha=value=>createHash('sha256').update(Buffer.from(typeof value==='string'?value:canonicalJson(value),'utf8')).digest('hex');
14
+ const {privateKey,publicKey}=generateKeyPairSync('ed25519');
15
+ const keyId=sha(Buffer.from(publicKey.export({type:'spki',format:'der'})));
16
+ const goalId=sha('projection-goal');
17
+ const goal={schema:'deadbyte.autonomous-goal.v1',goal_id:goalId,goal_sha256:sha('projection-body'),root_id:'core',
18
+ title:'repair linker',goal:'repair LNK2019',acceptance:'build and tests pass'};
19
+
20
+ function appendJournal(out,type,payload){
21
+ const index=out.length;
22
+ const body={schema:'deadbyte.autonomous-event.v1',seq:index+1,goal_id:goalId,
23
+ created_at_utc:`2026-09-20T02:00:${String(index).padStart(2,'0')}.000Z`,prev_sha256:out.at(-1)?.event_sha256??ZERO,type,payload};
24
+ const event_sha256=sha(body);const signed={...body,event_sha256};
25
+ const signature_base64=cryptoSign(null,Buffer.concat([DOMAIN,Buffer.from(canonicalJson(signed),'utf8')]),privateKey).toString('base64');
26
+ out.push({...signed,attestation:{algorithm:'ed25519',key_id:keyId,signature_base64}});
27
+ }
28
+ function journal(items){
29
+ const out=[];
30
+ for(const [type,payload] of items)appendJournal(out,type,payload);
31
+ return out;
32
+ }
33
+
34
+ const base=journal([
35
+ ['goal_created',{submission_id:'incident-1',acceptance:'build and tests pass'}],
36
+ ['planner_decision',{planner_round:1,decision:{action:'inspect',summary:'inspect linker output'}}],
37
+ ['profile_completed',{profile_id:'build',passed:false,tool:'msbuild',operation:'build',platform:'win32',architecture:'x64',
38
+ exit_code:1,diagnostic_codes:['LNK2019'],stderr_sha256:sha('stderr'),target:'release',symbols:['FooBar'],receipt_sha256:sha('build-fail')}],
39
+ ['planner_decision',{planner_round:2,decision:{action:'patch',summary:'add missing FooBar definition'}}],
40
+ ['native_diff_committed',{paths:['src/foo.cpp'],diff_receipt_sha256:sha('diff'),artifact_sha256:sha('foo-obj')}],
41
+ ['profile_completed',{profile_id:'build',passed:true,receipt_sha256:sha('build-pass')}],
42
+ ['release_completed',{receipt_sha256:sha('release')}]
43
+ ]);
44
+
45
+ test('R41 episodic memory contains only canonical journal references and rejects nonexistent events',()=>{
46
+ const episode=deriveEpisodicMemory(goal,base,{publicKey,keyId});
47
+ assert.equal(episode.schema,'deadbyte.episode.v1');
48
+ assert.equal(episode.outcome,'succeeded');
49
+ assert.deepEqual(episode.event_range,{first_seq:1,last_seq:7,journal_head_sha256:base.at(-1).event_sha256});
50
+ assert.ok(episode.observations.every(item=>item.event_ref?.event_sha256));
51
+ assert.ok(episode.decisions.every(item=>item.event_ref?.event_sha256));
52
+ assert.ok(episode.receipt_refs.includes(sha('release')));
53
+ assert.equal(verifyEpisode(episode,{goal,events:base,publicKey,keyId}).ok,true);
54
+ const forged=structuredClone(episode);forged.actions[0].event_ref.event_sha256=sha('nonexistent');
55
+ assert.equal(verifyEpisode(forged,{goal,events:base,publicKey,keyId}).ok,false);
56
+ });
57
+
58
+ test('R41 decision memory preserves supersession edges and rejects cycles',()=>{
59
+ const events=journal([
60
+ ['goal_created',{submission_id:'decisions'}],
61
+ ['planner_decision',{planner_round:1,decision:{action:'inspect',summary:'inspect first'}}]
62
+ ]);
63
+ const firstId=sha({schema:'deadbyte.decision-id.v1',goal_id:goalId,event_sha256:events[1].event_sha256});
64
+ appendJournal(events,'planner_decision',{planner_round:2,decision:{action:'patch',summary:'patch after evidence',supersedes:firstId}});
65
+ const memory=deriveDecisionMemory(goal,events,{publicKey,keyId});
66
+ assert.equal(memory.decisions.length,2);
67
+ assert.equal(memory.decisions[0].status,'superseded');
68
+ assert.equal(memory.decisions[1].status,'active');
69
+ assert.equal(memory.decisions[1].supersedes,memory.decisions[0].decision_id);
70
+ assert.equal(memory.decisions[0].superseded_by,memory.decisions[1].decision_id);
71
+ assert.equal(verifyDecisionMemory(memory,{goal,events,publicKey,keyId}).ok,true);
72
+
73
+ const cyclic=structuredClone(memory);
74
+ cyclic.decisions[0].supersedes=cyclic.decisions[1].decision_id;
75
+ cyclic.decisions[1].superseded_by=cyclic.decisions[0].decision_id;
76
+ assert.equal(verifyDecisionMemory(cyclic,{goal,events,publicKey,keyId}).ok,false);
77
+ });
78
+
79
+ test('R41 incidents use deterministic structured fingerprints and reject spoofing',()=>{
80
+ const memory=deriveIncidentMemory(goal,base,{publicKey,keyId});
81
+ assert.equal(memory.schema,'deadbyte.incident-memory.v1');
82
+ assert.equal(memory.incidents.length,1);
83
+ const incident=memory.incidents[0];
84
+ assert.equal(incident.fingerprint.tool,'msbuild');
85
+ assert.deepEqual(incident.fingerprint.diagnostic_codes,['LNK2019']);
86
+ assert.deepEqual(incident.fingerprint.symbols,['FooBar']);
87
+ assert.equal(incident.status,'resolved');
88
+ assert.ok(incident.successful_fix.some(ref=>ref.event_sha256===base[4].event_sha256));
89
+ assert.equal(verifyIncidentMemory(memory,{goal,events:base,publicKey,keyId}).ok,true);
90
+ const forged=structuredClone(memory);forged.incidents[0].fingerprint.exit_code=0;
91
+ assert.equal(verifyIncidentMemory(forged,{goal,events:base,publicKey,keyId}).ok,false);
92
+ });
@@ -0,0 +1,124 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { createHash, generateKeyPairSync, sign as cryptoSign } from 'node:crypto';
4
+ import { mkdtemp,readFile,rm } from 'node:fs/promises';
5
+ import os from 'node:os';
6
+ import path from 'node:path';
7
+ import { canonicalJson } from '../src/canonical-json.mjs';
8
+ import {
9
+ buildMemoryCorpus,buildRetrievalIndex,verifyRetrievalIndex,queryMemoryIndex,
10
+ buildWorkingMemory,verifyWorkingMemory,createSemanticMemoryAdapter,createR41MemoryProvider
11
+ } from '../src/memory-r41.mjs';
12
+
13
+ const DOMAIN=Buffer.from('DEADBYTE-AUTONOMOUS-EVENT-V1\0');
14
+ const ZERO='0'.repeat(64);
15
+ const sha=value=>createHash('sha256').update(Buffer.from(typeof value==='string'?value:canonicalJson(value),'utf8')).digest('hex');
16
+ const {privateKey,publicKey}=generateKeyPairSync('ed25519');
17
+ const keyId=sha(Buffer.from(publicKey.export({type:'spki',format:'der'})));
18
+ const goalId=sha('retrieval-goal');
19
+ const manifest=sha('r41-release');
20
+ const goal={schema:'deadbyte.autonomous-goal.v1',goal_id:goalId,goal_sha256:sha('retrieval-body'),root_id:'core',
21
+ title:'repair parser',goal:'repair ParserSymbol timeout',acceptance:'build and tests pass'};
22
+
23
+ function journal(items){
24
+ const out=[];
25
+ for(const [index,[type,payload]] of items.entries()){
26
+ const body={schema:'deadbyte.autonomous-event.v1',seq:index+1,goal_id:goalId,
27
+ created_at_utc:`2026-09-20T04:00:${String(index).padStart(2,'0')}.000Z`,prev_sha256:out.at(-1)?.event_sha256??ZERO,type,payload};
28
+ const event_sha256=sha(body);const signed={...body,event_sha256};
29
+ const signature_base64=cryptoSign(null,Buffer.concat([DOMAIN,Buffer.from(canonicalJson(signed),'utf8')]),privateKey).toString('base64');
30
+ out.push({...signed,attestation:{algorithm:'ed25519',key_id:keyId,signature_base64}});
31
+ }
32
+ return out;
33
+ }
34
+
35
+ const events=journal([
36
+ ['goal_created',{submission_id:'retrieval',acceptance:'build and tests pass'}],
37
+ ['planner_decision',{planner_round:1,decision:{action:'inspect',summary:'inspect ParserSymbol timeout'}}],
38
+ ['profile_completed',{profile_id:'test',passed:false,tool:'node',operation:'test',platform:'win32',architecture:'x64',
39
+ timeout_state:'expired',diagnostic_codes:['ERR_TEST_TIMEOUT'],stderr_sha256:sha('stderr'),symbols:['ParserSymbol'],receipt_sha256:sha('failed')}],
40
+ ['native_diff_committed',{paths:['src/parser.mjs'],diff_receipt_sha256:sha('diff'),artifact_sha256:sha('artifact')}],
41
+ ['profile_completed',{profile_id:'test',passed:true,receipt_sha256:sha('passed')}],
42
+ ['release_completed',{receipt_sha256:sha('release')}]
43
+ ]);
44
+
45
+ function fixture(){
46
+ const corpus=buildMemoryCorpus({goal,events,publicKey,keyId,sourceReleaseManifest:manifest});
47
+ const index=buildRetrievalIndex(corpus,{sourceReleaseManifest:manifest});
48
+ return {corpus,index};
49
+ }
50
+
51
+ test('R41 retrieval indexes rebuild byte-identically and support exact token symbol artifact and incident lookup',()=>{
52
+ const {corpus,index}=fixture();
53
+ const rebuilt=buildRetrievalIndex(corpus,{sourceReleaseManifest:manifest});
54
+ assert.equal(canonicalJson(index),canonicalJson(rebuilt));
55
+ assert.equal(verifyRetrievalIndex(index,{corpus,sourceReleaseManifest:manifest}).ok,true);
56
+ assert.ok(queryMemoryIndex(index,{query:'ParserSymbol timeout',limit:8}).candidate_ids.length>=1);
57
+ assert.ok(queryMemoryIndex(index,{symbol:'ParserSymbol',limit:8}).candidate_ids.length>=1);
58
+ assert.ok(queryMemoryIndex(index,{artifact_sha256:sha('artifact'),limit:8}).candidate_ids.length>=1);
59
+ assert.ok(queryMemoryIndex(index,{incident_fingerprint:corpus.incidents.incidents[0].fingerprint_sha256,limit:8}).candidate_ids.includes(corpus.incidents.incidents[0].incident_id));
60
+ assert.deepEqual(queryMemoryIndex(index,{id:corpus.episode.episode_id,limit:1}).candidate_ids,[corpus.episode.episode_id]);
61
+ });
62
+
63
+ test('R41 poisoned or cross-release indexes fail closed',()=>{
64
+ const {corpus,index}=fixture();
65
+ const poisoned=structuredClone(index);
66
+ poisoned.token_index.timeout=[sha('forged-document')];
67
+ assert.equal(verifyRetrievalIndex(poisoned,{corpus,sourceReleaseManifest:manifest}).ok,false);
68
+ assert.equal(verifyRetrievalIndex(index,{corpus,sourceReleaseManifest:sha('other-release')}).ok,false);
69
+ });
70
+
71
+ test('R41 working memory is bounded provenance-bearing disposable state and rejects staleness',()=>{
72
+ const {corpus,index}=fixture();
73
+ const args={goal,events,corpus,index,publicKey,keyId,sourceReleaseManifest:manifest,byteBudget:16384,
74
+ currentPlan:{step:'verify'},currentFiles:[{path:'src/parser.mjs',sha256:sha('parser'),source_event_sha256:events[3].event_sha256}],
75
+ currentSymbols:['ParserSymbol'],currentAuthority:{coding:{armed:true,reason:'standing-grant',instance_nonce:sha('secret')}}};
76
+ const working=buildWorkingMemory(args);
77
+ assert.ok(Buffer.byteLength(canonicalJson(working),'utf8')<=16384);
78
+ assert.equal(working.source_release_manifest,manifest);
79
+ assert.equal(working.journal_head_sha256,events.at(-1).event_sha256);
80
+ assert.equal(working.current_authority.authorizes_execution,false);
81
+ assert.equal(JSON.stringify(working).includes('instance_nonce'),false);
82
+ assert.ok(working.relevant_incidents[0].source_event_ids.length>=1);
83
+ assert.equal(verifyWorkingMemory(working,args).ok,true);
84
+ const staleArgs={...args,events:events.slice(0,-1)};
85
+ assert.equal(verifyWorkingMemory(working,staleArgs).ok,false);
86
+ assert.equal(verifyWorkingMemory(working,{...args,sourceReleaseManifest:sha('wrong-release')}).ok,false);
87
+ });
88
+
89
+ test('R41 semantic retrieval is disabled by default and verifies candidate IDs against canonical memory',async()=>{
90
+ const {corpus,index}=fixture();
91
+ const disabled=createSemanticMemoryAdapter();
92
+ await assert.rejects(disabled.query({query:'parser',corpus,index,sourceReleaseManifest:manifest}),/disabled/);
93
+
94
+ const validId=corpus.incidents.incidents[0].incident_id;
95
+ const enabled=createSemanticMemoryAdapter({enabled:true,retrieveCandidates:async()=>[validId]});
96
+ const resolved=await enabled.query({query:'parser timeout',corpus,index,sourceReleaseManifest:manifest});
97
+ assert.deepEqual(resolved.candidate_ids,[validId]);
98
+ assert.equal(resolved.records[0].incident_id,validId);
99
+
100
+ const poisoned=createSemanticMemoryAdapter({enabled:true,retrieveCandidates:async()=>[sha('not-canonical')]});
101
+ await assert.rejects(poisoned.query({query:'parser',corpus,index,sourceReleaseManifest:manifest}),/canonical candidate/);
102
+ });
103
+
104
+ test('R41 content-addressed projections survive deletion and rebuild byte-identically',async()=>{
105
+ const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r41-provider-'));
106
+ try{
107
+ const provider=createR41MemoryProvider({memoryRoot:root,sourceReleaseManifest:manifest,writerVersion:'0.13.0',
108
+ privateKey,publicKey,keyId,byteBudget:16384});
109
+ const input={goal,events,currentPlan:null,currentFiles:[],currentSymbols:['ParserSymbol'],currentAuthority:{}};
110
+ const first=await provider.refresh(input);
111
+ assert.equal(first.replay_mode,'full-replay');
112
+ const snapshotBytes=await readFile(first.snapshot_path);
113
+ const indexBytes=await readFile(first.index_path);
114
+ await rm(first.index_path);
115
+ const rebuilt=await provider.refresh(input);
116
+ assert.equal(rebuilt.replay_mode,'snapshot-suffix');
117
+ assert.equal(rebuilt.snapshot_sha256,first.snapshot_sha256);
118
+ assert.equal(rebuilt.index_sha256,first.index_sha256);
119
+ assert.deepEqual(await readFile(rebuilt.snapshot_path),snapshotBytes);
120
+ assert.deepEqual(await readFile(rebuilt.index_path),indexBytes);
121
+ assert.equal(provider.semantic_enabled,false);
122
+ assert.equal(Object.hasOwn(provider,'arm'),false);
123
+ }finally{await rm(root,{recursive:true,force:true});}
124
+ });
@@ -0,0 +1,106 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { createHash, generateKeyPairSync, sign as cryptoSign } from 'node:crypto';
4
+ import { mkdtemp, readFile, writeFile } from 'node:fs/promises';
5
+ import os from 'node:os';
6
+ import path from 'node:path';
7
+ import { canonicalJson } from '../src/canonical-json.mjs';
8
+ import {
9
+ deriveMemoryState,
10
+ createMemorySnapshot,
11
+ verifyMemorySnapshot,
12
+ replayFromMemorySnapshot,
13
+ loadMemoryState,
14
+ writeMemorySnapshot
15
+ } from '../src/memory-r41.mjs';
16
+
17
+ const EVENT_DOMAIN=Buffer.from('DEADBYTE-AUTONOMOUS-EVENT-V1\0');
18
+ const ZERO='0'.repeat(64);
19
+ const sha=value=>createHash('sha256').update(Buffer.from(canonicalJson(value),'utf8')).digest('hex');
20
+ const {privateKey,publicKey}=generateKeyPairSync('ed25519');
21
+ const keyId=sha(Buffer.from(publicKey.export({type:'spki',format:'der'})));
22
+ const goalId=sha('goal');
23
+ const manifest=sha('r41-manifest');
24
+ const goal={schema:'deadbyte.autonomous-goal.v1',goal_id:goalId,goal_sha256:sha('goal-body'),title:'repair',goal:'repair source',acceptance:'tests pass'};
25
+
26
+ function journal(types){
27
+ const events=[];
28
+ for(const [index,[type,payload]] of types.entries()){
29
+ const body={schema:'deadbyte.autonomous-event.v1',seq:index+1,goal_id:goalId,
30
+ created_at_utc:`2026-09-20T00:00:${String(index).padStart(2,'0')}.000Z`,
31
+ prev_sha256:events.at(-1)?.event_sha256??ZERO,type,payload};
32
+ const event_sha256=sha(body);
33
+ const signed={...body,event_sha256};
34
+ const signature_base64=cryptoSign(null,Buffer.concat([EVENT_DOMAIN,Buffer.from(canonicalJson(signed),'utf8')]),privateKey).toString('base64');
35
+ events.push({...signed,attestation:{algorithm:'ed25519',key_id:keyId,signature_base64}});
36
+ }
37
+ return events;
38
+ }
39
+
40
+ const events=journal([
41
+ ['goal_created',{submission_id:'r41',acceptance:'tests pass'}],
42
+ ['planner_decision',{planner_round:1,decision:{action:'inspect',summary:'inspect source'}}],
43
+ ['inspect_completed',{contexts:[{path:'src/a.mjs',sha256:sha('a'),bytes:1}]}],
44
+ ['profile_completed',{profile_id:'test',passed:false,receipt_sha256:sha('failed')}],
45
+ ['planner_decision',{planner_round:2,decision:{action:'patch',summary:'apply exact fix'}}],
46
+ ['native_diff_committed',{paths:['src/a.mjs'],mutation_epoch:1,diff_receipt_sha256:sha('diff')}],
47
+ ['profile_completed',{profile_id:'test',passed:true,receipt_sha256:sha('passed')}],
48
+ ['release_completed',{receipt_sha256:sha('release')}]
49
+ ]);
50
+
51
+ function makeSnapshot(prefix=events.slice(0,5)){
52
+ return createMemorySnapshot({goal,events:prefix,snapshotSequence:1,sourceReleaseManifest:manifest,
53
+ writerVersion:'0.13.0',createdAtUtc:'2026-09-20T01:00:00.000Z',privateKey,keyId,publicKey});
54
+ }
55
+
56
+ test('R41 snapshot plus verified suffix is byte-equivalent to full replay',()=>{
57
+ const snapshot=makeSnapshot();
58
+ assert.equal(snapshot.schema,'deadbyte.memory-snapshot.v1');
59
+ assert.equal(snapshot.schema_version,1);
60
+ assert.equal(snapshot.last_event_seq,5);
61
+ assert.equal(snapshot.journal_prefix_hash,events[4].event_sha256);
62
+ assert.equal(snapshot.source_release_manifest,manifest);
63
+ assert.equal(verifyMemorySnapshot(snapshot,{goal,events,publicKey,keyId,sourceReleaseManifest:manifest}).ok,true);
64
+ const resumed=replayFromMemorySnapshot(snapshot,{goal,events,publicKey,keyId,sourceReleaseManifest:manifest});
65
+ assert.equal(canonicalJson(resumed),canonicalJson(deriveMemoryState(goal,events,{publicKey,keyId})));
66
+ });
67
+
68
+ test('R41 snapshot tampering fails closed for schema sequence prefix state hash and signature',()=>{
69
+ const base=makeSnapshot();
70
+ const mutations=[
71
+ value=>{value.schema='deadbyte.memory-snapshot.v0';},
72
+ value=>{value.snapshot_sequence=0;},
73
+ value=>{value.last_event_seq=6;},
74
+ value=>{value.journal_prefix_hash=sha('wrong-prefix');},
75
+ value=>{value.state.last_event_seq=4;},
76
+ value=>{value.state_hash=sha('wrong-state');},
77
+ value=>{value.attestation.signature_base64=Buffer.alloc(64).toString('base64');}
78
+ ];
79
+ for(const mutate of mutations){
80
+ const candidate=structuredClone(base);mutate(candidate);
81
+ const proof=verifyMemorySnapshot(candidate,{goal,events,publicKey,keyId,sourceReleaseManifest:manifest});
82
+ assert.equal(proof.ok,false,JSON.stringify(candidate));
83
+ }
84
+ });
85
+
86
+ test('R41 missing or corrupt snapshot falls back explicitly to full verified replay',async()=>{
87
+ const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r41-snapshot-'));
88
+ const file=path.join(root,'memory.snapshot.json');
89
+ const missing=await loadMemoryState({snapshotPath:file,goal,events,publicKey,keyId,sourceReleaseManifest:manifest});
90
+ assert.equal(missing.mode,'full-replay');
91
+ assert.equal(missing.snapshot_reason,'missing');
92
+ assert.equal(canonicalJson(missing.state),canonicalJson(deriveMemoryState(goal,events,{publicKey,keyId})));
93
+
94
+ await writeFile(file,'{"broken":true}\n');
95
+ const corrupt=await loadMemoryState({snapshotPath:file,goal,events,publicKey,keyId,sourceReleaseManifest:manifest});
96
+ assert.equal(corrupt.mode,'full-replay');
97
+ assert.match(corrupt.snapshot_reason,/snapshot/i);
98
+
99
+ const snapshot=makeSnapshot();
100
+ await writeMemorySnapshot(file,snapshot);
101
+ const disk=JSON.parse(await readFile(file,'utf8'));
102
+ assert.equal(disk.snapshot_sha256,snapshot.snapshot_sha256);
103
+ const resumed=await loadMemoryState({snapshotPath:file,goal,events,publicKey,keyId,sourceReleaseManifest:manifest});
104
+ assert.equal(resumed.mode,'snapshot-suffix');
105
+ assert.equal(canonicalJson(resumed.state),canonicalJson(deriveMemoryState(goal,events,{publicKey,keyId})));
106
+ });
@@ -86,12 +86,12 @@ test('audit restart reconciles an orphan request with an explicit interrupted re
86
86
  }finally{await rm(stateRoot,{recursive:true,force:true});}
87
87
  });
88
88
 
89
- test('Windows current R40 gate emits manifest-bound machine-readable evidence outside the candidate tree', async()=>{
89
+ test('Windows current R41 gate emits manifest-bound machine-readable evidence outside the candidate tree', async()=>{
90
90
  const stateRoot=await temp('deadbyte-r33-windows-evidence-');
91
91
  try{
92
- const gate=await readFile(path.join(root,'scripts','gate-windows-r40.ps1'),'utf8');
93
- assert.match(gate,/windows-gate-evidence-r40\.mjs/,'gate-windows-r40.ps1 must invoke the evidence writer');
94
- const result=await run(process.execPath,[path.join(root,'scripts','windows-gate-evidence-r40.mjs')],{
92
+ const gate=await readFile(path.join(root,'scripts','gate-windows-r41.ps1'),'utf8');
93
+ assert.match(gate,/windows-gate-evidence-r41\.mjs/,'gate-windows-r41.ps1 must invoke the evidence writer');
94
+ const result=await run(process.execPath,[path.join(root,'scripts','windows-gate-evidence-r41.mjs')],{
95
95
  cwd:root,env:{...process.env,DEADBYTE_STATE_ROOT:stateRoot}
96
96
  });
97
97
  assert.equal(result.code,0,result.stderr||result.stdout);
@@ -99,12 +99,12 @@ test('Windows current R40 gate emits manifest-bound machine-readable evidence ou
99
99
  assert.equal(summary.status,'written');
100
100
  const evidence=JSON.parse(await readFile(summary.path,'utf8'));
101
101
  const manifestSha=sha256(await readFile(path.join(root,'MANIFEST.SHA256')));
102
- assert.equal(evidence.schema,'deadbyte.r40-windows-gate.v1');
102
+ assert.equal(evidence.schema,'deadbyte.r41-windows-gate.v1');
103
103
  assert.equal(evidence.status,'passed');
104
104
  assert.equal(evidence.exit_code,0);
105
- assert.equal(evidence.version,'0.12.0');
105
+ assert.equal(evidence.version,'0.13.0');
106
106
  assert.equal(evidence.manifest_sha256,manifestSha);
107
- assert.equal(evidence.marker,'DEADBYTE V0.12.0 / R40 WINDOWS BATCH GATE: PASS');
107
+ assert.equal(evidence.marker,'DEADBYTE V0.13.0 / R41 WINDOWS BATCH GATE: PASS');
108
108
  assert.ok(summary.path.startsWith(path.join(stateRoot,'evidence','release')));
109
109
  }finally{await rm(stateRoot,{recursive:true,force:true});}
110
110
  });
@@ -19,9 +19,9 @@ test('R34 public parity catalog is exact, unique, and includes production coding
19
19
 
20
20
  test('release parity and final verifier are package entry points', async () => {
21
21
  const pkg = JSON.parse(await text('package.json'));
22
- assert.equal(pkg.scripts['release:parity'], 'node scripts/release-parity-r40.mjs');
23
- assert.equal(pkg.scripts['release:final:write'], 'node scripts/final-closure-r40.mjs');
24
- assert.equal(pkg.scripts['release:final:verify'], 'node scripts/final-closure-verify-r40.mjs');
22
+ assert.equal(pkg.scripts['release:parity'], 'node scripts/release-parity-r41.mjs');
23
+ assert.equal(pkg.scripts['release:final:write'], 'node scripts/final-closure-r41.mjs');
24
+ assert.equal(pkg.scripts['release:final:verify'], 'node scripts/final-closure-verify-r41.mjs');
25
25
  assert.equal(typeof validateParityEvidence, 'function');
26
26
  assert.equal(typeof verifyFinalClosureObject, 'function');
27
27
  });
@@ -72,4 +72,4 @@ test('R34 parity isolates scratch mutation and search from the core release tree
72
72
  assert.match(parity, /machine_search_start[\s\S]*?root_id:scratchRoot/);
73
73
  assert.match(parity, /machine_fs_delete[\s\S]*?root_id:scratchRoot/);
74
74
  assert.doesNotMatch(parity, /machine_fs_(?:write|read|edit_exact|stat|delete)'[^\n]*root_id:'core'/);
75
- });
75
+ });