deadbyte-mcp 0.15.60 → 0.15.62

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 (91) hide show
  1. package/MANIFEST.SHA256 +90 -42
  2. package/PROVENANCE.json +33 -14
  3. package/README.txt +18 -18
  4. package/RELEASE.json +45 -16
  5. package/SBOM.cdx.json +2 -2
  6. package/TEST-MATRIX.json +24 -2
  7. package/bridge/package.json +1 -1
  8. package/controller/deadbyte-controller.ps1 +78 -1
  9. package/controller/deadbyte-process-policy.json +4 -4
  10. package/docs/R156-LOOP-AND-EPOCH-ROUTING.md +86 -0
  11. package/docs/R157-ARCHITECTURE-DEPENDENCIES.md +58 -0
  12. package/docs/R157-ARCHITECTURE-GRAPH.json +2874 -0
  13. package/docs/R157-ENGINEERING-HANDOFF.md +71 -0
  14. package/docs/R157-FILE-DELTA.json +80 -0
  15. package/docs/R157-FOCUSED-VERIFICATION.log +0 -0
  16. package/docs/R157-REFERENCE-CAPABILITY-MATRIX.md +207 -0
  17. package/docs/R157-REFERENCE-DECISIONS.md +46 -0
  18. package/docs/R157-REFERENCE-INVENTORY.json +2849 -0
  19. package/docs/R158-COMBINED-REGRESSION.log +0 -0
  20. package/docs/R158-DELTA.json +80 -0
  21. package/docs/R158-EPOCH-BOOTSTRAP-GREEN.log +0 -0
  22. package/docs/R158-EPOCH-BOOTSTRAP-RED.log +0 -0
  23. package/docs/R158-EPOCH-IDENTITY-RED.log +0 -0
  24. package/docs/R158-FOCUSED-GREEN.log +0 -0
  25. package/docs/R158-PROTECTED-EPOCH-VERIFIED.md +43 -0
  26. package/docs/R158-PROTECTED-EXACT-SOURCE-LIVE.log +0 -0
  27. package/docs/R158-UPDATER-REGRESSION.log +0 -0
  28. package/docs/R159-COMPLETED-HISTORY-BACKUP/deadbyte-cli.mjs.before +965 -0
  29. package/docs/R159-COMPLETED-HISTORY-BACKUP/legacy-marker-evidence-r159.mjs.before +102 -0
  30. package/docs/R159-COMPLETED-HISTORY-BACKUP/r159-legacy-marker-evidence.test.mjs.before +79 -0
  31. package/docs/R159-COMPLETED-HISTORY-PATCH.json +26 -0
  32. package/docs/R159-MARKER-LOCATOR-CHECKPOINT.md +46 -0
  33. package/docs/R160-ENGINEERING-HANDOFF.md +32 -0
  34. package/docs/R160-REFERENCE-CAPABILITY-MATRIX.json +165 -0
  35. package/package.json +2 -2
  36. package/scripts/bootstrap-uac-migration-r153.ps1 +17 -5
  37. package/scripts/deploy-r48.mjs +7 -6
  38. package/scripts/gate-windows-r160.ps1 +57 -0
  39. package/scripts/issue-uac-migration-r153.mjs +12 -5
  40. package/scripts/npm-release-r48.mjs +5 -0
  41. package/scripts/npm-release-readiness-r163.mjs +67 -0
  42. package/scripts/r153-prepublish-identity.mjs +3 -3
  43. package/scripts/request-uac-migration-r153.ps1 +17 -4
  44. package/scripts/verify-protected-stage-r153.mjs +1 -0
  45. package/src/autonomous-supervisor.mjs +21 -4
  46. package/src/clean-activation-recovery-r153.mjs +1 -1
  47. package/src/deadbyte-cli.mjs +83 -60
  48. package/src/host-command-pins-r154.mjs +34 -0
  49. package/src/legacy-marker-evidence-r159.mjs +128 -0
  50. package/src/package-identity-r160.mjs +61 -0
  51. package/src/release-generation.mjs +13 -0
  52. package/src/release-slot.mjs +2 -1
  53. package/src/remote-live-log.mjs +30 -2
  54. package/src/runtime-update.mjs +18 -6
  55. package/src/trusted-epoch-bootstrap-r158.mjs +42 -0
  56. package/src/uac-approval-contract-r153.mjs +6 -3
  57. package/src/version.mjs +1 -1
  58. package/src/windows-powershell-environment.mjs +5 -2
  59. package/test/r106-trusted-powershell-spawn.test.mjs +1 -0
  60. package/test/r130-release-security-contract.test.mjs +9 -9
  61. package/test/r132-release-identity.test.mjs +8 -10
  62. package/test/r153-clean-activation-recovery.test.mjs +2 -2
  63. package/test/r153-prepublish-identity.test.mjs +26 -5
  64. package/test/r153-r65-signed-precondition-recovery.test.mjs +2 -2
  65. package/test/r153-staging-leaf-acl.test.mjs +24 -10
  66. package/test/r153-uac-approval-contract.test.mjs +5 -3
  67. package/test/r153-uac-launch-parameter-contract.test.mjs +1 -1
  68. package/test/r154-multipin-recovery.test.mjs +45 -0
  69. package/test/r155-commander-live-log.test.mjs +44 -0
  70. package/test/r155-default-live-log.test.mjs +89 -0
  71. package/test/r156-epoch-route-smoke.ps1 +48 -0
  72. package/test/r156-supervisor-pacing.test.mjs +59 -0
  73. package/test/r157-architecture-map.mjs +61 -0
  74. package/test/r157-reference-survey.mjs +91 -0
  75. package/test/r157-supervisor-singleflight.test.mjs +32 -0
  76. package/test/r158-epoch-bootstrap.test.mjs +34 -0
  77. package/test/r159-legacy-marker-evidence.test.mjs +100 -0
  78. package/test/r159-legacy-marker-evidence.test.mjs.before-assertion-fix-20261025-120246.bak +100 -0
  79. package/test/r160-marker-proof.test.mjs +87 -0
  80. package/test/r160-package-decision-manifest.test.mjs +67 -0
  81. package/test/r160-release-contract.test.mjs +30 -0
  82. package/test/r160-stable-launcher.test.mjs +10 -0
  83. package/test/r163-isolated-slot-rollback-restore.test.mjs +58 -0
  84. package/test/r163-publish-fence.test.mjs +13 -0
  85. package/test/r48-release-contract.test.mjs +7 -1
  86. package/test/r58-launcher-shell.test.mjs +4 -1
  87. package/test/r59-tool-surface-compat.test.mjs +1 -1
  88. package/test/release-generation.test.mjs +16 -0
  89. package/test/remote-live-log-r37.test.mjs +5 -3
  90. package/test/remote-session-cli.test.mjs +11 -11
  91. package/test/stabilization-state-root.test.mjs +2 -1
