deadbyte-mcp 0.15.41 → 0.15.42

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 (85) hide show
  1. package/DEADBYTE-MCP.cmd +8 -4
  2. package/MANIFEST.SHA256 +84 -41
  3. package/PROVENANCE.json +53 -15
  4. package/README.txt +27 -18
  5. package/RELEASE.json +43 -15
  6. package/SBOM.cdx.json +2 -2
  7. package/TEST-MATRIX.json +106 -14
  8. package/bridge/package.json +1 -1
  9. package/controller/deadbyte-controller.ps1 +132 -12
  10. package/controller/deadbyte-process-policy.json +4 -4
  11. package/docs/R65-AUTHORITY-CONTINUITY-DESIGN.json +27 -0
  12. package/docs/R65-REFERENCE-GAP-MATRIX.json +22 -0
  13. package/package.json +5 -4
  14. package/scripts/deploy-r48.mjs +123 -7
  15. package/scripts/gate-windows-r65-prepublish.ps1 +65 -0
  16. package/scripts/npm-publication-r65.mjs +139 -0
  17. package/scripts/npm-release-r48.mjs +56 -37
  18. package/scripts/r65-canonical-full.mjs +45 -0
  19. package/scripts/r65-focused.mjs +37 -0
  20. package/scripts/verify-r65-parent-source.mjs +75 -0
  21. package/src/activation-continuity-engine-r65.mjs +225 -0
  22. package/src/activation-lock-r65.mjs +155 -0
  23. package/src/activation-preflight-r65.mjs +197 -0
  24. package/src/authority-continuity-r65.mjs +541 -0
  25. package/src/authority-epoch-cli-r65.mjs +10 -0
  26. package/src/autonomous-policy.mjs +7 -3
  27. package/src/coding-plane.mjs +12 -3
  28. package/src/desktop-policy-r40.mjs +6 -3
  29. package/src/doctor-transactions-r58.mjs +1 -1
  30. package/src/host-plane.mjs +9 -3
  31. package/src/process-policy.mjs +7 -4
  32. package/src/remote-authority.mjs +10 -1
  33. package/src/runtime-update.mjs +15 -5
  34. package/src/version.mjs +1 -1
  35. package/test/audit-context.test.mjs +15 -4
  36. package/test/autonomous-local-supervisor.test.mjs +7 -6
  37. package/test/autonomous-supervisor-integration.test.mjs +8 -7
  38. package/test/capability-resolver.test.mjs +11 -5
  39. package/test/codex-autonomous-r44.test.mjs +7 -6
  40. package/test/coding-observation.test.mjs +4 -3
  41. package/test/commander-real-parity-r47.test.mjs +5 -4
  42. package/test/commander-torture-r47.test.mjs +5 -4
  43. package/test/desktop-policy-r40.test.mjs +6 -4
  44. package/test/desktop-runtime-r40.test.mjs +8 -3
  45. package/test/host-inline-r45.test.mjs +4 -3
  46. package/test/machine-fs-runtime.test.mjs +4 -3
  47. package/test/process-longrun-r36.test.mjs +3 -2
  48. package/test/process-policy.test.mjs +10 -6
  49. package/test/process-runtime.test.mjs +9 -6
  50. package/test/r52-host-revocation.test.mjs +1 -0
  51. package/test/r59-tool-surface-compat.test.mjs +1 -1
  52. package/test/r64-release-contract.test.mjs +2 -1
  53. package/test/r65-activation-lock-recovery.test.mjs +72 -0
  54. package/test/r65-activation-lock.test.mjs +59 -0
  55. package/test/r65-activation-orchestration.test.mjs +179 -0
  56. package/test/r65-activation-preflight.test.mjs +35 -0
  57. package/test/r65-authority-continuity-decision.test.mjs +58 -0
  58. package/test/r65-authority-durable-policy-binding.test.mjs +34 -0
  59. package/test/r65-authority-epoch-cli.test.mjs +125 -0
  60. package/test/r65-authority-epoch-races.test.mjs +87 -0
  61. package/test/r65-authority-epoch-recovery.test.mjs +82 -0
  62. package/test/r65-authority-epoch-store.test.mjs +94 -0
  63. package/test/r65-authority-fixture.mjs +41 -0
  64. package/test/r65-authority-grant-capture.test.mjs +37 -0
  65. package/test/r65-authority-observation-epoch.test.mjs +25 -0
  66. package/test/r65-authority-policy-envelope.test.mjs +46 -0
  67. package/test/r65-authority-restored-safe.test.mjs +75 -0
  68. package/test/r65-authority-runtime-epoch.test.mjs +115 -0
  69. package/test/r65-authority-runtime-policy-binding.test.mjs +29 -0
  70. package/test/r65-authority-test-trust.mjs +20 -0
  71. package/test/r65-cli-invocation.test.mjs +38 -0
  72. package/test/r65-controller-authority-epoch-live.test.mjs +100 -0
  73. package/test/r65-controller-authority-epoch.test.mjs +37 -0
  74. package/test/r65-deploy-preflight.test.mjs +55 -0
  75. package/test/r65-epoch-native-activation-integration.test.mjs +141 -0
  76. package/test/r65-epoch-native-continuity-engine.test.mjs +112 -0
  77. package/test/r65-epoch-native-cross-plane.test.mjs +95 -0
  78. package/test/r65-legacy-authority-migration.test.mjs +63 -0
  79. package/test/r65-legacy-auto-restore-rejection.test.mjs +17 -0
  80. package/test/r65-npm-publication.test.mjs +114 -0
  81. package/test/r65-parent-source-verifier.test.mjs +63 -0
  82. package/test/r65-release-contract.test.mjs +74 -0
  83. package/test/r65-transaction-precondition.test.mjs +36 -0
  84. package/test/remote-session-cli.test.mjs +6 -6
  85. package/test/standing-grants.test.mjs +20 -4
package/README.txt CHANGED
@@ -1,4 +1,4 @@
1
- DEADBYTE MCP V0.15.41 / R64 BOUNDED LARGE-FILE READS
1
+ DEADBYTE MCP V0.15.42 / R65 RELEASE CONTROL + AUTHORITY CONTINUITY HARDENING
2
2
  =========================
3
3
 
4
4
  AUTHENTICATED MACHINE TRUTH + DURABLE AGENT + CODING + AUTONOMOUS PRODUCTION ENGINE
