deadbyte-mcp 0.15.50 → 0.15.52

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 (48) hide show
  1. package/MANIFEST.SHA256 +47 -17
  2. package/PROVENANCE.json +29 -11
  3. package/README.txt +18 -18
  4. package/RELEASE.json +392 -368
  5. package/SBOM.cdx.json +9 -4
  6. package/TEST-MATRIX.json +32 -2
  7. package/docs/R132-MANIFEST-PORTABILITY.md +23 -0
  8. package/docs/R135-AUTONOMOUS-SCOPE.md +21 -0
  9. package/docs/R136-SCOPED-OBSERVER.md +21 -0
  10. package/docs/R137-DESKTOP-COMMANDER-FOUNDATION.md +31 -0
  11. package/docs/R138-COMMANDER-WORKFLOW.md +21 -0
  12. package/docs/R139-COMMANDER-ERGONOMICS.md +17 -0
  13. package/docs/THIRD-PARTY-DESKTOP-COMMANDER-MIT.md +27 -0
  14. package/package.json +1 -1
  15. package/scripts/npm-prepublish-contract-r74.mjs +8 -2
  16. package/scripts/release-manifest.mjs +15 -1
  17. package/src/autonomous-scope-r135.mjs +91 -0
  18. package/src/commander-config-recovery-r137.mjs +67 -0
  19. package/src/commander-extended-runtime.mjs +22 -5
  20. package/src/commander-external-process-r48.mjs +25 -3
  21. package/src/commander-large-text-r139.mjs +66 -0
  22. package/src/commander-wire-adapter-r47.mjs +63 -12
  23. package/src/release-slot.mjs +13 -3
  24. package/src/scoped-observer-launcher-r136.mjs +77 -0
  25. package/src/scoped-observer-worker-r136.mjs +65 -0
  26. package/src/version.mjs +1 -1
  27. package/test/commander-wire-contract-r47.test.mjs +8 -5
  28. package/test/r130-release-security-contract.test.mjs +7 -7
  29. package/test/r131-installed-manifest-boundary.test.mjs +65 -0
  30. package/test/r132-release-identity.test.mjs +44 -0
  31. package/test/r135-autonomous-scope.test.mjs +103 -0
  32. package/test/r136-scoped-command-rights.test.mjs +39 -0
  33. package/test/r136-scoped-observer.test.mjs +89 -0
  34. package/test/r137-commander-config-recovery.test.mjs +111 -0
  35. package/test/r137-commander-three-version-contract.test.mjs +56 -0
  36. package/test/r138-commander-process-pagination.test.mjs +42 -0
  37. package/test/r138-commander-session-list.test.mjs +24 -0
  38. package/test/r138-commander-stream-resume.test.mjs +50 -0
  39. package/test/r139-large-text-edit.test.mjs +51 -0
  40. package/test/r139-large-text-read.test.mjs +46 -0
  41. package/test/r139-process-start-preview.test.mjs +50 -0
  42. package/test/r139-search-partial.test.mjs +42 -0
  43. package/test/r140-large-text-integrity.test.mjs +68 -0
  44. package/test/r141-commander-tail-utf8.test.mjs +55 -0
  45. package/test/r141-real-windows-disk.test.mjs +71 -0
  46. package/test/r142-native-machinefs-authority.test.mjs +127 -0
  47. package/test/r59-tool-surface-compat.test.mjs +1 -1
  48. package/test/r74-prepublish-contract.test.mjs +6 -4