@@ -0,0 +1,87 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {mkdtemp,mkdir,writeFile,readFile,rm} from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import os from 'node:os';
6
+ import {createHash} from 'node:crypto';
7
+ import {
8
+ selectLegacyMarkerEvidence,
9
+ verifyLocatedLegacyMarkerReceipt
10
+ } from '../src/legacy-marker-evidence-r159.mjs';
11
+ import {createMarkerReconciliationReceipt} from '../src/clean-activation-recovery-r153.mjs';
12
+ import {canonicalJson} from '../src/canonical-json.mjs';
13
+
14
+ const digest=bytes=>createHash('sha256').update(bytes).digest('hex');
15
+ const id=value=>value.repeat(64);
16
+ const pointer=Object.freeze({
17
+ release_id:'v0.15.61-CURRENT',version:'0.15.61',
18
+ manifest_sha256:id('1'),generation_manifest_sha256:id('2')
19
+ });
20
+ const policySha256=Object.freeze({
21
+ process:id('3'),coding:id('4'),autonomous:id('5'),desktop:id('6'),host:id('7')
22
+ });
23
+ const authority=Object.freeze({process:false,coding:false,autonomous:false,desktop:false,host:false});
24
+ const proofFor=(markerSha256,policies=policySha256)=>digest(Buffer.from(canonicalJson({
25
+ pointer,policy_sha256:policies,marker_sha256:markerSha256,authority
26
+ }),'utf8'));
27
+
28
+ async function locatedFixture(t,{tamper}={}){
29
+ const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r160-located-'));
30
+ const evidenceDir=path.join(root,'legacy-migration');
31
+ await mkdir(evidenceDir);
32
+ t.after(()=>rm(root,{recursive:true,force:true}));
33
+ const markerSha256=id('a'),intentSha256=id('b');
34
+ const receipt=createMarkerReconciliationReceipt({
35
+ pointer,policySha256,markerSha256,
36
+ proofSha256:proofFor(markerSha256),
37
+ observedAtUtc:'2026-10-25T00:00:00.000Z',intentSha256
38
+ });
39
+ const terminal=tamper?tamper({...receipt}):receipt;
40
+ const terminalPath=path.join(evidenceDir,`marker-${markerSha256}.terminal.json`);
41
+ const terminalBytes=Buffer.from(`${JSON.stringify(terminal)}\n`,'utf8');
42
+ await writeFile(terminalPath,terminalBytes);
43
+ await writeFile(path.join(evidenceDir,'r153-pending-migration.json'),`${JSON.stringify({
44
+ schema:'deadbyte.r153-pending-migration.v1',marker_sha256:markerSha256,
45
+ receipt_path:terminalPath,receipt_sha256:digest(terminalBytes)
46
+ })}\n`);
47
+ return {evidenceDir,terminalPath};
48
+ }
49
+
50
+ test('R160 located receipt is accepted only after R153 proof binding verification',async t=>{
51
+ const fixture=await locatedFixture(t);
52
+ const selected=await selectLegacyMarkerEvidence({evidenceDir:fixture.evidenceDir,activePointer:pointer});
53
+ const verified=await verifyLocatedLegacyMarkerReceipt({located:selected,pointer,policySha256});
54
+ assert.equal(verified.state,'MARKER_RECONCILED');
55
+ assert.equal(verified.receipt_path,fixture.terminalPath);
56
+ assert.match(verified.receipt_sha256,/^[0-9a-f]{64}$/);
57
+ });
58
+
59
+ test('R160 consistent locator and terminal hashes cannot hide a wrong proof subject',async t=>{
60
+ const fixture=await locatedFixture(t,{tamper:receipt=>({...receipt,proof_sha256:id('f')})});
61
+ const selected=await selectLegacyMarkerEvidence({evidenceDir:fixture.evidenceDir,activePointer:pointer});
62
+ assert.equal(selected.kind,'located','R159 selector alone accepts the internally consistent bytes');
63
+ await assert.rejects(
64
+ verifyLocatedLegacyMarkerReceipt({located:selected,pointer,policySha256}),
65
+ /proof binding mismatch|subject mismatch|predecessor drift/i
66
+ );
67
+ });
68
+
69
+ test('R160 located receipt verification rejects policy drift after selection',async t=>{
70
+ const fixture=await locatedFixture(t);
71
+ const selected=await selectLegacyMarkerEvidence({evidenceDir:fixture.evidenceDir,activePointer:pointer});
72
+ await assert.rejects(
73
+ verifyLocatedLegacyMarkerReceipt({
74
+ located:selected,pointer,policySha256:{...policySha256,coding:id('c')}
75
+ }),
76
+ /proof binding mismatch|predecessor drift/i
77
+ );
78
+ });
79
+
80
+ test('R160 CLI rechecks active pointer after located proof verification',async()=>{
81
+ const source=await readFile(new URL('../src/deadbyte-cli.mjs',import.meta.url),'utf8');
82
+ assert.match(source,/R160 active release changed after located marker verification/);
83
+ const verifyAt=source.indexOf('verifyLocatedLegacyMarkerReceipt({located:selected,pointer:readback,policySha256})');
84
+ const finalReadAt=source.indexOf('await readActiveRuntimeBinding(ctx.root)',verifyAt);
85
+ assert.ok(verifyAt>0&&finalReadAt>verifyAt,'final pointer read-back must follow proof verification');
86
+ });
87
+
@@ -0,0 +1,67 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {mkdtemp,mkdir,writeFile,readFile,rm} from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import os from 'node:os';
6
+ import {createHash} from 'node:crypto';
7
+ import {
8
+ R160_STARTUP_DECISION_FILES,
9
+ verifyPackageDecisionManifest
10
+ } from '../src/package-identity-r160.mjs';
11
+
12
+ const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
13
+
14
+ async function fixture(t){
15
+ const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r160-package-'));
16
+ t.after(()=>rm(root,{recursive:true,force:true}));
17
+ const bodies=new Map();
18
+ for(const rel of R160_STARTUP_DECISION_FILES){
19
+ const bytes=Buffer.from(rel==='package.json'
20
+ ? `${JSON.stringify({name:'deadbyte-mcp',version:'0.15.62'})}\n`
21
+ : `fixture:${rel}\n`,'utf8');
22
+ const file=path.join(root,...rel.split('/'));
23
+ await mkdir(path.dirname(file),{recursive:true});
24
+ await writeFile(file,bytes);
25
+ bodies.set(rel,bytes);
26
+ }
27
+ const manifest=Buffer.from([...bodies].map(([rel,bytes])=>`${sha(bytes)} ${rel}`).join('\n')+'\n','utf8');
28
+ await writeFile(path.join(root,'MANIFEST.SHA256'),manifest);
29
+ return {root,bodies,manifest};
30
+ }
31
+
32
+ test('R160 startup decision manifest binds every decision file and package identity',async t=>{
33
+ const f=await fixture(t);
34
+ const result=await verifyPackageDecisionManifest({root:f.root,expectedVersion:'0.15.62'});
35
+ assert.equal(result.files,R160_STARTUP_DECISION_FILES.length);
36
+ assert.equal(result.manifest_sha256,sha(f.manifest));
37
+ });
38
+
39
+ test('R160 startup decision manifest rejects changed bytes before foreground claim',async t=>{
40
+ const f=await fixture(t);
41
+ await writeFile(path.join(f.root,'src','deadbyte-cli.mjs'),'changed\n');
42
+ await assert.rejects(
43
+ verifyPackageDecisionManifest({root:f.root,expectedVersion:'0.15.62'}),
44
+ /startup decision file hash mismatch: src\/deadbyte-cli\.mjs/
45
+ );
46
+ });
47
+
48
+ test('R160 startup decision manifest rejects a newly required recovery module omitted from manifest',async t=>{
49
+ const f=await fixture(t);
50
+ const lines=(await readFile(path.join(f.root,'MANIFEST.SHA256'),'utf8')).split(/\r?\n/)
51
+ .filter(line=>!line.endsWith(' src/legacy-marker-evidence-r159.mjs'));
52
+ await writeFile(path.join(f.root,'MANIFEST.SHA256'),`${lines.join('\n')}\n`);
53
+ await assert.rejects(
54
+ verifyPackageDecisionManifest({root:f.root,expectedVersion:'0.15.62'}),
55
+ /startup decision manifest missing: src\/legacy-marker-evidence-r159\.mjs/
56
+ );
57
+ });
58
+
59
+ test('R160 remote startup verifies decision bytes before evidence recovery and foreground claim',async()=>{
60
+ const source=await readFile(new URL('../src/deadbyte-cli.mjs',import.meta.url),'utf8');
61
+ const verifyAt=source.indexOf('await verifyPackageDecisionManifest({root:CURRENT_PACKAGE_ROOT,expectedVersion:DEADBYTE_VERSION})');
62
+ const recoverAt=source.indexOf('const migrationContext=await recoverRemoteSession(ctx,{displayMode})');
63
+ const claimAt=source.indexOf('marker=await claimRemoteSession(ctx)');
64
+ assert.ok(verifyAt>0&&verifyAt<recoverAt&&recoverAt<claimAt,
65
+ 'package decision manifest must be verified before recovery and claim');
66
+ });
67
+
@@ -0,0 +1,30 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {readFile} from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import {fileURLToPath} from 'node:url';
6
+ import {DEADBYTE_VERSION} from '../src/version.mjs';
7
+
8
+ const root=path.resolve(fileURLToPath(new URL('..',import.meta.url)));
9
+ const read=async rel=>JSON.parse(await readFile(path.join(root,rel),'utf8'));
10
+
11
+ test('R160 package identity separates source and live runtime predecessors',async()=>{
12
+ const [pkg,lock,bridge,release,provenance,matrix,bom]=await Promise.all([
13
+ read('package.json'),read('package-lock.json'),read('bridge/package.json'),read('RELEASE.json'),
14
+ read('PROVENANCE.json'),read('TEST-MATRIX.json'),read('SBOM.cdx.json')]);
15
+ for(const version of [pkg.version,lock.version,lock.packages[''].version,bridge.version,release.version,
16
+ provenance.version,matrix.version,bom.metadata.component.version,DEADBYTE_VERSION]) assert.equal(version,'0.15.62');
17
+ assert.equal(release.train,'R160');
18
+ assert.equal(matrix.train,'R160');
19
+ assert.equal(release.runtime_predecessor.version,'0.15.61');
20
+ assert.equal(release.runtime_predecessor.release_id,'v0.15.61-055d1ff0aa99e60b');
21
+ assert.equal(release.runtime_predecessor.manifest_sha256,'055d1ff0aa99e60bbf9e9f136b02ebd4fffb8391712560f7607cff30af94dcdf');
22
+ assert.equal(release.runtime_predecessor.generation_manifest_sha256,'f940e794daac2dda097a66301c4b85c4b29a2df7c669e549503c05a2a55ff6c4');
23
+ assert.equal(release.source_predecessor.train,'R159');
24
+ assert.match(release.source_predecessor.source_path,/deadbyte-mcp-0\.15\.62-r159-marker-reconcile/i);
25
+ assert.equal(release.r160.public_tool_delta,0);
26
+ assert.equal(release.r160.authority_scope_delta,0);
27
+ assert.equal(release.r160.production_activation,'NOT_RUN');
28
+ assert.equal(release.r160.npm_publish,'NOT_RUN');
29
+ assert.equal(provenance.r160.source_bytes_copied_from_references,false);
30
+ });
@@ -0,0 +1,10 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {renderStableLauncherCmd} from '../src/release-slot.mjs';
4
+
5
+ test('R160 stable CMD launcher selects the native Windows PowerShell explicitly', () => {
6
+ const cmd=renderStableLauncherCmd();
7
+ assert.match(cmd,/if not defined SystemRoot exit \/b 1/i);
8
+ assert.match(cmd,/"%SystemRoot%\\System32\\WindowsPowerShell\\v1\.0\\powershell\.exe"/i);
9
+ assert.doesNotMatch(cmd,/(?:^|\r?\n)powershell\.exe\s/im);
10
+ });
@@ -0,0 +1,58 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import {createHash} from 'node:crypto';
4
+ import {mkdtemp,mkdir,readFile,rm,writeFile,lstat} from 'node:fs/promises';
5
+ import os from 'node:os';
6
+ import path from 'node:path';
7
+ import {fileURLToPath} from 'node:url';
8
+ import {atomicWriteActivePointer,materializeReleaseSlot,parseActivePointer,parseManifest,renderStableLauncherPs1,verifyManifestTreeExact} from '../src/release-slot.mjs';
9
+
10
+ const candidate=path.dirname(path.dirname(fileURLToPath(import.meta.url)));
11
+ const version='0.15.62';
12
+ const parent=path.join(os.homedir(),'.deadbyte-mcp','releases','v0.15.61-055d1ff0aa99e60b');
13
+ const parentDigest='055d1ff0aa99e60bbf9e9f136b02ebd4fffb8391712560f7607cff30af94dcdf';
14
+ const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
15
+ async function generation(state,label){
16
+ const root=path.join(state,'generations',label);
17
+ await mkdir(root,{recursive:true});
18
+ const config=Buffer.from(`@{ Label = '${label}' }\r\n`,'utf8');
19
+ await writeFile(path.join(root,'controller-config.psd1'),config,{flag:'wx'});
20
+ const manifest=Buffer.from(`${sha(config)} controller-config.psd1\n`,'utf8');
21
+ await writeFile(path.join(root,'GENERATION.SHA256'),manifest,{flag:'wx'});
22
+ return {root,manifest_sha256:sha(manifest),config_path:path.join(root,'controller-config.psd1')};
23
+ }
24
+ test('R163 isolated immutable slot activates, rolls back, and restores 0.15.62 without authority or production mutation',async()=>{
25
+ const stateBase=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r163-isolated-'));
26
+ const state=path.join(stateBase,'state');
27
+ try{
28
+ const pkg=JSON.parse(await readFile(path.join(candidate,'package.json'),'utf8'));
29
+ assert.equal(pkg.version,version);
30
+ const parentManifest=await readFile(path.join(parent,'MANIFEST.SHA256'));
31
+ const nextManifest=await readFile(path.join(candidate,'MANIFEST.SHA256'));
32
+ assert.equal(sha(parentManifest),parentDigest);
33
+ const nextDigest=sha(nextManifest);
34
+ const parentSlot=await materializeReleaseSlot({source:parent,stateRoot:state,version:'0.15.61',manifestSha256:parentDigest});
35
+ const nextSlot=await materializeReleaseSlot({source:candidate,stateRoot:state,version,manifestSha256:nextDigest});
36
+ const pGen=await generation(state,'r163-parent');
37
+ const nGen=await generation(state,'r163-next');
38
+ const launcherSha=sha(Buffer.from(renderStableLauncherPs1(),'utf8'));
39
+ const pointerPath=path.join(state,'active-release.json');
40
+ const ptr=(slot,ver,g)=>({schema:'deadbyte.active-release.v1',release_id:slot.release_id,version:ver,
41
+ manifest_sha256:slot.manifest_sha256,release_root:slot.release_root,generation_root:g.root,
42
+ generation_manifest_sha256:g.manifest_sha256,launcher_sha256:launcherSha,config_path:g.config_path});
43
+ const activated=await atomicWriteActivePointer(pointerPath,ptr(nextSlot,version,nGen));
44
+ assert.equal(activated.release_id,nextSlot.release_id);
45
+ await verifyManifestTreeExact(nextSlot.release_root,parseManifest(nextManifest.toString('utf8')));
46
+ const rolled=await atomicWriteActivePointer(pointerPath,ptr(parentSlot,'0.15.61',pGen));
47
+ assert.equal(rolled.release_id,parentSlot.release_id);
48
+ assert.equal(rolled.manifest_sha256,parentDigest);
49
+ await verifyManifestTreeExact(parentSlot.release_root,parseManifest(parentManifest.toString('utf8')));
50
+ const restored=await atomicWriteActivePointer(pointerPath,ptr(nextSlot,version,nGen));
51
+ assert.deepEqual(restored,activated);
52
+ assert.deepEqual(parseActivePointer(await readFile(pointerPath,'utf8')),activated);
53
+ await verifyManifestTreeExact(nextSlot.release_root,parseManifest(nextManifest.toString('utf8')));
54
+ for(const n of ['process-grant.json','coding-grant.json','autonomous-grant.json','desktop-grant.json','host-grant.json']){
55
+ await assert.rejects(()=>lstat(path.join(state,'runtime',n)),{code:'ENOENT'});
56
+ }
57
+ }finally{await rm(stateBase,{recursive:true,force:true});}
58
+ });
@@ -0,0 +1,13 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import path from 'node:path';
4
+ import {fileURLToPath} from 'node:url';
5
+ import {assertR163NpmPublishReady} from '../scripts/npm-release-readiness-r163.mjs';
6
+ const root=path.dirname(path.dirname(fileURLToPath(import.meta.url)));
7
+ const release={name:'deadbyte-mcp',version:'0.15.62',train:'R160',r163:{publication_mode:'PUBLISH_ONLY'},parent:{release_id:'v0.15.61-055d1ff0aa99e60b',manifest_sha256:'055d1ff0aa99e60bbf9e9f136b02ebd4fffb8391712560f7607cff30af94dcdf',generation_manifest_sha256:'f940e794daac2dda097a66301c4b85c4b29a2df7c669e549503c05a2a55ff6c4'},runtime_predecessor:{release_id:'v0.15.61-055d1ff0aa99e60b'}};
8
+ test('R163 publish gate fails closed with missing evidence',async()=>{
9
+ await assert.rejects(()=>assertR163NpmPublishReady(release,{root,evidenceRoot:null}),/PUBLISH_BLOCKED R163/);
10
+ });
11
+ test('R163 publish gate rejects changed parent identity before evidence read',async()=>{
12
+ await assert.rejects(()=>assertR163NpmPublishReady({...release,parent:{...release.parent,release_id:'v0.15.60-wrong'}},{root}),/predecessor lineage mismatch/);
13
+ });
@@ -30,5 +30,11 @@ test('R48 compatibility release contract remains coherent in the current success
30
30
  assert.equal(provenance.parent_release_id, release.parent.release_id);
31
31
  assert.equal(provenance.parent_manifest_sha256, release.parent.manifest_sha256);
32
32
  assert.equal(provenance.parent_generation_manifest_sha256, release.parent.generation_manifest_sha256);
33
- assert.equal(provenance.source_predecessor_tarball_sha256, release.source_predecessor.tarball_sha256);
33
+ if(release.train==='R160'){
34
+ assert.equal(release.source_predecessor.train,'R159');
35
+ assert.equal(release.source_predecessor.manifest_status,'STALE_REJECTED');
36
+ assert.equal(provenance.r160.source_predecessor_manifest_status,'STALE_REJECTED');
37
+ }else{
38
+ assert.equal(provenance.source_predecessor_tarball_sha256, release.source_predecessor.tarball_sha256);
39
+ }
34
40
  });