@@ -7,12 +7,21 @@ NPX PRIMARY OPERATOR UX
7
7
  ------------------------
8
8
  Use the npm CLI entry point instead of the legacy CMD convenience wrapper:
9
9
 
10
- npx -y deadbyte-mcp@0.15.41 mcp
11
- npx -y deadbyte-mcp@0.15.41 remote
12
- npx -y deadbyte-mcp@0.15.41 remote status
13
- npx -y deadbyte-mcp@0.15.41 remote restart
14
- npx -y deadbyte-mcp@0.15.41 audit status
15
- npx -y deadbyte-mcp@0.15.41 audit verify
10
+ Run npx/npm exec from a directory outside a DEADBYTE source or release tree.
11
+ On Windows the tree also contains DEADBYTE-MCP.cmd; cmd.exe can resolve that
12
+ same-name compatibility launcher before npm's requested package bin. From a
13
+ source tree, use `node src/deadbyte-cli.mjs` to select that source explicitly.
14
+ To request an exact published version, change to a neutral directory first and
15
+ check `--version` before issuing a stateful command. The compatibility CMD
16
+ fails with an explanation when npm is detected rather than forwarding the
17
+ wrong command to the controller.
18
+
19
+ npx -y deadbyte-mcp@0.15.42 mcp
20
+ npx -y deadbyte-mcp@0.15.42 remote
21
+ npx -y deadbyte-mcp@0.15.42 remote status
22
+ npx -y deadbyte-mcp@0.15.42 remote restart
23
+ npx -y deadbyte-mcp@0.15.42 audit status
24
+ npx -y deadbyte-mcp@0.15.42 audit verify
16
25
 
17
26
  MAJOR MCP CLIENT STDIO CONFIGS
18
27
  -------------------------------
@@ -23,7 +32,7 @@ CLAUDE DESKTOP
23
32
  "mcpServers": {
24
33
  "deadbyte": {
25
34
  "command": "npx",
26
- "args": ["-y", "deadbyte-mcp@0.15.41", "mcp"]
35
+ "args": ["-y", "deadbyte-mcp@0.15.42", "mcp"]
27
36
  }
28
37
  }
29
38
  }
@@ -35,7 +44,7 @@ Save as .cursor/mcp.json:
35
44
  "mcpServers": {
36
45
  "deadbyte": {
37
46
  "command": "npx",
38
- "args": ["-y", "deadbyte-mcp@0.15.41", "mcp"]
47
+ "args": ["-y", "deadbyte-mcp@0.15.42", "mcp"]
39
48
  }
40
49
  }
41
50
  }
@@ -48,7 +57,7 @@ Save as .vscode/mcp.json:
48
57
  "deadbyte": {
49
58
  "type": "stdio",
50
59
  "command": "npx",
51
- "args": ["-y", "deadbyte-mcp@0.15.41", "mcp"]
60
+ "args": ["-y", "deadbyte-mcp@0.15.42", "mcp"]
52
61
  }
53
62
  }
54
63
  }
@@ -58,7 +67,7 @@ Add to the Codex MCP configuration:
58
67
 
59
68
  [mcp_servers.deadbyte]
60
69
  command = "npx"
61
- args = ["-y", "deadbyte-mcp@0.15.41", "mcp"]
70
+ args = ["-y", "deadbyte-mcp@0.15.42", "mcp"]
62
71
 
63
72
  The `mcp` command is the quiet stdio server entry for local MCP clients; stdout is reserved for MCP.
64
73
  The remote CLI invokes the stable active-release PowerShell launcher directly with shell=false.
@@ -346,7 +355,7 @@ CONTROLLER
346
355
  ----------
347
356
  Primary operator entry point:
348
357
 
349
- npx -y deadbyte-mcp@0.15.41 remote
358
+ npx -y deadbyte-mcp@0.15.42 remote
350
359
 
351
360
  The legacy CMD entry remains compatibility-only for R33 rollback safety.
352
361
 
@@ -407,7 +416,7 @@ MCP CLIENT CONFIGURATION
407
416
  ------------------------
408
417
  The local stdio entry point is quiet and suitable for MCP hosts:
409
418
 
410
- npx -y deadbyte-mcp@0.15.41 mcp
419
+ npx -y deadbyte-mcp@0.15.42 mcp
411
420
 
412
421
  CLAUDE DESKTOP
413
422
  Use the standard local-server entry in claude_desktop_config.json:
@@ -416,7 +425,7 @@ Use the standard local-server entry in claude_desktop_config.json:
416
425
  "mcpServers": {
417
426
  "deadbyte": {
418
427
  "command": "npx",
419
- "args": ["-y", "deadbyte-mcp@0.15.41", "mcp"]
428
+ "args": ["-y", "deadbyte-mcp@0.15.42", "mcp"]
420
429
  }
421
430
  }
422
431
  }
@@ -429,7 +438,7 @@ Create .cursor/mcp.json:
429
438
  "deadbyte": {
430
439
  "type": "stdio",
431
440
  "command": "npx",
432
- "args": ["-y", "deadbyte-mcp@0.15.41", "mcp"]
441
+ "args": ["-y", "deadbyte-mcp@0.15.42", "mcp"]
433
442
  }
434
443
  }
435
444
  }
@@ -442,7 +451,7 @@ Create .vscode/mcp.json:
442
451
  "deadbyte": {
443
452
  "type": "stdio",
444
453
  "command": "npx",
445
- "args": ["-y", "deadbyte-mcp@0.15.41", "mcp"]
454
+ "args": ["-y", "deadbyte-mcp@0.15.42", "mcp"]
446
455
  }
447
456
  }
448
457
  }
@@ -452,9 +461,9 @@ Add this to ~/.codex/config.toml:
452
461
 
453
462
  [mcp_servers.deadbyte]
454
463
  command = "npx"
455
- args = ["-y", "deadbyte-mcp@0.15.41", "mcp"]
464
+ args = ["-y", "deadbyte-mcp@0.15.42", "mcp"]
456
465
 
457
- The remote device path remains `npx -y deadbyte-mcp@0.15.41 remote`. Remote public MCP uses the
466
+ The remote device path remains `npx -y deadbyte-mcp@0.15.42 remote`. Remote public MCP uses the
458
467
  verified HTTPS named-tunnel URL selected by the active generation; do not commit a private device