@@ -0,0 +1,50 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {createCommanderWireAdapter} from '../src/commander-wire-adapter-r47.mjs';
4
+
5
+ function mock({output='hello from child\n',readThrows=false}={}){
6
+ const calls={reads:[],started:0};
7
+ const raw=Buffer.from(output,'utf8');
8
+ const runtime={
9
+ policy:{roots:{core:{real_path:'C:\\\\r139'}},profiles:{repl:{allow_raw_input:false}}},
10
+ async start(){calls.started++;return {child_pid:29139,session_id:'a'.repeat(64),state:'running'}},
11
+ async read(args){calls.reads.push(args);if(readThrows)throw new Error('read unavailable');
12
+ const at=args.offset??0;const chunk=raw.subarray(at,at+args.maxBytes);
13
+ return {offset:at,next_offset:at+chunk.length,earliest_offset:0,stream_head:raw.length,
14
+ state:'exited',exit_code:0,data_base64:chunk.toString('base64')};},
15
+ };
16
+ return {runtime,calls};
17
+ }
18
+ async function invoke(f){
19
+ const oldProfile=process.env.DEADBYTE_COMMANDER_COMPAT_PROFILE;
20
+ const oldRoot=process.env.DEADBYTE_COMMANDER_COMPAT_ROOT;
21
+ process.env.DEADBYTE_COMMANDER_COMPAT_PROFILE='repl';
22
+ process.env.DEADBYTE_COMMANDER_COMPAT_ROOT='core';
23
+ try{
24
+ const a=createCommanderWireAdapter({processRuntime:f.runtime});
25
+ return await a.handlers.start_process({command:'echo sample',timeout_ms:1000});
26
+ }finally{
27
+ if(oldProfile===undefined)delete process.env.DEADBYTE_COMMANDER_COMPAT_PROFILE;
28
+ else process.env.DEADBYTE_COMMANDER_COMPAT_PROFILE=oldProfile;
29
+ if(oldRoot===undefined)delete process.env.DEADBYTE_COMMANDER_COMPAT_ROOT;
30
+ else process.env.DEADBYTE_COMMANDER_COMPAT_ROOT=oldRoot;
31
+ }
32
+ }
33
+ test('R139 start_process returns already-ready output preview without waiting or consuming output cursor',async()=>{
34
+ const f=mock();const res=await invoke(f);
35
+ assert.equal(res.structuredContent.pid,29139);
36
+ assert.equal(res.structuredContent.initial_output,'hello from child\n');
37
+ assert.equal(res.structuredContent.initial_output_truncated,false);
38
+ assert.match(res.content[0].text,/hello from child/);
39
+ assert.equal(f.calls.reads.length,1);
40
+ assert.equal(f.calls.reads[0].waitMs,0);
41
+ assert.equal(f.calls.reads[0].offset,0);
42
+ assert.ok(f.calls.reads[0].maxBytes<=16384);
43
+ });
44
+ test('R139 start_process preserves started session if quick output probe fails',async()=>{
45
+ const f=mock({readThrows:true});const res=await invoke(f);
46
+ assert.equal(f.calls.started,1);
47
+ assert.equal(res.structuredContent.pid,29139);
48
+ assert.equal(res.structuredContent.initial_output,'');
49
+ assert.equal(res.structuredContent.output_preview_unavailable,true);
50
+ });
@@ -0,0 +1,42 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {createCommanderWireAdapter} from '../src/commander-wire-adapter-r47.mjs';
4
+
5
+ const root='D:\\R139-SEARCH';
6
+ const mockFs={policy:{roots:{core:{real_path:root}}}};
7
+ const pause=()=>new Promise(resolve=>setImmediate(resolve));
8
+
9
+ test('R139 search returns the completed first page while later pages are still running',async()=>{
10
+ let resume,entered=false,calls=0;
11
+ const block=new Promise(r=>resume=r);
12
+ const adapter=createCommanderWireAdapter({machineFsRuntime:mockFs,searchRuntime:async args=>{
13
+ calls++;
14
+ if(calls===1)return {matches:[{path:'one.txt',line:1,preview:'alpha'}],next_cursor:'page-2'};
15
+ entered=true;await block;
16
+ return {matches:[{path:'two.txt',line:2,preview:'alpha'}],next_cursor:null};
17
+ }});
18
+ const started=await adapter.handlers.start_search({path:root,pattern:'alpha',searchType:'content',ignoreCase:true});
19
+ try{
20
+ for(let i=0;i<20&&!entered;i++)await pause();
21
+ assert.equal(entered,true);
22
+ const partial=await adapter.handlers.get_more_search_results({sessionId:started.sessionId,offset:0,length:10});
23
+ assert.deepEqual(partial.results.map(x=>x.file),['one.txt']);
24
+ assert.equal(partial.isComplete,false);
25
+ assert.equal(partial.totalResults,1);
26
+ assert.equal(partial.hasMoreResults,true);
27
+ resume();
28
+ for(let i=0;i<20;i++){await pause();const done=await adapter.handlers.get_more_search_results({sessionId:started.sessionId,offset:0,length:10});if(done.isComplete){assert.deepEqual(done.results.map(x=>x.file),['one.txt','two.txt']);return;}}
29
+ assert.fail('search did not complete after second page released');
30
+ }finally{resume();}
31
+ });
32
+
33
+ test('R139 completed search returns cached page immediately without another runtime search',async()=>{
34
+ let calls=0;
35
+ const adapter=createCommanderWireAdapter({machineFsRuntime:mockFs,searchRuntime:async()=>{calls++;return {matches:[{path:'matched.txt',line:1,preview:'ok'}],next_cursor:null};}});
36
+ const start=await adapter.handlers.start_search({path:root,pattern:'matched',searchType:'files'});
37
+ let done;
38
+ for(let i=0;i<20;i++){await pause();done=await adapter.handlers.get_more_search_results({sessionId:start.sessionId,offset:0,length:10});if(done.isComplete)break;}
39
+ assert.equal(done.isComplete,true);
40
+ assert.equal(done.results[0].file,'matched.txt');
41
+ assert.equal(calls,1);
42
+ });
@@ -0,0 +1,68 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { createHash } from 'node:crypto';
4
+ import { readCommanderLargeText } from '../src/commander-large-text-r139.mjs';
5
+
6
+ const sha = bytes => createHash('sha256').update(bytes).digest('hex');
7
+ const source = Buffer.from(('line-000000: '+'.'.repeat(85)+'\r\n').repeat(60000), 'utf8');
8
+
9
+ function native(initial, mutate = null) {
10
+ let bytes = Buffer.from(initial), reads = 0, fullHashes = 0;
11
+ return {
12
+ policy: {max_read_bytes: 256*1024},
13
+ get counts() { return {reads, fullHashes}; },
14
+ async read({offset, maxBytes, hashFile}) {
15
+ reads++;
16
+ if(mutate) bytes = mutate(bytes, reads) ?? bytes;
17
+ const part = bytes.subarray(offset, offset + maxBytes);
18
+ if(hashFile) fullHashes++;
19
+ return {offset, next_offset: offset + part.length,
20
+ data_base64:part.toString('base64'), eof:offset + part.length >= bytes.length,
21
+ file_size:bytes.length, file_sha256:hashFile ? sha(bytes) : null};
22
+ }
23
+ };
24
+ }
25
+
26
+ test('R140 large file hashes once, checks whole delivered stream, and preserves page semantics', async () => {
27
+ assert.ok(source.length > 4*1024*1024);
28
+ const runtime = native(source);
29
+ const result = await readCommanderLargeText({runtime, rootId:'core',
30
+ relativePath:'large.txt', offset:59997, length:3});
31
+ assert.equal(result.fileSha256, sha(source));
32
+ assert.equal(result.totalLines, 60001);
33
+ assert.equal(result.lineOffset, 59997);
34
+ assert.equal(result.lineCount, 3);
35
+ assert.equal(result.content, ('line-000000: '+'.'.repeat(85)+'\n').repeat(3));
36
+ assert.equal(runtime.counts.fullHashes, 1, 'must not rehash whole file per chunk');
37
+ assert.ok(runtime.counts.reads > 2);
38
+ });
39
+
40
+ test('R140 detects same-length mutation of bytes already delivered across page boundary', async () => {
41
+ const runtime = native(source, (bytes, readNumber) => {
42
+ if(readNumber === 3) { const changed=Buffer.from(bytes); changed[40]^=1; return changed; }
43
+ });
44
+ await assert.rejects(readCommanderLargeText({runtime,rootId:'core',
45
+ relativePath:'large.txt',offset:59000,length:2}), /changed during paged read|identity mismatch/);
46
+ assert.equal(runtime.counts.fullHashes,1);
47
+ });
48
+
49
+ test('R140 detects same-length mutation immediately before closing hash', async () => {
50
+ const expectedChunks = Math.ceil(source.length / (256*1024));
51
+ const runtime = native(source, (bytes, readNumber) => {
52
+ if(readNumber === expectedChunks+1) { const changed=Buffer.from(bytes); changed[2]^=1; return changed; }
53
+ });
54
+ await assert.rejects(readCommanderLargeText({runtime,rootId:'core',
55
+ relativePath:'large.txt',offset:59999,length:1}), /changed during paged read|identity mismatch/);
56
+ });
57
+
58
+ test('R140 rejects untrusted or absent closing SHA-256 identity', async () => {
59
+ const runtime = native(source);
60
+ const original=runtime.read.bind(runtime);
61
+ runtime.read = async args => {
62
+ const result=await original(args);
63
+ if(args.hashFile) result.file_sha256=null;
64
+ return result;
65
+ };
66
+ await assert.rejects(readCommanderLargeText({runtime,rootId:'core',
67
+ relativePath:'large.txt',offset:1,length:1}), /identity missing/);
68
+ });
@@ -0,0 +1,55 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {createCommanderWireAdapter} from '../src/commander-wire-adapter-r47.mjs';
4
+
5
+ const PATH='D:\\R141-TAIL\\log.txt';
6
+ function fixture(data,{maxRead=64,tailFileOffset=null}={}){
7
+ const bytes=Buffer.from(data); let reads=0;
8
+ const fs={
9
+ policy:{roots:{core:{real_path:'D:\\R141-TAIL'}},max_read_bytes:maxRead},
10
+ async read({offset=0,maxBytes,hashFile=false}){
11
+ reads++;
12
+ const at=offset<0?Math.max(0,bytes.length+offset):offset;
13
+ const part=bytes.subarray(at,at+maxBytes);
14
+ return {status:'ok',offset:at,next_offset:at+part.length,
15
+ file_size:bytes.length,eof:at+part.length>=bytes.length,
16
+ file_sha256:null,data_base64:part.toString('base64')};
17
+ }
18
+ };
19
+ return {fs,reads:()=>reads};
20
+ }
21
+ test('R141 negative tail rejects invalid UTF-8 instead of silently introducing replacement characters', async()=>{
22
+ const runtime=fixture(Buffer.concat([Buffer.from('ok\ninvalid '),Buffer.from([0xc3,0x28]),Buffer.from('\n')]));
23
+ const api=createCommanderWireAdapter({machineFsRuntime:runtime.fs});
24
+ await assert.rejects(api.handlers.read_file({path:PATH,offset:-1}),/valid UTF-8|UTF-8/);
25
+ });
26
+ test('R141 negative tail rejects embedded NUL just like positive text detection',async()=>{
27
+ const runtime=fixture(Buffer.from('ok\ntail\0broken\n'));
28
+ const api=createCommanderWireAdapter({machineFsRuntime:runtime.fs});
29
+ await assert.rejects(api.handlers.read_file({path:PATH,offset:-1}),/NUL|binary/);
30
+ });
31
+ test('R141 negative tail does not decode the leading partial UTF-8 line',async()=>{
32
+ const prefix=Buffer.from('prefix '+('x'.repeat(18))+'é-not-selected\n');
33
+ const bytes=Buffer.concat([prefix,Buffer.from('valid-一\nlast-€\n')]);
34
+ const tailLen=bytes.length-(prefix.indexOf(Buffer.from('é'))+1);
35
+ const runtime=fixture(bytes,{maxRead:tailLen});
36
+ const api=createCommanderWireAdapter({machineFsRuntime:runtime.fs});
37
+ const result=await api.handlers.read_file({path:PATH,offset:-2});
38
+ assert.equal(result.content[0].text,'valid-一\nlast-€');
39
+ assert.equal(result.structuredContent.tailByteOffset,bytes.length-tailLen);
40
+ });
41
+ test('R141 tail decodes intact multibyte UTF-8 CRLF lines',async()=>{
42
+ const runtime=fixture(Buffer.from('old\r\n漢字\r\nterminus €\r\n'));
43
+ const api=createCommanderWireAdapter({machineFsRuntime:runtime.fs});
44
+ const result=await api.handlers.read_file({path:PATH,offset:-2});
45
+ assert.equal(result.content[0].text,'漢字\nterminus €');
46
+ assert.equal(result.structuredContent.lineCount,2);
47
+ });
48
+
49
+ test('R141 keeps a complete first line when the bounded tail begins exactly at a line boundary',async()=>{
50
+ const source=Buffer.from('header!\nlast-1\nlast-2\n');
51
+ const runtime=fixture(source,{maxRead:14});
52
+ const api=createCommanderWireAdapter({machineFsRuntime:runtime.fs});
53
+ const result=await api.handlers.read_file({path:PATH,offset:-2});
54
+ assert.equal(result.content[0].text,'last-1\nlast-2');
55
+ });
@@ -0,0 +1,71 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {createHash} from 'node:crypto';
4
+ import {mkdtemp,readFile,writeFile,open,rm} from 'node:fs/promises';
5
+ import {tmpdir} from 'node:os';
6
+ import {join} from 'node:path';
7
+ import {spawnSync} from 'node:child_process';
8
+ import {readCommanderLargeText} from '../src/commander-large-text-r139.mjs';
9
+
10
+ const sha = bytes => createHash('sha256').update(bytes).digest('hex');
11
+ const source=Buffer.from(('deadbyte-0123456789-'+'.'.repeat(87)+'\r\n').repeat(52000));
12
+ assert.ok(source.length > 5*1024*1024);
13
+
14
+ async function withFixture(fn){
15
+ const dir=await mkdtemp(join(tmpdir(),'deadbyte-r141-real-io-'));
16
+ const file=join(dir,'test.log');
17
+ await writeFile(file,source);
18
+ try { await fn(file); } finally { await rm(dir,{recursive:true,force:true}); }
19
+ }
20
+ function diskRuntime(file,{mutateAt=Infinity}={}){
21
+ let reads=0,hashed=0;
22
+ return {
23
+ policy:{max_read_bytes:256*1024},
24
+ get calls(){return {reads,hashed};},
25
+ async read({offset,maxBytes,hashFile=false}){
26
+ reads++;
27
+ if(reads===mutateAt){
28
+ const command='const fs=require("fs");const f=process.argv[1];const fd=fs.openSync(f,"r+");const b=Buffer.from([0x58]);fs.writeSync(fd,b,0,1,3);fs.fsyncSync(fd);fs.closeSync(fd)';
29
+ const child=spawnSync(process.execPath,['-e',command,file],{windowsHide:true});
30
+ assert.equal(child.status,0,child.stderr?.toString());
31
+ }
32
+ const h=await open(file,'r');
33
+ let n=0,part=Buffer.alloc(maxBytes);
34
+ try { ({bytesRead:n}=await h.read(part,0,maxBytes,offset)); } finally {await h.close();}
35
+ part=part.subarray(0,n);
36
+ const current=await readFile(file);
37
+ let fileSha256=null;
38
+ if(hashFile){hashed++;fileSha256=sha(current);}
39
+ return {offset,next_offset:offset+n,file_size:current.length,
40
+ eof:offset+n>=current.length,data_base64:part.toString('base64'),file_sha256:fileSha256};
41
+ }
42
+ };
43
+ }
44
+ test('R141 5MiB+ physical Windows filesystem read matches independent file digest',async()=>{
45
+ await withFixture(async file=>{
46
+ const runtime=diskRuntime(file);
47
+ const result=await readCommanderLargeText({runtime,rootId:'core',relativePath:file,offset:51998,length:2});
48
+ assert.equal(result.fileSha256,sha(await readFile(file)));
49
+ assert.equal(result.totalLines,52001);
50
+ assert.equal(result.lineCount,2);
51
+ assert.equal(runtime.calls.hashed,1);
52
+ assert.ok(runtime.calls.reads>20);
53
+ });
54
+ });
55
+ test('R141 cross-process same-size on-disk mutation between pages fails closed',async()=>{
56
+ await withFixture(async file=>{
57
+ const before=sha(await readFile(file));
58
+ const runtime=diskRuntime(file,{mutateAt:4});
59
+ await assert.rejects(readCommanderLargeText({runtime,rootId:'core',relativePath:file,offset:51998,length:2}),/identity mismatch/);
60
+ assert.notEqual(sha(await readFile(file)),before);
61
+ assert.equal(runtime.calls.hashed,1);
62
+ });
63
+ });
64
+ test('R141 cross-process late mutation before native closing hash fails closed',async()=>{
65
+ await withFixture(async file=>{
66
+ const pages=Math.ceil(source.length/(256*1024));
67
+ const runtime=diskRuntime(file,{mutateAt:pages+1});
68
+ await assert.rejects(readCommanderLargeText({runtime,rootId:'core',relativePath:file,offset:51998,length:2}),/identity mismatch/);
69
+ assert.equal(runtime.calls.hashed,1);
70
+ });
71
+ });
@@ -0,0 +1,127 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { createHash } from 'node:crypto';
4
+ import { spawnSync } from 'node:child_process';
5
+ import { mkdtemp, mkdir, writeFile, readFile, rm } from 'node:fs/promises';
6
+ import os from 'node:os';
7
+ import path from 'node:path';
8
+ import { generateTrustKeypair } from '../src/trust.mjs';
9
+ import { loadCodingPolicy } from '../src/coding-plane.mjs';
10
+ import { createMachineFsRuntime } from '../src/machine-fs.mjs';
11
+ import { writeBoundStandingGrant } from './r65-authority-fixture.mjs';
12
+ import { readCommanderLargeText } from '../src/commander-large-text-r139.mjs';
13
+
14
+ const digest = bytes => createHash('sha256').update(bytes).digest('hex');
15
+ const line = 'R142-EVIDENCE:' + '.'.repeat(95) + '\r\n';
16
+ const bytes = Buffer.from(line.repeat(50000));
17
+ assert.ok(bytes.length > 5 * 1024 * 1024);
18
+
19
+ async function isolatedFixture({grant=true,read=true}={}) {
20
+ const state = await mkdtemp(path.join(os.tmpdir(), 'deadbyte-r142-authority-'));
21
+ const project = path.join(state,'project');
22
+ await mkdir(project);
23
+ const file = path.join(project,'large.log');
24
+ await writeFile(file,bytes);
25
+ const policyFile = path.join(state,'coding-policy.json');
26
+ const leaseFile = path.join(state,'runtime','coding-grant.json');
27
+ await writeFile(policyFile, JSON.stringify({
28
+ schema:'deadbyte.coding-policy.v1',enabled:true,
29
+ lease_file:leaseFile,evidence_dir:path.join(state,'evidence'),
30
+ roots:{project:{path:project,read,write:false,exec:false,deny_paths:[]}},
31
+ commands:{},max_read_bytes:262144,max_write_bytes:65536
32
+ }));
33
+ const policy = await loadCodingPolicy(policyFile);
34
+ if(grant) await writeBoundStandingGrant('coding', leaseFile, {
35
+ schema:'deadbyte.coding-grant.v2',policy_sha256:policy.policy_sha256,
36
+ instance_nonce:'c'.repeat(64),root_ids:['project'],granted_at_utc:new Date().toISOString()
37
+ });
38
+ const keys = await generateTrustKeypair({
39
+ privateKeyPath:path.join(state,'private.pem'),publicKeyPath:path.join(state,'public.pem')
40
+ });
41
+ return {state,file,policy,keys,runtime:createMachineFsRuntime({
42
+ policy,signingKeyPath:keys.privateKeyPath,verifyKeyPath:keys.publicKeyPath
43
+ })};
44
+ }
45
+
46
+ function modifyViaOtherProcess(file) {
47
+ const script = 'const fs=require("node:fs");const fd=fs.openSync(process.argv[1],"r+");' +
48
+ 'const n=Buffer.from("X");fs.writeSync(fd,n,0,1,14);fs.fsyncSync(fd);fs.closeSync(fd)';
49
+ const child = spawnSync(process.execPath,['-e',script,file],{
50
+ windowsHide:true,encoding:'utf8',timeout:15000
51
+ });
52
+ assert.equal(child.status,0,child.stderr || String(child.error));
53
+ }
54
+
55
+ function instrument(real,file,{mutateCall=Infinity}={}) {
56
+ let reads=0,hashRequests=0;
57
+ return {
58
+ policy:real.policy,
59
+ counters:()=>({reads,hashRequests}),
60
+ async read(args){
61
+ reads++;
62
+ if(reads===mutateCall) modifyViaOtherProcess(file);
63
+ if(args.hashFile) hashRequests++;
64
+ return real.read(args);
65
+ }
66
+ };
67
+ }
68
+
69
+ test('R142 real MachineFS signed isolated read authority, native pages and final SHA',async()=>{
70
+ const f=await isolatedFixture();
71
+ try {
72
+ const runtime=instrument(f.runtime,f.file);
73
+ const result=await readCommanderLargeText({
74
+ runtime,rootId:'project',relativePath:'large.log',offset:49998,length:2
75
+ });
76
+ assert.equal(result.fileSha256,digest(await readFile(f.file)));
77
+ assert.equal(result.bytesScanned,bytes.length);
78
+ assert.equal(result.totalLines,50001);
79
+ assert.equal(result.lineCount,2);
80
+ assert.equal(runtime.counters().hashRequests,1);
81
+ assert.ok(runtime.counters().reads>20);
82
+ } finally {await rm(f.state,{recursive:true,force:true});}
83
+ });
84
+
85
+ test('R142 real MachineFS detects same-size concurrent child writer before an intermediate page',async()=>{
86
+ const f=await isolatedFixture();
87
+ try {
88
+ const runtime=instrument(f.runtime,f.file,{mutateCall:4});
89
+ await assert.rejects(readCommanderLargeText({
90
+ runtime,rootId:'project',relativePath:'large.log',offset:49998,length:2
91
+ }),/large text file changed during paged read: identity mismatch/);
92
+ assert.notEqual(digest(await readFile(f.file)),digest(bytes));
93
+ assert.equal(runtime.counters().hashRequests,1);
94
+ } finally {await rm(f.state,{recursive:true,force:true});}
95
+ });
96
+
97
+ test('R142 real MachineFS detects same-size child writer just before closing hash',async()=>{
98
+ const f=await isolatedFixture();
99
+ try {
100
+ const chunks=Math.ceil(bytes.length/262144);
101
+ const runtime=instrument(f.runtime,f.file,{mutateCall:chunks+1});
102
+ await assert.rejects(readCommanderLargeText({
103
+ runtime,rootId:'project',relativePath:'large.log',offset:49998,length:2
104
+ }),/large text file changed during paged read: identity mismatch/);
105
+ assert.equal(runtime.counters().hashRequests,1);
106
+ } finally {await rm(f.state,{recursive:true,force:true});}
107
+ });
108
+
109
+ test('R142 real MachineFS rejects reads denied by isolated root policy even when disarmed',async()=>{
110
+ const f=await isolatedFixture({grant:false,read:false});
111
+ try {
112
+ await assert.rejects(readCommanderLargeText({
113
+ runtime:f.runtime,rootId:'project',relativePath:'large.log',offset:0,length:1
114
+ }),/does not allow read/i);
115
+ } finally {await rm(f.state,{recursive:true,force:true});}
116
+ });
117
+
118
+ test('R142 disarmed MachineFS permits explicitly policy-authorized read-only access',async()=>{
119
+ const f=await isolatedFixture({grant:false,read:true});
120
+ try {
121
+ const one=await f.runtime.read({rootId:'project',relativePath:'large.log',offset:0,maxBytes:64,hashFile:false});
122
+ assert.equal(Buffer.from(one.data_base64,'base64').toString('utf8'),bytes.subarray(0,64).toString('utf8'));
123
+ await assert.rejects(f.runtime.write({
124
+ rootId:'project',relativePath:'no-write.txt',content:'x',expectedSha256:'absent'
125
+ }),/disarmed|does not allow write|authority/i);
126
+ } finally {await rm(f.state,{recursive:true,force:true});}
127
+ });
@@ -83,7 +83,7 @@ test('R72 compact baseline permits only R64 read offset and authorized coding-on
83
83
  assert.deepEqual(diff.added,[]);
84
84
  assert.deepEqual(diff.removed,[]);
85
85
  const packageVersion=JSON.parse(await readFile(path.join(repoRoot,'package.json'),'utf8')).version;
86
- if(['0.15.41','0.15.42','0.15.43','0.15.44','0.15.45','0.15.46','0.15.47','0.15.48','0.15.49','0.15.50'].includes(packageVersion)){
86
+ if(['0.15.41','0.15.42','0.15.43','0.15.44','0.15.45','0.15.46','0.15.47','0.15.48','0.15.49','0.15.50','0.15.51','0.15.52'].includes(packageVersion)){
87
87
  assert.deepEqual([...diff.schema_changed].sort(),['machine_fs','native_diff_preview']);
88
88
  assert.equal(diff.unchanged.length,41);
89
89
  const prior=baseline.tools.find(tool=>tool.name==='machine_fs');
@@ -9,7 +9,9 @@ import {verifyR74PrepublishContract} from '../scripts/npm-prepublish-contract-r7
9
9
  const repoRoot = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
10
10
 
11
11
  test('R74 prepublish contract: positive path succeeds and verifies identities', async () => {
12
- const result = await verifyR74PrepublishContract({rootPath: repoRoot});
12
+ const manifestVerification = process.env.DEADBYTE_TEST_PROTECTED_MANIFEST === 'installed' ? 'installed' : 'source';
13
+ const result = await verifyR74PrepublishContract({rootPath: repoRoot, manifestVerification});
14
+ assert.equal(result.checks.manifest_verification_mode, manifestVerification);
13
15
  assert.equal(result.schema, 'deadbyte.r74-prepublish-contract.v1');
14
16
  assert.equal(result.valid, true);
15
17
  assert.equal(result.checks.predecessors_distinct, true);
@@ -18,9 +20,9 @@ test('R74 prepublish contract: positive path succeeds and verifies identities',
18
20
  assert.equal(result.checks.package_leak_check.ok, true);
19
21
  assert.equal(result.checks.no_self_referential_tarball_hash, true);
20
22
  assert.equal(result.identities.package_name, 'deadbyte-mcp');
21
- // This R74 component contract remains scoped to train R74, even when
22
- // the containing npm package is the R130 0.15.50 security candidate.
23
- assert.equal(result.identities.package_version, '0.15.50');
23
+ // R74 component contract retains its train-specific source and predecessor assertions;
24
+ // the containing R143 package must report its actual immutable package version.
25
+ assert.equal(result.identities.package_version, '0.15.52');
24
26
  assert.equal(result.identities.target_train, 'R74');
25
27
  assert.equal(result.identities.published_source_predecessor, '0.15.46');
26
28
  assert.notEqual(result.identities.published_source_predecessor, result.identities.runtime_predecessor);