@@ -4,6 +4,7 @@ import { mkdir, mkdtemp, writeFile } from 'node:fs/promises';
4
4
  import { spawnSync } from 'node:child_process';
5
5
  import path from 'node:path';
6
6
  import { renderStableLauncherPs1 } from '../src/release-slot.mjs';
7
+ import { windowsPowerShellEnvironment } from '../src/runtime-update.mjs';
7
8
 
8
9
  test('R58 launcher dispatch uses native Windows PowerShell even when entered from pwsh', async () => {
9
10
  const base = 'D:/Projects/deadbyte-mcp/testing/0.15.35/fixtures';
@@ -20,7 +21,9 @@ test('R58 launcher dispatch uses native Windows PowerShell even when entered fro
20
21
  const native = path.join(process.env.SystemRoot, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe');
21
22
  const modern = path.join(process.env.USERPROFILE, '.cache', 'codex-runtimes', 'codex-primary-runtime', 'dependencies', 'native', 'powershell', 'pwsh.exe');
22
23
  for (const executable of [native, modern]) {
23
- const observed = spawnSync(executable, ['-NoProfile', '-File', dispatch], { encoding: 'utf8', timeout: 20000 });
24
+ const observed = spawnSync(executable, ['-NoProfile', '-File', dispatch], {
25
+ env: windowsPowerShellEnvironment(process.env), encoding: 'utf8', timeout: 20000
26
+ });
24
27
  assert.ifError(observed.error);
25
28
  assert.equal(observed.status, 7, observed.stderr);
26
29
  assert.match(observed.stdout, /FIXTURE:status/);
@@ -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','0.15.51','0.15.52','0.15.53','0.15.54','0.15.55','0.15.56','0.15.57','0.15.58','0.15.59','0.15.60'].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','0.15.53','0.15.54','0.15.55','0.15.56','0.15.57','0.15.58','0.15.59','0.15.60','0.15.61','0.15.62'].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');
@@ -156,6 +156,22 @@ test('R27 generation bundle rebinds authority and mutable state outside the rele
156
156
  const second=await build({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:changedConfig,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy,desktopPolicy});
157
157
  assert.notEqual(second.generation_root,result.generation_root);
158
158
  assert.notEqual(second.generation_seed_sha256,result.generation_seed_sha256);
159
+ // R158 regression: changing the trusted Epoch source changes generation identity.
160
+ const epochA=structuredClone(currentConfig);
161
+ epochA.AuthorityEpochRoot='C:\\Program Files\\DEADBYTE-R158-Epoch-A';
162
+ const generationA=await build({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:epochA,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy,desktopPolicy});
163
+ assert.notEqual(generationA.generation_root,result.generation_root);
164
+ assert.match(await readFile(generationA.config_path,'utf8'),/AuthorityEpochRoot = 'C:\\Program Files\\DEADBYTE-R158-Epoch-A'/);
165
+ const epochB=structuredClone(epochA);
166
+ epochB.AuthorityEpochRoot='C:\\Program Files\\DEADBYTE-R158-Epoch-B';
167
+ const generationB=await build({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:epochB,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy,desktopPolicy});
168
+ assert.notEqual(generationB.generation_root,generationA.generation_root);
169
+ assert.notEqual(generationB.generation_seed_sha256,generationA.generation_seed_sha256);
170
+ for(const invalidRoot of ['relative\\epoch','\\\\server\\share\\epoch','C:relative','']){
171
+ const invalid=structuredClone(currentConfig);
172
+ invalid.AuthorityEpochRoot=invalidRoot;
173
+ await assert.rejects(build({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:invalid,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy,desktopPolicy}),/AuthorityEpochRoot.*drive-absolute/i);
174
+ }
159
175
  const endpointChanged=structuredClone(currentConfig);
160
176
  endpointChanged.McpUrlFileSha256='2'.repeat(64);
161
177
  const third=await build({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:endpointChanged,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy,desktopPolicy});
@@ -72,13 +72,15 @@ test('R40 CLI exposes explicit verbose mode while keeping default live mode comp
72
72
  const {readFile}=await import('node:fs/promises');
73
73
  const src=await readFile(new URL('../src/deadbyte-cli.mjs',import.meta.url),'utf8');
74
74
  assert.match(src,/readLiveRootPaths\(ctx\.root\)/);
75
- assert.match(src,/createLiveTimelineTracker\(\{verbose,displayMode,rootPaths,trace,foldHeartbeats:!verbose\}\)/);
75
+ assert.match(src,/createLiveTimelineTracker\(\{verbose,displayMode,rootPaths,trace,\.\.\.defaultForegroundTimelineOptions\(\{verbose\}\)\}\)/);
76
+ assert.deepEqual(live.defaultForegroundTimelineOptions({verbose:false}),{commanderStyle:true,foldHeartbeats:false});
77
+ assert.deepEqual(live.defaultForegroundTimelineOptions({verbose:true}),{commanderStyle:false,foldHeartbeats:false});
76
78
  assert.match(src,/createLiveTimelineFilter\(filterExpression\)/);
77
79
  assert.match(src,/createLiveTimelineWriter\(\{stream:process\.stdout,displayMode,rewrite:false\}\)/);
78
80
  assert.match(src,/arg==='--verbose'\|\|arg==='-v'/);
79
81
  assert.match(src,/arg==='--trace'/);
80
82
  assert.match(src,/arg==='--filter'/);
81
- assert.match(src,/Transport IN\/OUT hidden/);
83
+ assert.match(src,/Transport hidden; signed audit remains on disk/);
82
84
  assert.doesNotMatch(src,/\[cursor \$\{recorded\.cursor\}\]/);
83
85
  });
84
86
 
@@ -232,7 +234,7 @@ test('human mutation span labels START and preserves terminal audit status',()=>
232
234
  test('foreground human log keeps START and DONE separate and folds heartbeat noise',async()=>{
233
235
  const {readFile}=await import('node:fs/promises');
234
236
  const src=await readFile(new URL('../src/deadbyte-cli.mjs',import.meta.url),'utf8');
235
- assert.match(src,/createLiveTimelineTracker\(\{verbose,displayMode,rootPaths,trace,foldHeartbeats:!verbose\}\)/);
237
+ assert.match(src,/createLiveTimelineTracker\(\{verbose,displayMode,rootPaths,trace,\.\.\.defaultForegroundTimelineOptions\(\{verbose\}\)\}\)/);
236
238
  assert.match(src,/createLiveTimelineWriter\(\{stream:process\.stdout,displayMode,rewrite:false\}\)/);
237
239
  });
238
240
 
@@ -330,7 +330,7 @@ winTest('bare remote uses one unified live timeline, keeps authority semantics,
330
330
  assert.match(output.stdout,/\[OK\] ONLINE/);
331
331
  assert.match(output.stdout,/\[READY\] DEADBYTE MCP online/);
332
332
  assert.match(output.stdout,/\[AUTH\] process ARMED \| coding ARMED \| autonomous ARMED \| desktop DISARMED \| host DISARMED/);
333
- assert.match(output.stdout,/\[LOG\] Human live timeline\. Transport IN\/OUT hidden; full replay\/audit detail remains on disk\./);
333
+ assert.match(output.stdout,/\[LOG\] Live tool calls with individual START\/DONE, sanitized arguments and results\. Transport hidden; signed audit remains on disk\./);
334
334
  assert.doesNotMatch(output.stdout,/Process plane\s*:/);
335
335
  assert.doesNotMatch(output.stdout,/Coding plane\s*:/);
336
336
  const auditDir=path.join(fx.state,'audit');
@@ -353,11 +353,11 @@ winTest('bare remote uses one unified live timeline, keeps authority semantics,
353
353
  '[TOOL OUT] 2026-09-16T00:00:00.002Z #000002 coding_file_read {"is_error":true}'
354
354
  ].join('\n')+'\n','utf8');
355
355
  const logDeadline=Date.now()+fixtureTimeoutMs;
356
- while(Date.now()<logDeadline&&!/^R .*#4 \[fedcba98\] coding_file_read projects:src\/deadbyte-cli\.mjs 1\.73s \[SLOW\] ERR$/m.test(output.stdout)) await sleep(50);
357
- assert.doesNotMatch(output.stdout,/\| Arguments:/,'default human view must not print request JSON');
358
- assert.match(output.stdout,/^S .*#2 \[abcdef12\] coding_tree projects:src 42ms OK$/m);
359
- assert.match(output.stdout,/^R .*#4 \[fedcba98\] coding_file_read projects:src\/deadbyte-cli\.mjs 1\.73s \[SLOW\] ERR$/m);
360
- assert.equal((output.stdout.match(/\[abcdef12\].*coding_tree.*42ms.*OK/g)||[]).length,1,'duplicate terminal result must print once');
356
+ while(Date.now()<logDeadline&&!/^\[.*\] \[FAIL\] Tool call coding_file_read failed \[fedcba98\] 1\.73s$/m.test(output.stdout)) await sleep(50);
357
+ assert.match(output.stdout,/\[CALL\] Received tool call \[abcdef12\] coding_tree Arguments:/,'default human view must show bounded sanitized arguments');
358
+ assert.match(output.stdout,/^\[.*\] \[DONE\] Tool call coding_tree completed \[abcdef12\] 42ms$/m);
359
+ assert.match(output.stdout,/^\[.*\] \[FAIL\] Tool call coding_file_read failed \[fedcba98\] 1\.73s$/m);
360
+ assert.equal((output.stdout.match(/\[DONE\] Tool call coding_tree completed \[abcdef12\] 42ms/g)||[]).length,1,'duplicate terminal result must print once');
361
361
  assert.doesNotMatch(output.stdout,/\[cursor r1:/,'full replay cursor belongs in the journal, not every human line');
362
362
  const resultJournal=JSON.parse(await readFile(path.join(fx.state,'runtime','remote-results',`${marker.result_session_id}.json`),'utf8'));
363
363
  assert.deepEqual(resultJournal.events.map(event=>event.seq),[1,2,3,4]);
@@ -377,7 +377,7 @@ winTest('bare remote uses one unified live timeline, keeps authority semantics,
377
377
  const commands=await traceCommands(fx.trace);
378
378
  assert.deepEqual(commands.slice(-8),['disarmautonomous','disarmcoding','disarmprocess','disarmdesktop','disarmhost','status','machinetest','park']);
379
379
  assert.match(output.stdout,/^DEADBYTE MCP$/m);
380
- assert.match(output.stdout,/Human live timeline/i);
380
+ assert.match(output.stdout,/Live tool calls with individual START\/DONE/i);
381
381
  assert.match(output.stdout,/\[AUTH\] Revoking session authority/);
382
382
  assert.doesNotMatch(output.stdout,/disarmautonomous OK|disarmcoding OK|disarmprocess OK|disarmdesktop OK|disarmhost OK|DEADBYTE MCP = PARKED/);
383
383
  assert.doesNotMatch(output.stdout,/\p{Extended_Pictographic}/u,'piped Windows fallback must remain ASCII-safe');
@@ -395,7 +395,7 @@ winTest('remote --resume replays sanitized tool-call and terminal result events
395
395
  const firstOutput=await collect(first);
396
396
  await waitFor(fx.trace,commands=>commands.filter(x=>x==='status').length>=4);
397
397
  const liveDeadline=Date.now()+3000;
398
- while(Date.now()<liveDeadline&&!/\[LOG\] Human live timeline/.test(firstOutput.stdout)) await sleep(50);
398
+ while(Date.now()<liveDeadline&&!/\[LOG\] Live tool calls/.test(firstOutput.stdout)) await sleep(50);
399
399
  const marker=JSON.parse(await readFile(path.join(fx.state,'runtime','remote-session.json'),'utf8'));
400
400
  assert.match(String(marker.result_session_id||''),/^[0-9a-f]{24}$/);
401
401
  const auditDir=path.join(fx.state,'audit');await mkdir(auditDir,{recursive:true});
@@ -428,7 +428,7 @@ winTest('remote --resume replays sanitized tool-call and terminal result events
428
428
  deadline=Date.now()+5000;
429
429
  while(Date.now()<deadline&&(!/coding_file_read\s+\| Arguments: .*\| REPLAY #3/.test(secondOutput.stdout)||
430
430
  !/\[REPLAY\] #4 coding_file_read OK/.test(secondOutput.stdout)||
431
- !/\[LOG\] Human live timeline/.test(secondOutput.stdout))) await sleep(50);
431
+ !/\[LOG\] Live tool calls/.test(secondOutput.stdout))) await sleep(50);
432
432
  assert.match(secondOutput.stdout,/^2026-09-18T23:30:01\.000\+07:00 \| coding_file_read\s+\| Arguments: .*"path":"src\/deadbyte-cli\.mjs".*\| REPLAY #3$/m);
433
433
  assert.match(secondOutput.stdout,/\[REPLAY\] #4 coding_file_read OK/);
434
434
  assert.match(secondOutput.stdout,/\[SESSION\] Previous result stream replayed/);
@@ -438,7 +438,7 @@ winTest('remote --resume replays sanitized tool-call and terminal result events
438
438
  assert.equal((secondOutput.stdout.match(/\[REPLAY\] #4 coding_file_read OK/g)||[]).length,1,'terminal replay duplicated');
439
439
  const callReplayIndex=secondOutput.stdout.indexOf('| coding_file_read');
440
440
  const resultReplayIndex=secondOutput.stdout.indexOf('[REPLAY] #4 coding_file_read OK');
441
- const liveIndex=secondOutput.stdout.indexOf('[LOG] Human live timeline');
441
+ const liveIndex=secondOutput.stdout.indexOf('[LOG] Live tool calls');
442
442
  assert.ok(callReplayIndex>=0&&resultReplayIndex>callReplayIndex&&liveIndex>resultReplayIndex,'resume ordering must be call -> result -> live tail');
443
443
  second.stdin.end();
444
444
  const secondEnded=await boundedCompletion(secondOutput.closed);
@@ -811,7 +811,7 @@ winTest('remote --trace --filter selects presentation without dropping journaled
811
811
  await writeFile(path.join(auditDir,'segment-00000001.jsonl'),audit.map(JSON.stringify).join('\n')+'\n','utf8');
812
812
  const deadline=Date.now()+4000;
813
813
  while(Date.now()<deadline&&!/machine_fs\.write.*trace=goal-1234/.test(output.stdout)) await sleep(50);
814
- assert.match(output.stdout,/machine_fs\.write.*trace=goal-123\.\.\. span=filter-w\.\.\..*10ms.*ERR - denied/);
814
+ assert.match(output.stdout,/Tool call machine_fs\.write failed \[filter-w\].*trace=goal-123\.\.\. span=filter-w\.\.\..*10ms.*denied/i);
815
815
  assert.doesNotMatch(output.stdout,/coding_file_read.*missing/);
816
816
  assert.doesNotMatch(output.stdout,/SECRET/);
817
817
  const journal=JSON.parse(await readFile(path.join(fx.state,'runtime','remote-results',marker.result_session_id+'.json'),'utf8'));
@@ -54,7 +54,8 @@ test('CMD launcher transports explicit root with spaces to nested Node child',as
54
54
  await writeFile(path.join(isolated,'bin','DEADBYTE-MCP.ps1'),`& '${process.execPath.replaceAll("'","''")}' -e 'console.log(process.env.DEADBYTE_STATE_ROOT)'\nexit $LASTEXITCODE\n`);
55
55
  const cmd=path.join(fixture,'launcher.cmd');
56
56
  await writeFile(cmd,renderStableLauncherCmd());
57
- const r=spawnSync(process.env.ComSpec,['/d','/c',cmd,'status'],{encoding:'utf8',timeout:20000,env:windowsPowerShellEnvironment({...process.env,DEADBYTE_STATE_ROOT:isolated,USERPROFILE:fixture})});
57
+ const nativeCmd=path.join(process.env.SystemRoot,'System32','cmd.exe');
58
+ const r=spawnSync(nativeCmd,['/d','/c',cmd,'status'],{encoding:'utf8',timeout:20000,env:windowsPowerShellEnvironment({...process.env,DEADBYTE_STATE_ROOT:isolated,USERPROFILE:fixture})});
58
59
  assert.equal(r.status,0,r.stderr);
59
60
  assert.equal(r.stdout.trim(),isolated);
60
61
  });