459
468
  URL or tunnel token into a repository.
460
469
 
package/RELEASE.json CHANGED
@@ -1,28 +1,28 @@
1
1
  {
2
2
  "schema": "deadbyte.release.v1",
3
3
  "name": "deadbyte-mcp",
4
- "version": "0.15.41",
5
- "train": "R64",
6
- "label": "BOUNDED LARGE-FILE READS",
4
+ "version": "0.15.42",
5
+ "train": "R65",
6
+ "label": "RELEASE CONTROL AND AUTHORITY CONTINUITY HARDENING",
7
7
  "protocol_revision": "2026-07-28",
8
8
  "parent": {
9
- "version": "0.15.39",
10
- "release_id": "v0.15.39-3cda3b1c65b7b7c5",
11
- "manifest_sha256": "3cda3b1c65b7b7c561c5a8617156ab87d69cf162f447f3e99a4cb4a76471b3de",
12
- "generation_manifest_sha256": "f47cb96083679e764725df1bde6eda53169a39f55772c173ab22f89a1dfaa7ab",
9
+ "version": "0.15.41",
10
+ "release_id": "v0.15.41-63a78ad159ad3003",
11
+ "manifest_sha256": "63a78ad159ad3003db3fefafcd468bef22599c829a867f4f10a46c7a20748b3e",
12
+ "generation_manifest_sha256": "19ae2efcdcde9f80c474f0e55851d4ada51c22813d3e05af03b11acb28c3fca5",
13
13
  "activation_status": "PRODUCTION_ACTIVE"
14
14
  },
15
15
  "runtime_predecessor": {
16
- "release_id": "v0.15.39-3cda3b1c65b7b7c5",
17
- "manifest_sha256": "3cda3b1c65b7b7c561c5a8617156ab87d69cf162f447f3e99a4cb4a76471b3de",
18
- "generation_manifest_sha256": "f47cb96083679e764725df1bde6eda53169a39f55772c173ab22f89a1dfaa7ab"
16
+ "release_id": "v0.15.41-63a78ad159ad3003",
17
+ "manifest_sha256": "63a78ad159ad3003db3fefafcd468bef22599c829a867f4f10a46c7a20748b3e",
18
+ "generation_manifest_sha256": "19ae2efcdcde9f80c474f0e55851d4ada51c22813d3e05af03b11acb28c3fca5"
19
19
  },
20
20
  "source_predecessor": {
21
- "version": "0.15.40",
22
- "source_path": "D:\\Projects\\deadbyte-mcp\\development\\deadbyte-mcp-0.15.40-r63",
23
- "manifest_file_sha256": "d6f75feada9ad0ae2c248b3a833ac9cf0e04150d2430ddaa70b3dfb64a0b0a86",
24
- "manifest_file_count": 2227,
25
- "release_status": "NOT_PROVEN_RELEASED"
21
+ "version": "0.15.41",
22
+ "source_path": "D:\\Projects\\deadbyte-mcp\\development\\deadbyte-mcp-0.15.41-r64",
23
+ "manifest_file_sha256": "63a78ad159ad3003db3fefafcd468bef22599c829a867f4f10a46c7a20748b3e",
24
+ "manifest_file_count": 2234,
25
+ "release_status": "PRODUCTION_RELEASED"
26
26
  },
27
27
  "consolidation": {
28
28
  "frontend_status_vocabulary": true,
@@ -276,5 +276,33 @@
276
276
  "package_verification": "PENDING",
277
277
  "publication_activation": "PROHIBITED_THIS_TRAIN",
278
278
  "release_ready": false
279
+ },
280
+ "r65_release_control_hardening": {
281
+ "public_surface_tool_count": 43,
282
+ "new_public_tools": 0,
283
+ "new_authority_scopes": 0,
284
+ "npm_publication_reconciliation": true,
285
+ "deterministic_precondition_terminal_receipts": true,
286
+ "canonical_cli_invocation_regression": true,
287
+ "durable_per_plane_authority_epoch": true,
288
+ "policy_security_envelope_binding": true,
289
+ "epoch_native_cross_generation_restore": true,
290
+ "legacy_r64_auto_restore": false,
291
+ "epoch_native_restore_requires_continuity_proof": true,
292
+ "explicit_revoke_wins": true,
293
+ "replacement_grant_wins": true,
294
+ "revoked_nonce_resurrection": false,
295
+ "restored_grant_requires_fresh_nonce": true,
296
+ "coding_dependency_protects_autonomous": true,
297
+ "focused_tests": "PASS_71_OF_71_PRE_METADATA_REFRESH",
298
+ "full_regression": "PASS_1360_TESTS_1319_PASS_41_DOCUMENTED_SKIP_0_FAIL_PRE_METADATA_REFRESH",
299
+ "production_mutations": 0,
300
+ "npm_publications": 0,
301
+ "stable_final_claim": false,
302
+ "restored_safe_semantics": "PASS_RED_2_OF_2_THEN_GREEN_2_OF_2",
303
+ "restored_safe_red_receipt_sha256": "f15f57a54aeb046e366292c4e91bc0b045be0f6a0780eb47fb5fbac596741eee",
304
+ "restored_safe_green_receipt_sha256": "d859409d33f9f1a165889c5ce4360f2f83b8f4bb66f5b6ab63980b8464678a72",
305
+ "final_gate_evidence_location": "D:\\Projects\\deadbyte-mcp\\testing\\0.15.42-r65",
306
+ "final_gate_receipts_external_to_candidate": true
279
307
  }
280
308
  }
package/SBOM.cdx.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "bomFormat": "CycloneDX",
3
3
  "specVersion": "1.6",
4
- "serialNumber": "urn:cdx:deadbyte-mcp:r64:0.15.41",
4
+ "serialNumber": "urn:cdx:deadbyte-mcp:r65:0.15.42",
5
5
  "version": 1,
6
6
  "metadata": {
7
7
  "component": {
8
8
  "type": "application",
9
9
  "name": "deadbyte-mcp",
10
- "version": "0.15.41"
10
+ "version": "0.15.42"
11
11
  }
12
12
  },
