deadbyte-mcp 0.14.0 → 0.15.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.
- package/AGENTS.md +11 -18
- package/CONTEXT.md +3 -3
- package/MANIFEST.SHA256 +104 -53
- package/R43-PARENT.json +20 -0
- package/R44-DONORS.json +99 -0
- package/R44-PARENT.json +18 -0
- package/README.txt +7 -2
- package/controller/README.TXT +4 -5
- package/controller/deadbyte-controller.ps1 +1 -1
- package/docs/ARCHITECTURE.md +8 -1
- package/docs/R44-ARCHITECTURE.md +37 -0
- package/package.json +13 -8
- package/scripts/deferred-slot-operation-r43.mjs +126 -0
- package/scripts/deferred-slot-operation-r44.mjs +126 -0
- package/scripts/final-closure-r43.mjs +115 -0
- package/scripts/final-closure-r44.mjs +121 -0
- package/scripts/final-closure-verify-r43.mjs +213 -0
- package/scripts/final-closure-verify-r44.mjs +220 -0
- package/scripts/finalize-r43.mjs +217 -0
- package/scripts/finalize-r44.mjs +217 -0
- package/scripts/full-regression-r43.mjs +20 -0
- package/scripts/full-regression-r44.mjs +20 -0
- package/scripts/gate-windows-r43.ps1 +36 -0
- package/scripts/gate-windows-r44.ps1 +36 -0
- package/scripts/release-parity-r43.mjs +218 -0
- package/scripts/release-parity-r44.mjs +242 -0
- package/scripts/release-parity-tests-r43.ps1 +8 -0
- package/scripts/release-parity-tests-r44.ps1 +8 -0
- package/scripts/verify-r43-parent.mjs +126 -0
- package/scripts/verify-r44-parent.mjs +142 -0
- package/scripts/windows-gate-evidence-r43.mjs +55 -0
- package/scripts/windows-gate-evidence-r44.mjs +55 -0
- package/src/agent-backend-r44.mjs +254 -0
- package/src/autonomous-output-contracts.mjs +1 -1
- package/src/autonomous-policy.mjs +41 -4
- package/src/autonomous-runtime.mjs +25 -12
- package/src/autonomous-supervisor-host.mjs +12 -2
- package/src/capability-ledger.mjs +2 -1
- package/src/codex-app-server-r44.mjs +154 -0
- package/src/coding-plane.mjs +66 -19
- package/src/durable-job-r44.mjs +145 -0
- package/src/external-job-provider-r44.mjs +126 -0
- package/src/host-plane.mjs +27 -6
- package/src/job-supervisor-host-r44.mjs +112 -0
- package/src/machine-fs-smoke-client.mjs +1 -1
- package/src/machine-fs.mjs +21 -10
- package/src/mcp-host-smoke-client.mjs +1 -1
- package/src/mcp-server.mjs +20 -3
- package/src/mcp-smoke-client.mjs +1 -1
- package/src/native-diff-v2.mjs +3 -3
- package/src/native-diff.mjs +3 -2
- package/src/observation-smoke-client.mjs +1 -1
- package/src/operator-surface.mjs +2 -2
- package/src/process-policy.mjs +19 -0
- package/src/process-runtime.mjs +5 -2
- package/src/process-smoke-client.mjs +2 -2
- package/src/provider-circuit.mjs +8 -2
- package/src/r44-compact-disarmed-probe.mjs +74 -0
- package/src/r44-full-surface-probe.mjs +34 -0
- package/src/remote-device-r44.mjs +205 -0
- package/src/remote-mcp-autonomous-smoke-client.mjs +4 -4
- package/src/remote-mcp-r44-parity-client.mjs +203 -0
- package/src/remote-mcp-smoke-client.mjs +7 -4
- package/src/runtime-update.mjs +64 -31
- package/src/skill-mcp-tools-r44.mjs +37 -0
- package/src/skill-plane-r44.mjs +203 -0
- package/src/tunnel-stdio-compat-smoke.mjs +1 -1
- package/src/version.mjs +1 -1
- package/test/agent-backend-r44.test.mjs +115 -0
- package/test/agent-runtime.test.mjs +3 -3
- package/test/autonomous-loop.test.mjs +97 -11
- package/test/autonomous-runtime.test.mjs +2 -2
- package/test/capability-ledger-r36.test.mjs +3 -3
- package/test/cli-entrypoint.test.mjs +1 -1
- package/test/codex-app-server-r44.test.mjs +115 -0
- package/test/codex-autonomous-r44.test.mjs +87 -0
- package/test/coding-plane.test.mjs +2 -2
- package/test/coding-runtime.test.mjs +36 -1
- package/test/compact-catalog-r36.test.mjs +3 -3
- package/test/compact-max-catalog-r40.test.mjs +4 -2
- package/test/compact-max-catalog-r44.test.mjs +97 -0
- package/test/core.test.mjs +1 -1
- package/test/durable-job-r44.test.mjs +75 -0
- package/test/external-job-provider-r44.test.mjs +46 -0
- package/test/full-max-catalog-r40.test.mjs +5 -3
- package/test/full-max-catalog-r44.test.mjs +91 -0
- package/test/host-plane.test.mjs +15 -1
- package/test/native-diff.test.mjs +28 -0
- package/test/output-schema.test.mjs +2 -2
- package/test/process-policy.test.mjs +22 -1
- package/test/prompts-resources.test.mjs +1 -1
- package/test/r33-closeout-regression.test.mjs +13 -30
- package/test/r33-finalization.test.mjs +7 -7
- package/test/r43-finalization.test.mjs +31 -0
- package/test/r43-finalizer.test.mjs +34 -0
- package/test/r43-parent.test.mjs +29 -0
- package/test/r44-finalization.test.mjs +58 -0
- package/test/r44-finalizer.test.mjs +48 -0
- package/test/r44-parent.test.mjs +25 -0
- package/test/release-version.test.mjs +53 -19
- package/test/remote-device-r44.test.mjs +104 -0
- package/test/runtime-self-update.test.mjs +42 -0
- package/test/skill-mcp-r44.test.mjs +38 -0
- package/test/skill-plane-r44.test.mjs +93 -0
- package/test/standing-grants.test.mjs +5 -1
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { createDurableJobSupervisorR44 } from '../src/durable-job-r44.mjs';
|
|
7
|
+
|
|
8
|
+
class FakeProvider{
|
|
9
|
+
constructor({external=true}={}){this.external=external;this.handles=new Map();this.starts=0;}
|
|
10
|
+
descriptor(){return {kind:this.external?'external-supervisor':'controller-local',instance_id:'sup-1'};}
|
|
11
|
+
async start(spec){
|
|
12
|
+
const handle={handle_id:`h-${++this.starts}`,pid:1000+this.starts,creation_id:`c-${this.starts}`,profile_id:spec.profile_id};
|
|
13
|
+
const running={...handle,state:'running'};this.handles.set(handle.handle_id,running);return {...running};
|
|
14
|
+
}
|
|
15
|
+
async reattach(handle){
|
|
16
|
+
const current=this.handles.get(handle.handle_id);return current?{...current}:null;
|
|
17
|
+
}
|
|
18
|
+
async status(handle){return this.handles.get(handle.handle_id)??null;}
|
|
19
|
+
async terminate(handle){const current=this.handles.get(handle.handle_id);if(current){current.state='terminated';return {...current};}return null;}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
test('R44 controller/session jobs never masquerade as persistent after owner restart',async()=>{
|
|
23
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r44-job-'));const provider=new FakeProvider();
|
|
24
|
+
try{
|
|
25
|
+
const one=await createDurableJobSupervisorR44({stateDir:root,provider,ownerInstanceId:'owner-1'});
|
|
26
|
+
const c=await one.start({lifetime:'controller',profileId:'build',rootId:'core',cwd:'.',args:[]});
|
|
27
|
+
const s=await one.start({lifetime:'session',profileId:'test',rootId:'core',cwd:'.',args:[]});
|
|
28
|
+
assert.equal(c.state,'running');assert.equal(s.state,'running');
|
|
29
|
+
const two=await createDurableJobSupervisorR44({stateDir:root,provider,ownerInstanceId:'owner-2'});
|
|
30
|
+
assert.equal((await two.status({jobId:c.job_id})).state,'interrupted');
|
|
31
|
+
assert.equal((await two.status({jobId:s.job_id})).state,'interrupted');
|
|
32
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test('R44 persistent job reattaches only through external supervisor with exact process identity',async()=>{
|
|
36
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r44-job-persist-'));const provider=new FakeProvider();
|
|
37
|
+
try{
|
|
38
|
+
const one=await createDurableJobSupervisorR44({stateDir:root,provider,ownerInstanceId:'owner-1'});
|
|
39
|
+
const job=await one.start({lifetime:'persistent',profileId:'watch',rootId:'core',cwd:'.',args:[]});
|
|
40
|
+
const two=await createDurableJobSupervisorR44({stateDir:root,provider,ownerInstanceId:'owner-2'});
|
|
41
|
+
const recovered=await two.status({jobId:job.job_id});
|
|
42
|
+
assert.equal(recovered.state,'running');assert.equal(recovered.recovered,true);
|
|
43
|
+
assert.equal(recovered.pid,job.pid);assert.equal(recovered.creation_id,job.creation_id);
|
|
44
|
+
|
|
45
|
+
const live=provider.handles.get(job.handle_id);live.creation_id='spoofed';
|
|
46
|
+
const three=await createDurableJobSupervisorR44({stateDir:root,provider,ownerInstanceId:'owner-3'});
|
|
47
|
+
assert.equal((await three.status({jobId:job.job_id})).state,'orphaned');
|
|
48
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('R44 persistent lifetime rejects controller-local provider and state corruption',async()=>{
|
|
52
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r44-job-local-'));
|
|
53
|
+
try{
|
|
54
|
+
const local=await createDurableJobSupervisorR44({stateDir:root,provider:new FakeProvider({external:false}),ownerInstanceId:'owner'});
|
|
55
|
+
await assert.rejects(local.start({lifetime:'persistent',profileId:'x',rootId:'core',cwd:'.',args:[]}),/external supervisor/);
|
|
56
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
57
|
+
|
|
58
|
+
const corrupt=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r44-job-corrupt-'));
|
|
59
|
+
try{
|
|
60
|
+
await writeFile(path.join(corrupt,'jobs.json'),'{"schema":','utf8');
|
|
61
|
+
await assert.rejects(createDurableJobSupervisorR44({stateDir:corrupt,provider:new FakeProvider(),ownerInstanceId:'owner'}),/state JSON invalid/);
|
|
62
|
+
}finally{await rm(corrupt,{recursive:true,force:true});}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('R44 terminate binds exact supervisor handle and becomes durable terminal state',async()=>{
|
|
66
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r44-job-term-'));const provider=new FakeProvider();
|
|
67
|
+
try{
|
|
68
|
+
const sup=await createDurableJobSupervisorR44({stateDir:root,provider,ownerInstanceId:'owner'});
|
|
69
|
+
const job=await sup.start({lifetime:'persistent',profileId:'watch',rootId:'core',cwd:'.',args:[]});
|
|
70
|
+
const ended=await sup.terminate({jobId:job.job_id});
|
|
71
|
+
assert.equal(ended.state,'terminated');
|
|
72
|
+
const restarted=await createDurableJobSupervisorR44({stateDir:root,provider,ownerInstanceId:'owner-2'});
|
|
73
|
+
assert.equal((await restarted.status({jobId:job.job_id})).state,'terminated');
|
|
74
|
+
}finally{await rm(root,{recursive:true,force:true});}
|
|
75
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { mkdir, mkdtemp, rm, writeFile, readFile } from 'node:fs/promises';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
import { createDurableJobSupervisorR44 } from '../src/durable-job-r44.mjs';
|
|
9
|
+
import { createExternalJobProviderR44 } from '../src/external-job-provider-r44.mjs';
|
|
10
|
+
|
|
11
|
+
const sha=b=>createHash('sha256').update(b).digest('hex');
|
|
12
|
+
const here=path.dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const repoRoot=path.resolve(here,'..');
|
|
14
|
+
const workerPath=path.join(repoRoot,'src','job-supervisor-host-r44.mjs');
|
|
15
|
+
|
|
16
|
+
test('R44 real external supervisor preserves persistent job identity across controller recreation',async()=>{
|
|
17
|
+
const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r44-real-supervisor-'));
|
|
18
|
+
const supervisorState=path.join(root,'host'),jobsState=path.join(root,'jobs'),project=path.join(root,'project');
|
|
19
|
+
await mkdir(project,{recursive:true});
|
|
20
|
+
const script=path.join(project,'hold.mjs');
|
|
21
|
+
await writeFile(script,`process.stdout.write('READY\\n');setInterval(()=>{},1000);\n`,'utf8');
|
|
22
|
+
const nodeSha=sha(await readFile(process.execPath)), workerSha=sha(await readFile(workerPath));
|
|
23
|
+
const config={stateDir:supervisorState,nodeExecutable:process.execPath,nodeExecutableSha256:nodeSha,
|
|
24
|
+
workerPath,workerSha256:workerSha,roots:{core:project},profiles:{
|
|
25
|
+
hold:{executable:process.execPath,executable_sha256:nodeSha,root_ids:['core'],prefix_args:[script],max_args:4,max_arg_bytes:1024}
|
|
26
|
+
}};
|
|
27
|
+
let providerA=null,providerB=null;
|
|
28
|
+
try{
|
|
29
|
+
providerA=await createExternalJobProviderR44(config);
|
|
30
|
+
const one=await createDurableJobSupervisorR44({stateDir:jobsState,provider:providerA,ownerInstanceId:'controller-a'});
|
|
31
|
+
const started=await one.start({lifetime:'persistent',profileId:'hold',rootId:'core',cwd:'.',args:[]});
|
|
32
|
+
assert.equal(started.state,'running');assert.ok(started.pid>0);assert.match(started.creation_id,/^[0-9a-f]{64}$/);
|
|
33
|
+
|
|
34
|
+
providerB=await createExternalJobProviderR44(config);
|
|
35
|
+
assert.equal(providerB.descriptor().instance_id,providerA.descriptor().instance_id,'must reconnect same external supervisor');
|
|
36
|
+
const two=await createDurableJobSupervisorR44({stateDir:jobsState,provider:providerB,ownerInstanceId:'controller-b'});
|
|
37
|
+
const recovered=await two.status({jobId:started.job_id});
|
|
38
|
+
assert.equal(recovered.state,'running');assert.equal(recovered.recovered,true);
|
|
39
|
+
assert.equal(recovered.handle_id,started.handle_id);assert.equal(recovered.pid,started.pid);assert.equal(recovered.creation_id,started.creation_id);
|
|
40
|
+
const ended=await two.terminate({jobId:started.job_id});assert.equal(ended.state,'terminated');
|
|
41
|
+
}finally{
|
|
42
|
+
if(providerB)await providerB.shutdown().catch(()=>{});
|
|
43
|
+
else if(providerA)await providerA.shutdown().catch(()=>{});
|
|
44
|
+
await rm(root,{recursive:true,force:true});
|
|
45
|
+
}
|
|
46
|
+
});
|
|
@@ -10,8 +10,10 @@ import { createR34Fixture } from './helpers/autonomous-r34-fixture.mjs';
|
|
|
10
10
|
|
|
11
11
|
const here=path.dirname(fileURLToPath(import.meta.url));
|
|
12
12
|
const repoRoot=path.resolve(here,'..');
|
|
13
|
-
const
|
|
14
|
-
const
|
|
13
|
+
const parent=JSON.parse(await readFile(path.join(repoRoot,'R44-PARENT.json'),'utf8'));
|
|
14
|
+
const parentRoot=parent.parent_release_root;
|
|
15
|
+
const serverPath=path.join(parentRoot,'src','mcp-server.mjs');
|
|
16
|
+
const desktopPolicyPath=path.join(parentRoot,'controller','deadbyte-desktop-policy.json');
|
|
15
17
|
const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
16
18
|
const absent=async p=>{try{await access(p);return false;}catch(e){if(e?.code==='ENOENT')return true;throw e;}};
|
|
17
19
|
|
|
@@ -70,7 +72,7 @@ test('R40 real max-runtime full stdio catalog is exactly 80 with four Desktop pr
|
|
|
70
72
|
DEADBYTE_AUTONOMOUS_POLICY:path.join(f.root,'autonomous-policy.json'),
|
|
71
73
|
DEADBYTE_AUTONOMOUS_SUPERVISOR_MODE:'external'
|
|
72
74
|
};
|
|
73
|
-
const transport=new StdioClientTransport({command:process.execPath,args:[serverPath],cwd:
|
|
75
|
+
const transport=new StdioClientTransport({command:process.execPath,args:[serverPath],cwd:parentRoot,env,stderr:'pipe'});
|
|
74
76
|
try{
|
|
75
77
|
await client.connect(transport);
|
|
76
78
|
const listed=await client.listTools();
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { access, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { Client } from '@modelcontextprotocol/client';
|
|
8
|
+
import { StdioClientTransport, getDefaultEnvironment } from '@modelcontextprotocol/client/stdio';
|
|
9
|
+
import { createR34Fixture } from './helpers/autonomous-r34-fixture.mjs';
|
|
10
|
+
|
|
11
|
+
const here=path.dirname(fileURLToPath(import.meta.url));
|
|
12
|
+
const repoRoot=path.resolve(here,'..');
|
|
13
|
+
const serverPath=path.join(repoRoot,'src','mcp-server.mjs');
|
|
14
|
+
const desktopPolicyPath=path.join(repoRoot,'controller','deadbyte-desktop-policy.json');
|
|
15
|
+
const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
16
|
+
const absent=async p=>{try{await access(p);return false;}catch(e){if(e?.code==='ENOENT')return true;throw e;}};
|
|
17
|
+
|
|
18
|
+
test('R44 real max-runtime full stdio catalog is exactly 81 with skill and four Desktop primitives while authority remains disarmed',async()=>{
|
|
19
|
+
const f=await createR34Fixture({authority:'disarmed'});
|
|
20
|
+
const processPolicyPath=path.join(f.root,'process-policy.json');
|
|
21
|
+
const processGrant=path.join(f.root,'process-grant.json');
|
|
22
|
+
const processState=path.join(f.root,'process-state');
|
|
23
|
+
const hostPolicyPath=path.join(f.root,'host-policy.json');
|
|
24
|
+
const hostArm=path.join(f.root,'host-arm.json');
|
|
25
|
+
const nodeSha=sha(await readFile(process.execPath));
|
|
26
|
+
await mkdir(processState,{recursive:true});
|
|
27
|
+
await writeFile(processPolicyPath,JSON.stringify({
|
|
28
|
+
schema:'deadbyte.process-policy.v1',enabled:true,grant_file:processGrant,state_dir:processState,
|
|
29
|
+
native_host:{path:process.execPath,sha256:nodeSha},
|
|
30
|
+
roots:{core:{path:f.project,deny_paths:[]}},
|
|
31
|
+
profiles:{node:{executable:process.execPath,executable_sha256:nodeSha,root_ids:['core'],
|
|
32
|
+
prefix_args:[],transport:'pipe',max_args:8,max_arg_bytes:1024,max_sessions:2,
|
|
33
|
+
max_input_bytes:65536,max_retained_output_bytes:262144,env_allow:['PATH','TEMP','TMP'],
|
|
34
|
+
input_actions:{ping:'PING\r\n'}}}
|
|
35
|
+
},null,2));
|
|
36
|
+
await writeFile(hostPolicyPath,JSON.stringify({
|
|
37
|
+
schema:'deadbyte.host-policy.v1',enabled:true,arm_file:hostArm,max_read_bytes:262144,max_write_bytes:1048576,
|
|
38
|
+
roots:{core:{path:f.project,read:true,write:true,exec:true}},
|
|
39
|
+
commands:{node_script:{kind:'script',executable:process.execPath,executable_sha256:nodeSha,
|
|
40
|
+
root_ids:['core'],prefix_args:[],extensions:['.mjs'],timeout_ms:5000,max_output_bytes:65536}}
|
|
41
|
+
},null,2));
|
|
42
|
+
|
|
43
|
+
const desktopRaw=JSON.parse(await readFile(desktopPolicyPath,'utf8'));
|
|
44
|
+
const desktopGrant=desktopRaw.grant_file;
|
|
45
|
+
const codingLease=f.codingPolicy.lease_file;
|
|
46
|
+
const autonomousLease=f.policy.lease_file;
|
|
47
|
+
for(const q of [processGrant,hostArm,desktopGrant,codingLease,autonomousLease]) assert.equal(await absent(q),true,'authority unexpectedly armed before start: '+q);
|
|
48
|
+
|
|
49
|
+
const client=new Client({name:'deadbyte-r44-full-catalog',version:'0.15.0'},{versionNegotiation:{mode:{pin:'2026-07-28'}}});
|
|
50
|
+
const env={
|
|
51
|
+
...getDefaultEnvironment(),
|
|
52
|
+
DEADBYTE_CAPABILITY_PROFILE:'full',
|
|
53
|
+
DEADBYTE_AUDIT_RUNTIME:'0',
|
|
54
|
+
DEADBYTE_STATE_ROOT:path.join(f.root,'state'),
|
|
55
|
+
DEADBYTE_WORKSPACE_ROOT:f.root,
|
|
56
|
+
DEADBYTE_SIGNING_KEY:f.keys.privateKeyPath,
|
|
57
|
+
DEADBYTE_VERIFY_KEY:f.keys.publicKeyPath,
|
|
58
|
+
DEADBYTE_PRIVILEGED_POLICY:hostPolicyPath,
|
|
59
|
+
DEADBYTE_MACHINE_RUNTIME:'1',
|
|
60
|
+
DEADBYTE_AGENT_RUNTIME:'1',
|
|
61
|
+
DEADBYTE_PROCESS_RUNTIME:'1',
|
|
62
|
+
DEADBYTE_PROCESS_POLICY:processPolicyPath,
|
|
63
|
+
DEADBYTE_CODING_RUNTIME:'1',
|
|
64
|
+
DEADBYTE_CODING_POLICY:path.join(f.root,'coding-policy.json'),
|
|
65
|
+
DEADBYTE_MACHINE_FS_RUNTIME:'1',
|
|
66
|
+
DEADBYTE_OBSERVATION_RUNTIME:'1',
|
|
67
|
+
DEADBYTE_DESKTOP_RUNTIME:'1',
|
|
68
|
+
DEADBYTE_DESKTOP_POLICY:desktopPolicyPath,
|
|
69
|
+
DEADBYTE_AUTONOMOUS_RUNTIME:'1',
|
|
70
|
+
DEADBYTE_AUTONOMOUS_POLICY:path.join(f.root,'autonomous-policy.json'),
|
|
71
|
+
DEADBYTE_AUTONOMOUS_SUPERVISOR_MODE:'external'
|
|
72
|
+
};
|
|
73
|
+
const transport=new StdioClientTransport({command:process.execPath,args:[serverPath],cwd:repoRoot,env,stderr:'pipe'});
|
|
74
|
+
try{
|
|
75
|
+
await client.connect(transport);
|
|
76
|
+
const listed=await client.listTools();
|
|
77
|
+
const names=listed.tools.map(t=>t.name).sort();
|
|
78
|
+
const {R44_EXPECTED_TOOLS}=await import('../src/remote-mcp-r44-parity-client.mjs');
|
|
79
|
+
assert.equal(names.length,81,'expected exact full R44 catalog 81, got '+names.length+': '+names.join(','));
|
|
80
|
+
assert.deepEqual(names,R44_EXPECTED_TOOLS);
|
|
81
|
+
for(const name of ['desktop_status','desktop_observe','desktop_target','desktop_action',
|
|
82
|
+
'host_file_read','host_file_write','host_exec','skill_catalog']) assert.ok(names.includes(name),'missing '+name);
|
|
83
|
+
for(const tool of listed.tools) assert.equal(tool.outputSchema?.additionalProperties,false,'non-strict output '+tool.name);
|
|
84
|
+
const catalog_sha256=sha(Buffer.from(JSON.stringify(names),'utf8'));
|
|
85
|
+
console.log(JSON.stringify({tool_count:names.length,catalog_sha256,desktop_tools:4,skill:true,authority:'DISARMED'}));
|
|
86
|
+
} finally {
|
|
87
|
+
await client.close().catch(()=>{});
|
|
88
|
+
for(const q of [processGrant,hostArm,desktopGrant,codingLease,autonomousLease]) assert.equal(await absent(q),true,'authority file appeared during catalog probe: '+q);
|
|
89
|
+
await f.cleanup();
|
|
90
|
+
}
|
|
91
|
+
});
|
package/test/host-plane.test.mjs
CHANGED
|
@@ -11,7 +11,8 @@ import {
|
|
|
11
11
|
hostExec,
|
|
12
12
|
hostFileRead,
|
|
13
13
|
hostFileWrite,
|
|
14
|
-
loadHostPolicy
|
|
14
|
+
loadHostPolicy,
|
|
15
|
+
recheckHostAuthority
|
|
15
16
|
} from '../src/host-plane.mjs';
|
|
16
17
|
|
|
17
18
|
const sha = bytes => createHash('sha256').update(bytes).digest('hex');
|
|
@@ -66,6 +67,19 @@ test('privileged host plane requires a live policy-bound arm lease', async () =>
|
|
|
66
67
|
await assert.rejects(() => assertHostArmed(expired.policy), /arm expired/);
|
|
67
68
|
});
|
|
68
69
|
|
|
70
|
+
test('host authority recheck rejects arm generation or expiry drift before side effects', async () => {
|
|
71
|
+
const f = await fixture();
|
|
72
|
+
const initial = await assertHostArmed(f.policy);
|
|
73
|
+
const arm = JSON.parse(await readFile(f.arm, 'utf8'));
|
|
74
|
+
await writeFile(f.arm, JSON.stringify({ ...arm, instance_nonce: 'b'.repeat(64) }));
|
|
75
|
+
await assert.rejects(() => recheckHostAuthority(f.policy, initial), /host authority changed during operation/);
|
|
76
|
+
await writeFile(f.arm, JSON.stringify({
|
|
77
|
+
...arm,
|
|
78
|
+
expires_at_utc: new Date(Date.parse(arm.expires_at_utc) + 60000).toISOString()
|
|
79
|
+
}));
|
|
80
|
+
await assert.rejects(() => recheckHostAuthority(f.policy, initial), /host authority changed during operation/);
|
|
81
|
+
});
|
|
82
|
+
|
|
69
83
|
test('host_file_write is root-scoped hash-precondition and host_file_read returns a verified digest', async () => {
|
|
70
84
|
const f = await fixture();
|
|
71
85
|
const first = await hostFileWrite(f.policy, {
|
|
@@ -79,6 +79,34 @@ test('native diff rolls back earlier operations when a later operation fails', a
|
|
|
79
79
|
} finally { await rm(f.root,{recursive:true,force:true}); }
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
+
test('native diff revocation between operations rolls back to preimage without autonomous rollback authority', async () => {
|
|
83
|
+
const f = await fixture();
|
|
84
|
+
try {
|
|
85
|
+
let writes = 0;
|
|
86
|
+
const revokingCoding = Object.freeze({
|
|
87
|
+
...f.codingRuntime,
|
|
88
|
+
fileWrite: async args => {
|
|
89
|
+
const result = await f.codingRuntime.fileWrite(args);
|
|
90
|
+
writes += 1;
|
|
91
|
+
if (writes === 1) {
|
|
92
|
+
const lease = JSON.parse(await readFile(f.policy.lease_file, 'utf8'));
|
|
93
|
+
await writeFile(f.policy.lease_file, JSON.stringify({ ...lease, instance_nonce:'e'.repeat(64) }));
|
|
94
|
+
}
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
const runtime = createNativeDiffRuntime({ policy:f.policy, codingRuntime:revokingCoding,
|
|
99
|
+
signingKeyPath:f.keys.privateKeyPath, verifyKeyPath:f.keys.publicKeyPath });
|
|
100
|
+
const preview = await runtime.preview({ rootId:'project', title:'revoke mid transaction', operations:[
|
|
101
|
+
{ kind:'write', path:'first.txt', expected_sha256:'absent', encoding:'utf8', content:'first\n' },
|
|
102
|
+
{ kind:'write', path:'second.txt', expected_sha256:'absent', encoding:'utf8', content:'second\n' }
|
|
103
|
+
] });
|
|
104
|
+
await assert.rejects(runtime.apply({ diffId:preview.diff_id }), /rolled back.*autonomous authority changed/i);
|
|
105
|
+
assert.equal(await exists(path.join(f.project,'first.txt')), false);
|
|
106
|
+
assert.equal(await exists(path.join(f.project,'second.txt')), false);
|
|
107
|
+
} finally { await rm(f.root,{recursive:true,force:true}); }
|
|
108
|
+
});
|
|
109
|
+
|
|
82
110
|
test('autonomous application scope isolates repeated identical native diffs across goals', async () => {
|
|
83
111
|
const f = await fixture();
|
|
84
112
|
try {
|
|
@@ -19,7 +19,7 @@ const EXPECTED_TOOLS = [
|
|
|
19
19
|
'agent_task_run', 'agent_task_status', 'agent_task_submit',
|
|
20
20
|
'agent_task_verify', 'contained_transform', 'evidence_verify',
|
|
21
21
|
'file_read',
|
|
22
|
-
'proof_execute', 'workspace_open'
|
|
22
|
+
'proof_execute', 'skill_catalog', 'workspace_open'
|
|
23
23
|
];
|
|
24
24
|
|
|
25
25
|
async function fixture() {
|
|
@@ -47,7 +47,7 @@ async function fixture() {
|
|
|
47
47
|
return { trust, client, transport };
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
test('
|
|
50
|
+
test('R44 hermetic base-plus-agent catalog advertises 13 strict output schemas', async () => {
|
|
51
51
|
const f = await fixture();
|
|
52
52
|
try {
|
|
53
53
|
await f.client.connect(f.transport);
|
|
@@ -9,7 +9,8 @@ import {
|
|
|
9
9
|
PROCESS_POLICY_SCHEMA,
|
|
10
10
|
assertProcessArmed,
|
|
11
11
|
loadProcessPolicy,
|
|
12
|
-
processSessionStatus
|
|
12
|
+
processSessionStatus,
|
|
13
|
+
recheckProcessAuthority
|
|
13
14
|
} from '../src/process-policy.mjs';
|
|
14
15
|
|
|
15
16
|
const sha = bytes => createHash('sha256').update(bytes).digest('hex');
|
|
@@ -69,6 +70,26 @@ test('process policy loads pinned native host, profile and root while grant is a
|
|
|
69
70
|
await assert.rejects(() => assertProcessArmed(policy, 'other', 'core'), /profile 'other' is not included/);
|
|
70
71
|
});
|
|
71
72
|
|
|
73
|
+
test('process authority recheck rejects grant generation or scope drift before side effects', async () => {
|
|
74
|
+
const f = await fixture();
|
|
75
|
+
const policy = await loadProcessPolicy(f.policyPath);
|
|
76
|
+
const grant = {
|
|
77
|
+
schema: PROCESS_GRANT_SCHEMA,
|
|
78
|
+
policy_sha256: policy.policy_sha256,
|
|
79
|
+
instance_nonce: 'a'.repeat(64),
|
|
80
|
+
profile_ids: ['node'],
|
|
81
|
+
root_ids: ['core'],
|
|
82
|
+
granted_at_utc: '2026-09-14T00:00:00Z'
|
|
83
|
+
};
|
|
84
|
+
await writeFile(f.grantFile, JSON.stringify(grant));
|
|
85
|
+
const initial = await assertProcessArmed(policy, 'node', 'core');
|
|
86
|
+
await writeFile(f.grantFile, JSON.stringify({ ...grant, instance_nonce: 'b'.repeat(64) }));
|
|
87
|
+
await assert.rejects(() => recheckProcessAuthority(policy, initial, 'node', 'core'), /process authority changed during operation/);
|
|
88
|
+
await writeFile(f.grantFile, JSON.stringify({ ...grant, profile_ids: ['node', 'node'] }));
|
|
89
|
+
const deduped = await recheckProcessAuthority(policy, initial, 'node', 'core');
|
|
90
|
+
assert.equal(deduped.instance_nonce, initial.instance_nonce);
|
|
91
|
+
});
|
|
92
|
+
|
|
72
93
|
test('process grant with wrong policy digest is disarmed', async () => {
|
|
73
94
|
const f = await fixture();
|
|
74
95
|
const policy = await loadProcessPolicy(f.policyPath);
|
|
@@ -30,7 +30,7 @@ test('MCP exposes compact workflow prompts and source-of-truth context resources
|
|
|
30
30
|
const surfaceState=JSON.parse(surfaceText);
|
|
31
31
|
assert.equal(surfaceState.schema,'deadbyte.surface-profile.v1');
|
|
32
32
|
assert.equal(surfaceState.profile,'full');
|
|
33
|
-
assert.equal(surfaceState.compact_tool_limit,
|
|
33
|
+
assert.equal(surfaceState.compact_tool_limit,43);
|
|
34
34
|
const context=await client.readResource({uri:'deadbyte://context'});
|
|
35
35
|
const contextText=context.contents.map(c=>'text' in c?c.text:'').join('\n');
|
|
36
36
|
assert.match(contextText,/Machine truth/i); assert.match(contextText,/Authority plane/i); assert.match(contextText,/Loop Supervisor/i);
|
|
@@ -86,40 +86,23 @@ 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
|
|
90
|
-
const stateRoot=await temp('deadbyte-
|
|
89
|
+
test('Windows current R44 gate emits signed-R43-parent feature evidence outside the candidate tree', async()=>{
|
|
90
|
+
const stateRoot=await temp('deadbyte-r44-windows-evidence-');
|
|
91
91
|
try{
|
|
92
|
-
const gate=await readFile(path.join(root,'scripts','gate-windows-
|
|
93
|
-
assert.match(gate,/windows-gate-evidence-
|
|
94
|
-
assert.match(gate,/r42-model-backed-eval/,'R42 gate must require model-backed eval before evidence writer');
|
|
95
|
-
|
|
96
|
-
const suite=JSON.parse(await readFile(path.join(root,'harness','r42-agent-evals.json'),'utf8'));
|
|
92
|
+
const gate=await readFile(path.join(root,'scripts','gate-windows-r44.ps1'),'utf8');
|
|
93
|
+
assert.match(gate,/windows-gate-evidence-r44\.mjs/);assert.match(gate,/r44-parent-verify/);
|
|
97
94
|
const manifestSha=sha256(await readFile(path.join(root,'MANIFEST.SHA256')));
|
|
98
|
-
const {
|
|
99
|
-
const
|
|
100
|
-
const evaluation=await runAgentEvalSuiteR42({
|
|
101
|
-
suite,subjectManifestSha256:manifestSha,
|
|
102
|
-
evidenceRoot:path.join(stateRoot,'evidence','release','r42-agent-evals'),
|
|
103
|
-
clock:()=>new Date('2026-09-20T02:00:00.000Z'),
|
|
104
|
-
requestModel:async call=>call.role==='generator'
|
|
105
|
-
?{backend:'fixture',model:'fixture',response_id:`g-${call.case_id}`,raw_text:JSON.stringify({artifact:{plan:['inspect','verify','fail_closed']}})}
|
|
106
|
-
:{backend:'fixture',model:'fixture',response_id:`j-${call.case_id}`,raw_text:JSON.stringify({
|
|
107
|
-
schema:'deadbyte.agent-eval-judge-result.v1',verdict:'pass',advisory:true,findings:[],evidence_refs:['1'.repeat(64)]
|
|
108
|
-
})}
|
|
109
|
-
});
|
|
110
|
-
assert.equal(evaluation.payload.status,'passed');
|
|
111
|
-
|
|
112
|
-
const summary=await writeWindowsGateEvidence({candidateRoot:root,stateRoot,clock:()=>new Date('2026-09-20T02:01:00.000Z')});
|
|
113
|
-
assert.equal(summary.status,'written');
|
|
95
|
+
const {writeWindowsGateEvidence}=await import('../scripts/windows-gate-evidence-r44.mjs');
|
|
96
|
+
const summary=await writeWindowsGateEvidence({candidateRoot:root,stateRoot,clock:()=>new Date('2026-09-21T00:01:00.000Z')});
|
|
114
97
|
const evidence=JSON.parse(await readFile(summary.path,'utf8'));
|
|
115
|
-
assert.equal(evidence.schema,'deadbyte.
|
|
116
|
-
assert.equal(evidence.status,'passed');
|
|
117
|
-
assert.equal(evidence.exit_code,0);
|
|
118
|
-
assert.equal(evidence.version,'0.14.0');
|
|
98
|
+
assert.equal(evidence.schema,'deadbyte.r44-windows-gate.v1');assert.equal(evidence.version,'0.15.0');
|
|
119
99
|
assert.equal(evidence.manifest_sha256,manifestSha);
|
|
120
|
-
assert.equal(evidence.marker,'DEADBYTE V0.
|
|
121
|
-
assert.equal(evidence.
|
|
122
|
-
assert.equal(evidence.
|
|
100
|
+
assert.equal(evidence.marker,'DEADBYTE V0.15.0 / R44 REMOTE AGENT SKILL WINDOWS BATCH GATE: PASS');
|
|
101
|
+
assert.equal(evidence.parent.release_id,'v0.14.1-0a5a833892593283');
|
|
102
|
+
assert.equal(evidence.parent.final_closure_sha256,'2f29e94dd726638c23b2e520a608dcf2a6919e43348855be3940599d557f920b');
|
|
103
|
+
for(const key of ['skill_integrity','agent_backend_persistence','codex_protocol_contract','remote_device_identity','durable_job_supervisor','real_external_supervisor_smoke','full_regression_required']) assert.equal(evidence.features[key],true,key);
|
|
123
104
|
assert.ok(summary.path.startsWith(path.join(stateRoot,'evidence','release')));
|
|
105
|
+
const historical=await readFile(path.join(root,'scripts','windows-gate-evidence-r43.mjs'),'utf8');
|
|
106
|
+
assert.match(historical,/version:'0\.14\.1'/);assert.match(historical,/deadbyte\.r43-windows-gate\.v1/);
|
|
124
107
|
}finally{await rm(stateRoot,{recursive:true,force:true});}
|
|
125
108
|
});
|
|
@@ -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-
|
|
23
|
-
assert.equal(pkg.scripts['release:final:write'], 'node scripts/final-closure-
|
|
24
|
-
assert.equal(pkg.scripts['release:final:verify'], 'node scripts/final-closure-verify-
|
|
22
|
+
assert.equal(pkg.scripts['release:parity'], 'node scripts/release-parity-r44.mjs');
|
|
23
|
+
assert.equal(pkg.scripts['release:final:write'], 'node scripts/final-closure-r44.mjs');
|
|
24
|
+
assert.equal(pkg.scripts['release:final:verify'], 'node scripts/final-closure-verify-r44.mjs');
|
|
25
25
|
assert.equal(typeof validateParityEvidence, 'function');
|
|
26
26
|
assert.equal(typeof verifyFinalClosureObject, 'function');
|
|
27
27
|
});
|
|
@@ -45,11 +45,11 @@ test('final closure verifier canonicalizes traversal order before exact-tree com
|
|
|
45
45
|
assert.match(verifier, /const expected=\[\.\.\.entries\.keys\(\)\]\.sort\(\(a,b\)=>a\.localeCompare\(b,'en'\)\);/);
|
|
46
46
|
});
|
|
47
47
|
|
|
48
|
-
test('
|
|
48
|
+
test('R44 autonomous live gate binds the current compact gateway contract instead of the historical 73-tool public catalog', async () => {
|
|
49
49
|
const autonomous = await text('src/remote-mcp-autonomous-smoke-client.mjs');
|
|
50
|
-
assert.match(autonomous, /
|
|
51
|
-
assert.match(autonomous, /
|
|
52
|
-
assert.match(autonomous, /names\.length >
|
|
50
|
+
assert.match(autonomous, /R44_COMPACT_GATEWAYS/);
|
|
51
|
+
assert.match(autonomous, /R44_COMPACT_TOOL_LIMIT/);
|
|
52
|
+
assert.match(autonomous, /names\.length > R44_COMPACT_TOOL_LIMIT/);
|
|
53
53
|
for (const name of ['autonomous_goal_submit','autonomous_goal_run','autonomous_goal_verify','autonomous_release_gate','native_diff_apply','native_diff_verify']) {
|
|
54
54
|
assert.match(autonomous,new RegExp(name));
|
|
55
55
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { validateParityEvidence,R43_PREDECESSOR_RELEASE_ID,R43_PREDECESSOR_MANIFEST } from '../scripts/release-parity-r43.mjs';
|
|
5
|
+
import { verifyFinalClosureObject } from '../scripts/final-closure-verify-r43.mjs';
|
|
6
|
+
|
|
7
|
+
const root=new URL('../',import.meta.url);const text=rel=>readFile(new URL(rel,root),'utf8');
|
|
8
|
+
function parity(){const manifest='a'.repeat(64);return {schema:'deadbyte.r43-parity.v1',status:'passed',execution_provider:'deadbyte_mcp',rdc_operation_count:0,
|
|
9
|
+
candidate:{release_id:`v0.14.1-${manifest.slice(0,16)}`,version:'0.14.1',manifest_sha256:manifest},
|
|
10
|
+
immutable_slot:{protected:true,release_root:'C:/immutable/r43',development_root:'D:/Projects/deadbyte-mcp/development/deadbyte-mcp-r42-agentic-dev'},
|
|
11
|
+
local_full:{status:'passed',tool_count:80,strict_output_schemas:true},
|
|
12
|
+
public_compact:{status:'passed',tool_count:42,capability_closure:true,gateway_count:6,desktop_armed:false,desktop_observation_receipt_verified:true,desktop_grounding_receipt_verified:true},
|
|
13
|
+
autonomous:{status:'passed',signed_release_verified:true},desktop_guarded:{status:'passed',native_injected:true,replay_performed:false,predispatch_retry_count:0,observation_receipts_verified:1,action_receipts_verified:3},
|
|
14
|
+
deterministic_memory:{status:'passed',goal_count:1,snapshot_count:1,index_count:1},
|
|
15
|
+
before_rollback_disarmed:{status:'passed',capability_closure:true,coding_armed:false,autonomous_armed:false,desktop_armed:false},rollback:{state:'completed'},restore:{state:'completed'},stage_restore:{status:'restored',manifest_sha256:manifest},
|
|
16
|
+
predecessor:{release_id:R43_PREDECESSOR_RELEASE_ID,version:'0.14.0',manifest_sha256:R43_PREDECESSOR_MANIFEST},predecessor_disarmed:{status:'passed',tool_count:42,capability_closure:true},
|
|
17
|
+
successor:{release_id:`v0.14.1-${manifest.slice(0,16)}`,version:'0.14.1',manifest_sha256:manifest},successor_disarmed:{status:'passed',capability_closure:true,coding_armed:false,autonomous_armed:false,desktop_armed:false},
|
|
18
|
+
requirements:Object.fromEntries(['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'].map(key=>[key,true]))};}
|
|
19
|
+
|
|
20
|
+
test('R43 parity requires exact R42 predecessor and immutable R43 slot',()=>{const value=parity();assert.equal(validateParityEvidence(value),true);
|
|
21
|
+
assert.throws(()=>validateParityEvidence({...value,predecessor:{...value.predecessor,manifest_sha256:'b'.repeat(64)}}),/predecessor/i);
|
|
22
|
+
assert.throws(()=>validateParityEvidence({...value,immutable_slot:{...value.immutable_slot,development_root:value.immutable_slot.release_root}}),/immutable-slot/i);});
|
|
23
|
+
|
|
24
|
+
test('R43 release machinery binds 0.14.1 exact R42 predecessor and no fresh model credential dependency',async()=>{const [gate,deferred,paritySource,writer,verifier,evidence,suite,finalizer]=await Promise.all([
|
|
25
|
+
text('scripts/gate-windows-r43.ps1'),text('scripts/deferred-slot-operation-r43.mjs'),text('scripts/release-parity-r43.mjs'),text('scripts/final-closure-r43.mjs'),text('scripts/final-closure-verify-r43.mjs'),text('scripts/windows-gate-evidence-r43.mjs'),text('scripts/release-parity-tests-r43.ps1'),text('scripts/finalize-r43.mjs')]);
|
|
26
|
+
assert.equal(R43_PREDECESSOR_RELEASE_ID,'v0.14.0-08cd8f3b98c90e0e');assert.equal(R43_PREDECESSOR_MANIFEST,'08cd8f3b98c90e0e250cf506ff396515065ff5457909f850b75b0b6e8ecc2dd1');
|
|
27
|
+
assert.match(gate,/r43-parent-verify/);assert.doesNotMatch(gate,/model-backed-eval|OPENAI_API_KEY/);assert.match(gate,/full-regression/);assert.match(gate,/r43:full:test/);assert.match(gate,/DEADBYTE V0\.14\.1 \/ R43 AUTHORITY HARDENING WINDOWS BATCH GATE: PASS/);
|
|
28
|
+
assert.match(deferred,/--expected-version','0\.14\.1'/);assert.match(paritySource,/deadbyte\.r43-parity\.v1/);assert.doesNotMatch(paritySource,/verifyR42ModelEval|model_eval/);
|
|
29
|
+
for(const source of [writer,verifier]){assert.match(source,/DEADBYTE-R43-FINAL-CLOSURE-V1/);assert.match(source,/deadbyte\.r43-final-closure\.v1/);assert.match(source,/R43 AUTHORITY HARDENING PATCH/);assert.doesNotMatch(source,/model_eval/);}
|
|
30
|
+
assert.equal(typeof verifyFinalClosureObject,'function');assert.match(evidence,/deadbyte\.r43-windows-gate\.v1/);assert.match(evidence,/parent_activation_receipt_sha256/);assert.match(suite,/autonomous-loop\.test\.mjs/);assert.match(suite,/runtime-self-update\.test\.mjs/);assert.match(suite,/r43-finalizer\.test\.mjs/);assert.match(finalizer,/--restore-standing-grants/);assert.match(finalizer,/final_authority\?\.process_armed===true/);assert.match(finalizer,/requires Process standing grant/);assert.match(finalizer,/runReleaseParity/);assert.match(finalizer,/writeFinalClosure/);assert.match(finalizer,/verifyFinalClosureObject/);assert.match(finalizer,/--rollback-receipt/);assert.match(finalizer,/parity_scratch/);
|
|
31
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { validateFinalizerAuthorityStatus, validateWindowsGateEvidence } from '../scripts/finalize-r43.mjs';
|
|
4
|
+
|
|
5
|
+
const manifest='a'.repeat(64);
|
|
6
|
+
const parent={parent_release_id:'v0.14.0-08cd8f3b98c90e0e',
|
|
7
|
+
parent_manifest_sha256:'08cd8f3b98c90e0e250cf506ff396515065ff5457909f850b75b0b6e8ecc2dd1',
|
|
8
|
+
parent_generation_manifest_sha256:'df8ca9894a3e2ca9a9f145cfa3e4e23fd71f42c1988266a1591fc16261ab18a5'};
|
|
9
|
+
const valid=()=>({schema:'deadbyte.r43-windows-gate.v1',status:'passed',exit_code:0,version:'0.14.1',
|
|
10
|
+
marker:'DEADBYTE V0.14.1 / R43 AUTHORITY HARDENING WINDOWS BATCH GATE: PASS',manifest_sha256:manifest,
|
|
11
|
+
parent:{release_id:parent.parent_release_id,manifest_sha256:parent.parent_manifest_sha256,
|
|
12
|
+
generation_manifest_sha256:parent.parent_generation_manifest_sha256,
|
|
13
|
+
activation_receipt_sha256:'074140ad8b94501e0a095a7fa132dc5d6e2c57102c9eeaaa2ac9e4ea93b9b187'},
|
|
14
|
+
hardening:{authority_toctou:true,absolute_execution_deadline:true,pre_spawn_authority_recheck:true,
|
|
15
|
+
full_regression_required:true,model_path_changed:false}});
|
|
16
|
+
|
|
17
|
+
test('R43 detached finalizer requires explicit Process+Coding+Autonomous grants and keeps Desktop+Host disarmed',()=>{
|
|
18
|
+
assert.equal(validateFinalizerAuthorityStatus({
|
|
19
|
+
process_armed:true,coding_armed:true,autonomous_armed:true,desktop_armed:false,host_armed:false
|
|
20
|
+
}),true);
|
|
21
|
+
assert.throws(()=>validateFinalizerAuthorityStatus({
|
|
22
|
+
process_armed:false,coding_armed:true,autonomous_armed:true,desktop_armed:false,host_armed:false
|
|
23
|
+
}),/Process standing grant/);
|
|
24
|
+
assert.throws(()=>validateFinalizerAuthorityStatus({
|
|
25
|
+
process_armed:true,coding_armed:true,autonomous_armed:true,desktop_armed:false,host_armed:true
|
|
26
|
+
}),/Host DISARMED/);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test('R43 detached finalizer accepts only exact parent-bound hardening gate evidence',()=>{
|
|
30
|
+
assert.equal(validateWindowsGateEvidence(valid(),manifest,parent),true);
|
|
31
|
+
assert.throws(()=>validateWindowsGateEvidence({...valid(),manifest_sha256:'b'.repeat(64)},manifest,parent),/candidate mismatch/);
|
|
32
|
+
assert.throws(()=>validateWindowsGateEvidence({...valid(),hardening:{...valid().hardening,authority_toctou:false}},manifest,parent),/hardening contract/);
|
|
33
|
+
assert.throws(()=>validateWindowsGateEvidence({...valid(),parent:{...valid().parent,release_id:'v0.14.0-bad'}},manifest,parent),/parent mismatch/);
|
|
34
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { verifyR43Parent } from '../scripts/verify-r43-parent.mjs';
|
|
5
|
+
|
|
6
|
+
const root=new URL('../',import.meta.url);
|
|
7
|
+
|
|
8
|
+
test('R43 parent contract binds exact immutable R42 release and signed activation evidence', async()=>{
|
|
9
|
+
const record=JSON.parse(await readFile(new URL('../R43-PARENT.json',import.meta.url),'utf8'));
|
|
10
|
+
assert.equal(record.schema,'deadbyte.r43-parent.v1');
|
|
11
|
+
assert.equal(record.parent_release_id,'v0.14.0-08cd8f3b98c90e0e');
|
|
12
|
+
assert.equal(record.parent_version,'0.14.0');
|
|
13
|
+
assert.equal(record.parent_manifest_sha256,'08cd8f3b98c90e0e250cf506ff396515065ff5457909f850b75b0b6e8ecc2dd1');
|
|
14
|
+
assert.equal(record.parent_generation_manifest_sha256,'df8ca9894a3e2ca9a9f145cfa3e4e23fd71f42c1988266a1591fc16261ab18a5');
|
|
15
|
+
assert.equal(record.parent_manifest_file_count,1820);
|
|
16
|
+
assert.equal(record.parent_generation_file_count,7);
|
|
17
|
+
assert.equal(record.parent_final_closure_present,false);
|
|
18
|
+
const verified=await verifyR43Parent(new URL('../R43-PARENT.json',import.meta.url));
|
|
19
|
+
assert.equal(verified.status,'passed');
|
|
20
|
+
assert.equal(verified.release_files,1820);
|
|
21
|
+
assert.equal(verified.generation_files,7);
|
|
22
|
+
assert.equal(verified.parent_activation_receipt_sha256,'074140ad8b94501e0a095a7fa132dc5d6e2c57102c9eeaaa2ac9e4ea93b9b187');
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test('R43 parent record explicitly refuses to invent missing R42 final closure evidence', async()=>{
|
|
26
|
+
const record=JSON.parse(await readFile(new URL('../R43-PARENT.json',import.meta.url),'utf8'));
|
|
27
|
+
assert.equal(record.parent_final_closure_present,false);
|
|
28
|
+
assert.equal(Object.prototype.hasOwnProperty.call(record,'parent_final_closure_path'),false);
|
|
29
|
+
});
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { validateParityEvidence,R44_PREDECESSOR_RELEASE_ID,R44_PREDECESSOR_MANIFEST } from '../scripts/release-parity-r44.mjs';
|
|
5
|
+
import { verifyFinalClosureObject } from '../scripts/final-closure-verify-r44.mjs';
|
|
6
|
+
|
|
7
|
+
const root=new URL('../',import.meta.url);const text=rel=>readFile(new URL(rel,root),'utf8');
|
|
8
|
+
const featureGate=manifest=>({schema:'deadbyte.r44-windows-gate.v1',status:'passed',exit_code:0,version:'0.15.0',
|
|
9
|
+
marker:'DEADBYTE V0.15.0 / R44 REMOTE AGENT SKILL WINDOWS BATCH GATE: PASS',manifest_sha256:manifest,
|
|
10
|
+
features:{skill_integrity:true,agent_backend_persistence:true,codex_protocol_contract:true,remote_device_identity:true,
|
|
11
|
+
durable_job_supervisor:true,real_external_supervisor_smoke:true,full_regression_required:true,codex_live_binary_required:false}});
|
|
12
|
+
function parity(){
|
|
13
|
+
const manifest='a'.repeat(64),gate=featureGate(manifest);
|
|
14
|
+
const requirements=Object.fromEntries(['tree_read','precondition_mutation','search','owned_process','observation','coding_loop','autonomy',
|
|
15
|
+
'interrupted_recovery','evidence_verification','compact_closure','full_surface','desktop_readonly','desktop_guarded_input','deterministic_memory',
|
|
16
|
+
'skill_integrity','agent_backend_persistence','codex_protocol_contract','remote_device_identity','durable_job_supervisor','real_external_supervisor_smoke'].map(key=>[key,true]));
|
|
17
|
+
return {schema:'deadbyte.r44-parity.v1',status:'passed',execution_provider:'deadbyte_mcp',rdc_operation_count:0,
|
|
18
|
+
candidate:{release_id:`v0.15.0-${manifest.slice(0,16)}`,version:'0.15.0',manifest_sha256:manifest},
|
|
19
|
+
immutable_slot:{protected:true,release_root:'C:/immutable/r44',development_root:'D:/Projects/deadbyte-mcp/development/deadbyte-mcp-r42-agentic-dev'},
|
|
20
|
+
local_full:{status:'passed',tool_count:81,strict_output_schemas:true},
|
|
21
|
+
public_compact:{status:'passed',tool_count:43,capability_closure:true,gateway_count:6,skill_catalog_verified:true,
|
|
22
|
+
desktop_armed:false,desktop_observation_receipt_verified:true,desktop_grounding_receipt_verified:true},
|
|
23
|
+
autonomous:{status:'passed',signed_release_verified:true},desktop_guarded:{status:'passed',native_injected:true,replay_performed:false,
|
|
24
|
+
predispatch_retry_count:0,observation_receipts_verified:1,action_receipts_verified:3},
|
|
25
|
+
deterministic_memory:{status:'passed',goal_count:1,snapshot_count:1,index_count:1},
|
|
26
|
+
feature_gate:gate,feature_gate_sha256:'f'.repeat(64),
|
|
27
|
+
before_rollback_disarmed:{status:'passed',capability_closure:true,coding_armed:false,autonomous_armed:false,desktop_armed:false},
|
|
28
|
+
rollback:{state:'completed'},restore:{state:'completed'},stage_restore:{status:'restored',manifest_sha256:manifest},
|
|
29
|
+
predecessor:{release_id:R44_PREDECESSOR_RELEASE_ID,version:'0.14.1',manifest_sha256:R44_PREDECESSOR_MANIFEST},
|
|
30
|
+
predecessor_disarmed:{status:'passed',tool_count:42,capability_closure:true},
|
|
31
|
+
successor:{release_id:`v0.15.0-${manifest.slice(0,16)}`,version:'0.15.0',manifest_sha256:manifest},
|
|
32
|
+
successor_disarmed:{status:'passed',tool_count:43,capability_closure:true,skill_catalog_verified:true,coding_armed:false,autonomous_armed:false,desktop_armed:false},
|
|
33
|
+
requirements};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
test('R44 parity requires exact R43 predecessor, 81/43 surface and feature contract',()=>{
|
|
37
|
+
const value=parity();assert.equal(validateParityEvidence(value),true);
|
|
38
|
+
assert.throws(()=>validateParityEvidence({...value,predecessor:{...value.predecessor,manifest_sha256:'b'.repeat(64)}}),/predecessor/i);
|
|
39
|
+
assert.throws(()=>validateParityEvidence({...value,local_full:{...value.local_full,tool_count:80}}),/81-tool/i);
|
|
40
|
+
assert.throws(()=>validateParityEvidence({...value,public_compact:{...value.public_compact,tool_count:42}}),/compact/i);
|
|
41
|
+
assert.throws(()=>validateParityEvidence({...value,feature_gate:{...value.feature_gate,features:{...value.feature_gate.features,codex_protocol_contract:false}}}),/codex_protocol_contract/);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('R44 release machinery is isolated from R43 and binds 0.15.0 signed closure domains',async()=>{
|
|
45
|
+
const [gate,deferred,paritySource,writer,verifier,evidence,suite,finalizer,parent]=await Promise.all([
|
|
46
|
+
text('scripts/gate-windows-r44.ps1'),text('scripts/deferred-slot-operation-r44.mjs'),text('scripts/release-parity-r44.mjs'),
|
|
47
|
+
text('scripts/final-closure-r44.mjs'),text('scripts/final-closure-verify-r44.mjs'),text('scripts/windows-gate-evidence-r44.mjs'),
|
|
48
|
+
text('scripts/release-parity-tests-r44.ps1'),text('scripts/finalize-r44.mjs'),text('R44-PARENT.json')]);
|
|
49
|
+
assert.equal(R44_PREDECESSOR_RELEASE_ID,'v0.14.1-0a5a833892593283');
|
|
50
|
+
assert.equal(R44_PREDECESSOR_MANIFEST,'0a5a8338925932830986421dda60ec5643f62f600404de4992fda2a5e79d09a9');
|
|
51
|
+
assert.match(gate,/r44-parent-verify/);assert.match(gate,/r44:full:test/);assert.match(gate,/DEADBYTE V0\.15\.0 \/ R44 REMOTE AGENT SKILL WINDOWS BATCH GATE: PASS/);
|
|
52
|
+
assert.match(deferred,/--expected-version','0\.15\.0'/);assert.match(paritySource,/deadbyte\.r44-parity\.v1/);assert.match(paritySource,/tool_count===81/);assert.match(paritySource,/tool_count===43/);
|
|
53
|
+
for(const source of [writer,verifier]){assert.match(source,/DEADBYTE-R44-FINAL-CLOSURE-V1/);assert.match(source,/deadbyte\.r44-final-closure\.v1/);assert.match(source,/R44 REMOTE AGENT SKILL BASELINE/);}
|
|
54
|
+
assert.equal(typeof verifyFinalClosureObject,'function');assert.match(evidence,/deadbyte\.r44-windows-gate\.v1/);assert.match(evidence,/final_closure_sha256/);
|
|
55
|
+
assert.match(suite,/skill-plane-r44\.test\.mjs/);assert.match(suite,/codex-app-server-r44\.test\.mjs/);assert.match(suite,/external-job-provider-r44\.test\.mjs/);
|
|
56
|
+
assert.match(finalizer,/--restore-standing-grants/);assert.match(finalizer,/runReleaseParity/);assert.match(finalizer,/writeFinalClosure/);assert.match(finalizer,/verifyFinalClosureObject/);assert.match(finalizer,/--rollback-receipt/);
|
|
57
|
+
const parentRecord=JSON.parse(parent);assert.equal(parentRecord.parent_final_closure_sha256,'2f29e94dd726638c23b2e520a608dcf2a6919e43348855be3940599d557f920b');
|
|
58
|
+
});
|