13
13
  "components": [
package/TEST-MATRIX.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schema": "deadbyte.test-matrix.v1",
3
- "version": "0.15.41",
4
- "train": "R64",
3
+ "version": "0.15.42",
4
+ "train": "R65",
5
5
  "primary_platform": "win32-x64",
6
6
  "reference": {
7
7
  "package": "@wonderwhy-er/desktop-commander",
@@ -11,29 +11,24 @@
11
11
  },
12
12
  "required": [
13
13
  {
14
- "id": "r64-focused",
15
- "command": "npm run r64:focused:test",
16
- "expected": "PASS R64 release identity, large-file pagination, bounds, replacement visibility, inherited machine fs and bridge/control contracts"
14
+ "id": "r65-focused",
15
+ "command": "npm run r65:focused:test",
16
+ "expected": "PASS R65 publication reconciliation, activation continuity, epoch durability, legacy migration, crash/race and transaction terminality contracts"
17
17
  },
18
18
  {
19
- "id": "r64-full-regression",
19
+ "id": "r65-full-regression",
20
20
  "command": "npm test",
21
- "expected": "PASS complete current R64 regression with only documented historical/platform skips"
21
+ "expected": "PASS complete R65 regression with only documented historical/platform skips"
22
22
  },
23
23
  {
24
24
  "id": "windows-gate",
25
25
  "command": "npm run gate:windows",
26
- "expected": "PASS exact R63 source manifest and active 0.15.39 runtime predecessor, R64 focused/full regression, manifest verify and doctor"
26
+ "expected": "PASS exact sealed R64 parent identity, R65 focused/full regression, manifest verify and isolated doctor"
27
27
  },
28
28
  {
29
29
  "id": "package-verify",
30
30
  "command": "node scripts/npm-release-r48.mjs --verify-only",
31
- "expected": "PASS exact packed surface and isolated package version/doctor execution"
32
- },
33
- {
34
- "id": "r64-read-benchmark",
35
- "command": "node scripts/r64-read-benchmark.mjs <R63> <R64> <scratch> <output>",
36
- "expected": "PASS alternating same-host R63/R64 read and control-lane measurements without unexplained material regression"
31
+ "expected": "PASS exact packed surface, registry-safe release checks, isolated package version and doctor without publish"
37
32
  }
38
33
  ],
39
34
  "observed_pre_release_evidence": {
@@ -243,6 +238,72 @@
243
238
  "registry": "PENDING",
244
239
  "activation_rollback_restore": "PENDING",
245
240
  "focused_receipt_sha256": "010db961ecbe0aff98edfa7ee8f7db953f462c94a8e6cf0aaf6c5df229274ba7"
241
+ },
242
+ "r65_restored_safe_tdd": {
243
+ "status": "PASS_RED_THEN_GREEN",
244
+ "red": {
245
+ "tests": 2,
246
+ "passed": 0,
247
+ "failed": 2,
248
+ "receipt_id": "092a4b944c7bb653e63908e4",
249
+ "receipt_sha256": "f15f57a54aeb046e366292c4e91bc0b045be0f6a0780eb47fb5fbac596741eee"
250
+ },
251
+ "green": {
252
+ "tests": 2,
253
+ "passed": 2,
254
+ "failed": 0,
255
+ "receipt_id": "10e1e5a46d1673dd1d0636e7",
256
+ "receipt_sha256": "d859409d33f9f1a165889c5ce4360f2f83b8f4bb66f5b6ab63980b8464678a72"
257
+ }
258
+ },
259
+ "r65_focused_pre_final_metadata_freeze": {
260
+ "status": "PASS_PRE_FINAL_METADATA_FREEZE",
261
+ "tests": 74,
262
+ "passed": 74,
263
+ "failed": 0,
264
+ "skipped": 0,
265
+ "receipt_id": "ab40025003536ec1cb96692d",
266
+ "receipt_sha256": "4a6b3c0ecef62f29f1c3b386df56afd711428ab8f2d4db6d081ef3eca1278466",
267
+ "request_sha256": "86351d039db5c617b49a80c863b1d9880a71c297945f19ff50406638f86b34b3"
268
+ },
269
+ "r65_full_regression_pre_final_metadata_freeze": {
270
+ "status": "PASS_PRE_FINAL_METADATA_FREEZE",
271
+ "tests": 1363,
272
+ "passed": 1322,
273
+ "failed": 0,
274
+ "skipped": 41,
275
+ "receipt_id": "b645ec173577da59ff540270",
276
+ "receipt_sha256": "778638208d42e9b18d7df2d5f9f59ab2623d754a90adcaab859abdab6a251379",
277
+ "request_sha256": "8ac5a56b5f16f7d0859de91bae7b487fdfa533b8ee6bc27544e7d512b83c43db"
278
+ },
279
+ "final_gate_evidence_contract": {
280
+ "status": "PENDING",
281
+ "location": "D:\\Projects\\deadbyte-mcp\\testing\\0.15.42-r65",
282
+ "note": "Final focused/full/Windows/package signed receipts are intentionally external to candidate release bytes to avoid self-referential evidence."
283
+ },
284
+ "r65_focused_pre_metadata_refresh_current": {
285
+ "status": "PASS_PRE_METADATA_REFRESH",
286
+ "tests": 71,
287
+ "passed": 71,
288
+ "failed": 0,
289
+ "skipped": 0,
290
+ "receipt_id": "795ac2683d544675eec1388c",
291
+ "receipt_sha256": "a772ecdaffa32098eaf67bfaca7555ec971e4fa889f25329cb321a65f2f4a0ad",
292
+ "request_sha256": "2b4a5dc8e01e0207fa930a3c648415443046090628c649514e889b92d32b0ca6"
293
+ },
294
+ "r65_full_regression_pre_metadata_refresh_current": {
295
+ "status": "PASS_PRE_METADATA_REFRESH",
296
+ "tests": 1360,
297
+ "passed": 1319,
298
+ "failed": 0,
299
+ "skipped": 41,
300
+ "task_id": "4c2dfd186e985fd446db26e22357f0695a5873932b8f39c446331e35b57ee4f9",
301
+ "receipt_id": "93dd39c895029a299f5999c7",
302
+ "receipt_sha256": "424d264ac50c37ce0ef385df7a6d288ba3c22eda2588af0d40f245f8692659dc",
303
+ "request_sha256": "7467766fdb18558701cc115d4398f6f6e779d5f9a75b24c619333a9e12a918d2",
304
+ "result_file_sha256": "47a835df560e303bcd15a9cc87f53be88676be421c9cc2addd594ead44cbcd7d",
305
+ "stdout_sha256": "b96de9c3f24e289b3656c861368333c021c020ba5a6e1e53d502c5b8bb3ed115",
306
+ "stderr_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
246
307
  }
247
308
  },
248
309
  "inherited_parent_evidence": {
@@ -353,5 +414,36 @@
353
414
  "clean_machine": "WAIVED_BY_OPERATOR",
354
415
  "reason": "Operator explicitly requested immediate deployment without further testing.",
355
416
  "stable_final_claim": false
417
+ },
418
+ "r65": {
419
+ "parent_version": "0.15.41",
420
+ "parent_release_id": "v0.15.41-63a78ad159ad3003",
421
+ "parent_manifest_sha256": "63a78ad159ad3003db3fefafcd468bef22599c829a867f4f10a46c7a20748b3e",
422
+ "parent_generation_manifest_sha256": "19ae2efcdcde9f80c474f0e55851d4ada51c22813d3e05af03b11acb28c3fca5",
423
+ "public_surface_tool_count": 43,
424
+ "new_public_tools": 0,
425
+ "new_authority_scopes": 0,
426
+ "legacy_r64_auto_restore": false,
427
+ "epoch_native_restore_requires_continuity_proof": true,
428
+ "focused_pre_identity": "PASS_69_OF_69",
429
+ "full_regression_pre_identity": {
430
+ "tests": 1359,
431
+ "passed": 1317,
432
+ "failed": 2,
433
+ "skipped": 40,
434
+ "failures": [
435
+ "r64 historical release-contract harness drift",
436
+ "r65 expected identity not yet bumped"
437
+ ]
438
+ },
439
+ "prepublish_only": true,
440
+ "focused_post_identity": "PASS_69_OF_69",
441
+ "full_regression_post_identity": {
442
+ "tests": 1361,
443
+ "passed": 1320,
444
+ "failed": 0,
445
+ "skipped": 41,
446
+ "status": "PASS"
447
+ }
356
448
  }
357
449
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deadbyte-chatgpt-bridge",
3
- "version": "0.15.41",
3
+ "version": "0.15.42",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "engines": {
@@ -937,6 +937,47 @@ function Assert-PolicyRootsAvailable($Policy, [string]$Plane) {
937
937
  return $rootIds
938
938
  }
939
939
 
940
+ function Get-AuthorityEpochStatus($Cfg, [string]$Plane, [string]$GrantFile, [string]$GrantNonce) {
941
+ if ([string]::IsNullOrWhiteSpace($GrantNonce) -or $GrantNonce -cnotmatch '^[0-9a-f]{64}$') {
942
+ return [pscustomobject]@{ Trusted=$false; Reason='epoch-grant-nonce-invalid'; Seq=$null; Action=$null; EventSha256=$null }
943
+ }
944
+ try {
945
+ $verified = Invoke-AuthorityEpochCommand $Cfg $Plane 'status' $GrantFile
946
+ if (-not $verified.trusted) {
947
+ return [pscustomobject]@{ Trusted=$false; Reason=[string]$verified.reason; Seq=$verified.seq; Action=$verified.action; EventSha256=$verified.event_sha256 }
948
+ }
949
+ return [pscustomobject]@{ Trusted=$true; Reason=[string]$verified.reason; Seq=$verified.seq; Action=$verified.action; EventSha256=$verified.event_sha256 }
950
+ } catch {
951
+ return [pscustomobject]@{ Trusted=$false; Reason='authority-epoch-verifier-unavailable'; Seq=$null; Action=$null; EventSha256=$null }
952
+ }
953
+ }
954
+
955
+ function Invoke-AuthorityEpochCommand($Cfg, [string]$Plane, [string]$Action, [string]$GrantFile, [string]$UpdateId = '', [string]$ExpectedHead = '') {
956
+ $cli = Join-Path ([string]$Cfg.CoreRoot) 'src\authority-epoch-cli-r65.mjs'
957
+ if (-not (Test-Path -LiteralPath $cli -PathType Leaf)) { Fail "authority epoch CLI missing: $cli" }
958
+ $node = [string]$Cfg.Bridge.FilePath
959
+ if ([string]::IsNullOrWhiteSpace($node) -or -not (Test-Path -LiteralPath $node -PathType Leaf)) { Fail 'authority epoch Node executable unavailable' }
960
+ $policyFile = switch ($Plane) {
961
+ 'process' { [string]$Cfg.ProcessPolicyFile }
962
+ 'coding' { [string]$Cfg.CodingPolicyFile }
963
+ 'autonomous' { [string]$Cfg.AutonomousPolicyFile }
964
+ 'desktop' { [string]$Cfg.DesktopPolicyFile }
965
+ 'host' { [string]$Cfg.HostPolicyFile }
966
+ default { Fail "authority epoch plane invalid: $Plane" }
967
+ }
968
+ if ([string]::IsNullOrWhiteSpace($policyFile) -or -not (Test-Path -LiteralPath $policyFile -PathType Leaf)) { Fail "authority epoch policy unavailable for $Plane" }
969
+ $args = @($cli, $Action, '--plane', $Plane, '--grant-file', $GrantFile, '--policy-file', $policyFile)
970
+ if ($Action -in @('transaction-revoke','transaction-restore')) {
971
+ if ([string]::IsNullOrWhiteSpace($UpdateId) -or $ExpectedHead -cnotmatch '^[0-9a-f]{64}$') { Fail 'authority epoch transaction binding invalid' }
972
+ $args += @('--update-id', $UpdateId, '--expected-head', $ExpectedHead)
973
+ }
974
+ $output = @(& $node @args)
975
+ $exit = $LASTEXITCODE
976
+ if ($exit -ne 0) { Fail "authority epoch command '$Action' failed for $Plane (exit=$exit)" }
977
+ try { return (($output -join [Environment]::NewLine) | ConvertFrom-Json) }
978
+ catch { Fail "authority epoch command '$Action' returned invalid JSON for $Plane" }
979
+ }
980
+
940
981
  function Get-HostPolicyMetadata($Cfg) {
941
982
  if ([string]::IsNullOrWhiteSpace([string]$Cfg.HostPolicyFile)) { Fail 'privileged host plane is not configured' }
942
983
  $policyPath = [string]$Cfg.HostPolicyFile
@@ -961,7 +1002,10 @@ function Get-HostArmStatus($Cfg) {
961
1002
  try { $arm = Get-Content -LiteralPath $meta.ArmFile -Raw -Encoding UTF8 | ConvertFrom-Json } catch { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='invalid-grant' } }
962
1003
  if ($arm.schema -ne 'deadbyte.host-grant.v2') { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='grant-schema' } }
963
1004
  if ([string]$arm.policy_sha256 -ne [string]$meta.Sha256) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='policy-digest' } }
964
- return [pscustomobject]@{ Configured=$true; Armed=$true; Reason='standing-grant' }
1005
+ if ([string]$arm.instance_nonce -cnotmatch '^[0-9a-f]{64}$') { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='nonce-invalid' } }
1006
+ $epoch = Get-AuthorityEpochStatus $Cfg 'host' $meta.ArmFile ([string]$arm.instance_nonce)
1007
+ if (-not $epoch.Trusted) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason=[string]$epoch.Reason } }
1008
+ return [pscustomobject]@{ Configured=$true; Armed=$true; Reason='standing-grant'; EpochSeq=$epoch.Seq; EpochSha256=$epoch.EventSha256 }
965
1009
  }
966
1010
 
967
1011
  function Arm-Host($Cfg) {
@@ -981,15 +1025,23 @@ function Arm-Host($Cfg) {
981
1025
  $tmp = $meta.ArmFile + '.tmp'
982
1026
  $body | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath $tmp -Encoding UTF8
983
1027
  Move-Item -LiteralPath $tmp -Destination $meta.ArmFile -Force
1028
+ try { Invoke-AuthorityEpochCommand $Cfg 'host' 'grant' $meta.ArmFile | Out-Null }
1029
+ catch {
1030
+ Remove-Item -LiteralPath $meta.ArmFile -Force -ErrorAction SilentlyContinue
1031
+ throw
1032
+ }
984
1033
  Write-Host 'PRIVILEGED HOST PLANE ENABLED UNTIL EXPLICIT REVOKE'
985
1034
  }
986
1035
 
987
1036
  function Disarm-Host($Cfg) {
988
1037
  $meta = Get-HostPolicyMetadata $Cfg
1038
+ $epochError = $null
989
1039
  if (Test-Path -LiteralPath $meta.ArmFile) {
990
- Remove-Item -LiteralPath $meta.ArmFile -Force -ErrorAction Stop
1040
+ try { Invoke-AuthorityEpochCommand $Cfg 'host' 'user-revoke' $meta.ArmFile | Out-Null } catch { $epochError = $_.Exception }
1041
+ Remove-Item -LiteralPath $meta.ArmFile -Force -ErrorAction SilentlyContinue
991
1042
  }
992
1043
  if (Test-Path -LiteralPath $meta.ArmFile) { throw 'Host authority revocation failed: grant remains present' }
1044
+ if ($null -ne $epochError) { throw $epochError }
993
1045
  Write-Host 'PRIVILEGED HOST PLANE DISARMED'
994
1046
  }
995
1047
 
@@ -1021,10 +1073,13 @@ function Get-ProcessGrantStatus($Cfg) {
1021
1073
  try { $grant = Get-Content -LiteralPath $meta.GrantFile -Raw -Encoding UTF8 | ConvertFrom-Json } catch { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='invalid-grant' } }
1022
1074
  if ($grant.schema -ne 'deadbyte.process-grant.v1') { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='grant-schema' } }
1023
1075
  if ([string]$grant.policy_sha256 -ne [string]$meta.Sha256) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='policy-digest' } }
1076
+ if ([string]$grant.instance_nonce -cnotmatch '^[0-9a-f]{64}$') { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='nonce-invalid' } }
1024
1077
  $profiles = @($grant.profile_ids); $roots = @($grant.root_ids)
1025
1078
  if ($profiles.Count -lt 1 -or @($profiles | Where-Object { $_ -notin $meta.ProfileIds }).Count -gt 0) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='profiles-invalid' } }
1026
1079
  if ($roots.Count -lt 1 -or @($roots | Where-Object { $_ -notin $meta.RootIds }).Count -gt 0) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='roots-invalid' } }
1027
- return [pscustomobject]@{ Configured=$true; Armed=$true; Reason='standing-grant' }
1080
+ $epoch = Get-AuthorityEpochStatus $Cfg 'process' $meta.GrantFile ([string]$grant.instance_nonce)
1081
+ if (-not $epoch.Trusted) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason=[string]$epoch.Reason } }
1082
+ return [pscustomobject]@{ Configured=$true; Armed=$true; Reason='standing-grant'; EpochSeq=$epoch.Seq; EpochSha256=$epoch.EventSha256 }
1028
1083
  }
1029
1084
 
1030
1085
  function Arm-Process($Cfg) {
@@ -1045,12 +1100,23 @@ function Arm-Process($Cfg) {
1045
1100
  $tmp = $meta.GrantFile + '.tmp'
1046
1101
  $body | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath $tmp -Encoding UTF8
1047
1102
  Move-Item -LiteralPath $tmp -Destination $meta.GrantFile -Force
1103
+ try { Invoke-AuthorityEpochCommand $Cfg 'process' 'grant' $meta.GrantFile | Out-Null }
1104
+ catch {
1105
+ Remove-Item -LiteralPath $meta.GrantFile -Force -ErrorAction SilentlyContinue
1106
+ throw
1107
+ }
1048
1108
  Write-Host 'PROCESS PLANE ENABLED UNTIL EXPLICIT REVOKE'
1049
1109
  }
1050
1110
 
1051
1111
  function Disarm-Process($Cfg) {
1052
1112
  $meta = Get-ProcessPolicyMetadata $Cfg
1053
- Remove-Item -LiteralPath $meta.GrantFile -Force -ErrorAction SilentlyContinue
1113
+ $epochError = $null
1114
+ if (Test-Path -LiteralPath $meta.GrantFile -PathType Leaf) {
1115
+ try { Invoke-AuthorityEpochCommand $Cfg 'process' 'user-revoke' $meta.GrantFile | Out-Null } catch { $epochError = $_.Exception }
1116
+ Remove-Item -LiteralPath $meta.GrantFile -Force -ErrorAction SilentlyContinue
1117
+ }
1118
+ if (Test-Path -LiteralPath $meta.GrantFile) { throw 'Process authority revocation failed: grant remains present' }
1119
+ if ($null -ne $epochError) { throw $epochError }
1054
1120
  Write-Host 'PROCESS PLANE DISARMED'
1055
1121
  }
1056
1122
 
@@ -1080,9 +1146,12 @@ function Get-CodingLeaseStatus($Cfg) {
1080
1146
  try { $lease = Get-Content -LiteralPath $meta.LeaseFile -Raw -Encoding UTF8 | ConvertFrom-Json } catch { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='invalid-grant' } }
1081
1147
  if ($lease.schema -ne 'deadbyte.coding-grant.v2') { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='grant-schema' } }
1082
1148
  if ([string]$lease.policy_sha256 -ne [string]$meta.Sha256) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='policy-digest' } }
1149
+ if ([string]$lease.instance_nonce -cnotmatch '^[0-9a-f]{64}$') { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='nonce-invalid' } }
1083
1150
  $roots = @($lease.root_ids)
1084
1151
  if ($roots.Count -lt 1 -or @($roots | Where-Object { $_ -notin $meta.RootIds }).Count -gt 0) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='roots-invalid' } }
1085
- return [pscustomobject]@{ Configured=$true; Armed=$true; Reason='standing-grant' }
1152
+ $epoch = Get-AuthorityEpochStatus $Cfg 'coding' $meta.LeaseFile ([string]$lease.instance_nonce)
1153
+ if (-not $epoch.Trusted) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason=[string]$epoch.Reason } }
1154
+ return [pscustomobject]@{ Configured=$true; Armed=$true; Reason='standing-grant'; EpochSeq=$epoch.Seq; EpochSha256=$epoch.EventSha256 }
1086
1155
  }
1087
1156
 
1088
1157
  function Arm-Coding($Cfg) {
@@ -1103,13 +1172,27 @@ function Arm-Coding($Cfg) {
1103
1172
  $tmp = $meta.LeaseFile + '.tmp'
1104
1173
  $body | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath $tmp -Encoding UTF8
1105
1174
  Move-Item -LiteralPath $tmp -Destination $meta.LeaseFile -Force
1175
+ try { Invoke-AuthorityEpochCommand $Cfg 'coding' 'grant' $meta.LeaseFile | Out-Null }
1176
+ catch {
1177
+ Remove-Item -LiteralPath $meta.LeaseFile -Force -ErrorAction SilentlyContinue
1178
+ throw
1179
+ }
1106
1180
  Write-Host 'CODING PLANE ENABLED UNTIL EXPLICIT REVOKE'
1107
1181
  }
1108
1182
 
1109
1183
  function Disarm-Coding($Cfg) {
1110
1184
  $meta = Get-CodingPolicyMetadata $Cfg
1111
- Remove-Item -LiteralPath $meta.LeaseFile -Force -ErrorAction SilentlyContinue
1112
- try { Disarm-Autonomous $Cfg -Quiet } catch { Write-Warning "autonomous lease cleanup failed after coding revocation: $($_.Exception.Message)" }
1185
+ $epochError = $null
1186
+ if (Test-Path -LiteralPath $meta.LeaseFile -PathType Leaf) {
1187
+ try { Invoke-AuthorityEpochCommand $Cfg 'coding' 'user-revoke' $meta.LeaseFile | Out-Null } catch { $epochError = $_.Exception }
1188
+ Remove-Item -LiteralPath $meta.LeaseFile -Force -ErrorAction SilentlyContinue
1189
+ }
1190
+ try { Disarm-Autonomous $Cfg -Quiet } catch {
1191
+ if ($null -eq $epochError) { $epochError = $_.Exception }
1192
+ else { Write-Warning "autonomous lease cleanup failed after coding revocation: $($_.Exception.Message)" }
1193
+ }
1194
+ if (Test-Path -LiteralPath $meta.LeaseFile) { throw 'Coding authority revocation failed: grant remains present' }
1195
+ if ($null -ne $epochError) { throw $epochError }
1113
1196
  Write-Host 'CODING PLANE DISARMED; AUTONOMOUS AUTHORITY REVOKED'
1114
1197
  }
1115
1198
 
@@ -1145,9 +1228,12 @@ function Get-AutonomousLeaseStatus($Cfg) {
1145
1228
  if ($lease.schema -ne 'deadbyte.autonomous-grant.v2') { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='grant-schema' } }
1146
1229
  if ([string]$lease.policy_sha256 -ne [string]$meta.Sha256) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='policy-digest' } }
1147
1230
  if ([string]$lease.coding_policy_sha256 -ne [string]$meta.CodingPolicySha256) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='coding-policy-digest' } }
1231
+ if ([string]$lease.instance_nonce -cnotmatch '^[0-9a-f]{64}$') { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='nonce-invalid' } }
1148
1232
  $roots = @($lease.root_ids)
1149
1233
  if ($roots.Count -lt 1 -or @($roots | Where-Object { $_ -notin $meta.RootIds }).Count -gt 0) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='roots-invalid' } }
1150
- return [pscustomobject]@{ Configured=$true; Armed=$true; Reason='standing-grant' }
1234
+ $epoch = Get-AuthorityEpochStatus $Cfg 'autonomous' $meta.LeaseFile ([string]$lease.instance_nonce)
1235
+ if (-not $epoch.Trusted) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason=[string]$epoch.Reason } }
1236
+ return [pscustomobject]@{ Configured=$true; Armed=$true; Reason='standing-grant'; EpochSeq=$epoch.Seq; EpochSha256=$epoch.EventSha256 }
1151
1237
  }
1152
1238
 
1153
1239
  function Arm-Autonomous($Cfg) {
@@ -1164,13 +1250,24 @@ function Arm-Autonomous($Cfg) {
1164
1250
  $tmp = $meta.LeaseFile + '.tmp'
1165
1251
  $body | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath $tmp -Encoding UTF8
1166
1252
  Move-Item -LiteralPath $tmp -Destination $meta.LeaseFile -Force
1253
+ try { Invoke-AuthorityEpochCommand $Cfg 'autonomous' 'grant' $meta.LeaseFile | Out-Null }
1254
+ catch {
1255
+ Remove-Item -LiteralPath $meta.LeaseFile -Force -ErrorAction SilentlyContinue
1256
+ throw
1257
+ }
1167
1258
  Write-Host 'AUTONOMOUS PLANE ENABLED UNTIL EXPLICIT REVOKE'
1168
1259
  }
1169
1260
 
1170
1261
  function Disarm-Autonomous($Cfg, [switch]$Quiet) {
1171
1262
  if ([string]::IsNullOrWhiteSpace([string]$Cfg.AutonomousPolicyFile)) { return }
1172
1263
  $meta = Get-AutonomousPolicyMetadata $Cfg
1173
- Remove-Item -LiteralPath $meta.LeaseFile -Force -ErrorAction SilentlyContinue
1264
+ $epochError = $null
1265
+ if (Test-Path -LiteralPath $meta.LeaseFile -PathType Leaf) {
1266
+ try { Invoke-AuthorityEpochCommand $Cfg 'autonomous' 'user-revoke' $meta.LeaseFile | Out-Null } catch { $epochError = $_.Exception }
1267
+ Remove-Item -LiteralPath $meta.LeaseFile -Force -ErrorAction SilentlyContinue
1268
+ }
1269
+ if (Test-Path -LiteralPath $meta.LeaseFile) { throw 'Autonomous authority revocation failed: grant remains present' }
1270
+ if ($null -ne $epochError) { throw $epochError }
1174
1271
  if (-not $Quiet) { Write-Host 'AUTONOMOUS PLANE DISARMED' }
1175
1272
  }
1176
1273
 
@@ -1244,7 +1341,9 @@ function Get-DesktopGrantStatus($Cfg) {
1244
1341
  $unique = @($actions | Sort-Object -Unique)
1245
1342
  if ($actions.Count -lt 1 -or $actions.Count -ne $unique.Count) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='actions-invalid'; ActionKinds=@() } }
1246
1343
  if (@($actions | Where-Object { $_ -notin $meta.ActionKinds }).Count -gt 0) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason='actions-outside-policy'; ActionKinds=@() } }
1247
- return [pscustomobject]@{ Configured=$true; Armed=$true; Reason='standing-grant'; ActionKinds=$actions }
1344
+ $epoch = Get-AuthorityEpochStatus $Cfg 'desktop' $meta.GrantFile ([string]$grant.instance_nonce)
1345
+ if (-not $epoch.Trusted) { return [pscustomobject]@{ Configured=$true; Armed=$false; Reason=[string]$epoch.Reason; ActionKinds=$actions } }
1346
+ return [pscustomobject]@{ Configured=$true; Armed=$true; Reason='standing-grant'; ActionKinds=$actions; EpochSeq=$epoch.Seq; EpochSha256=$epoch.EventSha256 }
1248
1347
  }
1249
1348
 
1250
1349
  function Arm-Desktop($Cfg) {
@@ -1265,13 +1364,24 @@ function Arm-Desktop($Cfg) {
1265
1364
  $tmp = $meta.GrantFile + '.tmp'
1266
1365
  $body | ConvertTo-Json -Depth 6 | Set-Content -LiteralPath $tmp -Encoding UTF8
1267
1366
  Move-Item -LiteralPath $tmp -Destination $meta.GrantFile -Force
1367
+ try { Invoke-AuthorityEpochCommand $Cfg 'desktop' 'grant' $meta.GrantFile | Out-Null }
1368
+ catch {
1369
+ Remove-Item -LiteralPath $meta.GrantFile -Force -ErrorAction SilentlyContinue
1370
+ throw
1371
+ }
1268
1372
  Write-Host ("DESKTOP PLANE ENABLED UNTIL EXPLICIT REVOKE [{0}]" -f ($meta.ActionKinds -join ','))
1269
1373
  }
1270
1374
 
1271
1375
  function Disarm-Desktop($Cfg, [switch]$Quiet) {
1272
1376
  $grantFile = Get-DesktopGrantFileForRevoke $Cfg
1273
1377
  if ([string]::IsNullOrWhiteSpace([string]$grantFile)) { return }
1274
- Remove-Item -LiteralPath $grantFile -Force -ErrorAction SilentlyContinue
1378
+ $epochError = $null
1379
+ if (Test-Path -LiteralPath $grantFile -PathType Leaf) {
1380
+ try { Invoke-AuthorityEpochCommand $Cfg 'desktop' 'user-revoke' $grantFile | Out-Null } catch { $epochError = $_.Exception }
1381
+ Remove-Item -LiteralPath $grantFile -Force -ErrorAction SilentlyContinue
1382
+ }
1383
+ if (Test-Path -LiteralPath $grantFile) { throw 'Desktop authority revocation failed: grant remains present' }
1384
+ if ($null -ne $epochError) { throw $epochError }
1275
1385
  if (-not $Quiet) { Write-Host 'DESKTOP PLANE DISARMED' }
1276
1386
  }
1277
1387
 
@@ -1346,7 +1456,17 @@ function Convert-OwnedObservation($Owned) {
1346
1456
  }
1347
1457
 
1348
1458
  function Convert-AuthorityObservation($Authority) {
1349
- [ordered]@{ configured=[bool]$Authority.Configured; armed=[bool]$Authority.Armed; reason=(Get-BoundedObservationReason $Authority.Reason) }
1459
+ $out = [ordered]@{ configured=[bool]$Authority.Configured; armed=[bool]$Authority.Armed; reason=(Get-BoundedObservationReason $Authority.Reason) }
1460
+ $seqProp = $Authority.PSObject.Properties['EpochSeq']
1461
+ $shaProp = $Authority.PSObject.Properties['EpochSha256']
1462
+ if ($null -ne $seqProp -or $null -ne $shaProp) {
1463
+ if ($null -eq $seqProp -or $null -eq $shaProp -or [int64]$seqProp.Value -lt 1 -or [string]$shaProp.Value -cnotmatch '^[0-9a-f]{64}$') {
1464
+ Fail 'authority epoch observation incomplete or invalid'
1465
+ }
1466
+ $out['epoch_seq'] = [int64]$seqProp.Value
1467
+ $out['epoch_sha256'] = [string]$shaProp.Value
1468
+ }
1469
+ return $out
1350
1470
  }
1351
1471
 
1352
1472
  function Get-DownstreamCoreObservation($Cfg, $Bridge) {