sneakoscope 8.1.2 → 8.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (261) hide show
  1. package/README.md +96 -58
  2. package/crates/sks-core/Cargo.lock +1 -1
  3. package/crates/sks-core/Cargo.toml +1 -1
  4. package/dist/bin/fast-inline.js +5 -51
  5. package/dist/cli/command-manifest-lite.js +2 -1
  6. package/dist/cli/command-registry.js +2 -1
  7. package/dist/cli/global-mode-router.js +1 -1
  8. package/dist/cli/install-helpers-codex-lb-config.js +112 -914
  9. package/dist/cli/install-helpers-codex-lb-shared.js +3 -44
  10. package/dist/cli/install-helpers-install-support.js +4 -20
  11. package/dist/cli/install-helpers.js +36 -2716
  12. package/dist/cli/router.js +9 -9
  13. package/dist/commands/bridge-command-output.js +111 -0
  14. package/dist/commands/bridge.js +320 -0
  15. package/dist/commands/codex-app.js +39 -123
  16. package/dist/commands/doctor-helpers.js +380 -0
  17. package/dist/commands/doctor-profile.js +3 -0
  18. package/dist/commands/doctor.js +114 -873
  19. package/dist/commands/mad-sks.js +0 -4
  20. package/dist/config/skills-manifest.json +1 -1
  21. package/dist/core/agents/agent-effort-policy.js +11 -21
  22. package/dist/core/agents/agent-recursion-guard.js +26 -0
  23. package/dist/core/agents/agent-runner-codex-exec.js +7 -9
  24. package/dist/core/architecture-hardening/contracts/contracts.js +225 -161
  25. package/dist/core/architecture-hardening/state/state-service.js +49 -13
  26. package/dist/core/auto-review.js +15 -9
  27. package/dist/core/codex/codex-config-guard.js +8 -0
  28. package/dist/core/codex-adapter.js +8 -10
  29. package/dist/core/codex-app/codex-app-fast-ui-repair.js +7 -29
  30. package/dist/core/codex-app/codex-app-launcher.js +10 -12
  31. package/dist/core/codex-app/codex-app-restart.js +10 -12
  32. package/dist/core/codex-app/menubar/constants.js +2 -5
  33. package/dist/core/codex-app/menubar/global-install.js +3 -2
  34. package/dist/core/codex-app/menubar/installer/result.js +23 -0
  35. package/dist/core/codex-app/menubar/installer/runtime.js +28 -0
  36. package/dist/core/codex-app/menubar/installer.js +5 -96
  37. package/dist/core/codex-app/menubar/migration.js +1 -42
  38. package/dist/core/codex-app/openrouter-provider.js +0 -78
  39. package/dist/core/codex-app.js +97 -360
  40. package/dist/core/codex-control/codex-app-server-runtime-env.js +8 -28
  41. package/dist/core/codex-control/codex-current-image-path-real-probe.js +2 -3
  42. package/dist/core/codex-control/codex-current-web-search-probe.js +2 -3
  43. package/dist/core/codex-control/codex-sdk-adapter.js +5 -48
  44. package/dist/core/codex-control/codex-task-runner.js +16 -60
  45. package/dist/core/codex-control/desktop-bridge-launch-guard.js +227 -0
  46. package/dist/core/codex-exec-output-schema.js +11 -13
  47. package/dist/core/codex-lb/bridge-contracts.js +2 -0
  48. package/dist/core/codex-lb/bridge-runtime-validation/capability.js +104 -0
  49. package/dist/core/codex-lb/bridge-runtime-validation/catalog.js +52 -0
  50. package/dist/core/codex-lb/bridge-runtime-validation/shared.js +109 -0
  51. package/dist/core/codex-lb/bridge-runtime-validation/status.js +250 -0
  52. package/dist/core/codex-lb/bridge-runtime-validation.js +106 -0
  53. package/dist/core/codex-lb/capability-runner.js +505 -201
  54. package/dist/core/codex-lb/codex-lb-env.js +179 -12
  55. package/dist/core/codex-lb/combined-catalog/builder.js +86 -0
  56. package/dist/core/codex-lb/combined-catalog/contracts.js +5 -0
  57. package/dist/core/codex-lb/combined-catalog/normalize.js +170 -0
  58. package/dist/core/codex-lb/combined-catalog/persistence.js +207 -0
  59. package/dist/core/codex-lb/combined-catalog/shared.js +12 -0
  60. package/dist/core/codex-lb/combined-catalog/storage.js +171 -0
  61. package/dist/core/codex-lb/combined-catalog.js +12 -0
  62. package/dist/core/codex-lb/desktop-bridge/client.js +4 -1
  63. package/dist/core/codex-lb/desktop-bridge/header-policy.js +48 -63
  64. package/dist/core/codex-lb/desktop-bridge/http-forward.js +115 -83
  65. package/dist/core/codex-lb/desktop-bridge/launchd.js +20 -13
  66. package/dist/core/codex-lb/desktop-bridge/location-rewrite.js +4 -1
  67. package/dist/core/codex-lb/desktop-bridge/security.js +381 -267
  68. package/dist/core/codex-lb/desktop-bridge/server.js +148 -19
  69. package/dist/core/codex-lb/desktop-bridge/state.js +56 -70
  70. package/dist/core/codex-lb/desktop-bridge/types.js +6 -1
  71. package/dist/core/codex-lb/desktop-bridge/websocket-forward.js +281 -106
  72. package/dist/core/codex-lb/desktop-bridge-migration/historical-config.js +245 -0
  73. package/dist/core/codex-lb/desktop-bridge-migration/historical-toml.js +56 -0
  74. package/dist/core/codex-lb/desktop-bridge-migration/metadata.js +73 -0
  75. package/dist/core/codex-lb/desktop-bridge-migration/receipt.js +52 -0
  76. package/dist/core/codex-lb/desktop-bridge-migration/retired-runtime-cleanup.js +106 -0
  77. package/dist/core/codex-lb/desktop-bridge-migration/types.js +1 -0
  78. package/dist/core/codex-lb/desktop-bridge-migration.js +238 -0
  79. package/dist/core/codex-lb/desktop-controller-v3/catalog.js +257 -0
  80. package/dist/core/codex-lb/desktop-controller-v3/diagnostics.js +62 -0
  81. package/dist/core/codex-lb/desktop-controller-v3/lifecycle-commands.js +203 -0
  82. package/dist/core/codex-lb/desktop-controller-v3/live-probes.js +293 -0
  83. package/dist/core/codex-lb/desktop-controller-v3/preflight-probes.js +144 -0
  84. package/dist/core/codex-lb/desktop-controller-v3/provider-commands.js +182 -0
  85. package/dist/core/codex-lb/desktop-controller-v3/shared.js +279 -0
  86. package/dist/core/codex-lb/desktop-controller-v3/status.js +269 -0
  87. package/dist/core/codex-lb/desktop-controller-v3/types.js +1 -0
  88. package/dist/core/codex-lb/desktop-controller-v3/verification.js +89 -0
  89. package/dist/core/codex-lb/desktop-controller-v3.js +67 -0
  90. package/dist/core/codex-lb/desktop-controller.js +2 -1730
  91. package/dist/core/codex-lb/desktop-service.js +462 -627
  92. package/dist/core/codex-lb/migration-receipt.js +560 -118
  93. package/dist/core/codex-lb/probes/auxiliary-surfaces-probe.js +37 -53
  94. package/dist/core/codex-lb/probes/bridge-probe.js +125 -64
  95. package/dist/core/codex-lb/probes/catalog-probe.js +36 -136
  96. package/dist/core/codex-lb/probes/computer-use-probe.js +63 -39
  97. package/dist/core/codex-lb/probes/image-generation-probe.js +98 -41
  98. package/dist/core/codex-lb/probes/probe-evidence.js +32 -33
  99. package/dist/core/codex-lb/probes/voice-realtime-probe.js +69 -43
  100. package/dist/core/codex-lb/provider-credentials/configuration.js +127 -0
  101. package/dist/core/codex-lb/provider-credentials/locks.js +11 -0
  102. package/dist/core/codex-lb/provider-credentials/private-snapshot.js +28 -0
  103. package/dist/core/codex-lb/provider-credentials/removal.js +33 -0
  104. package/dist/core/codex-lb/provider-credentials/resolution.js +59 -0
  105. package/dist/core/codex-lb/provider-credentials/runtime.js +55 -0
  106. package/dist/core/codex-lb/provider-credentials/types.js +1 -0
  107. package/dist/core/codex-lb/provider-credentials/validation-store.js +137 -0
  108. package/dist/core/codex-lb/provider-credentials.js +5 -0
  109. package/dist/core/codex-lb/provider-registry.js +323 -0
  110. package/dist/core/codex-lb/provider-route-policy.js +118 -0
  111. package/dist/core/codex-lb/request-route-resolver.js +172 -0
  112. package/dist/core/codex-lb/route-index.js +148 -0
  113. package/dist/core/codex-lb/trusted-deep-evidence.js +158 -286
  114. package/dist/core/commands/basic-cli.js +1 -1
  115. package/dist/core/commands/check-command.js +3 -10
  116. package/dist/core/commands/gate-result-contract.js +10 -14
  117. package/dist/core/commands/intent-normalization/normalizer.js +1 -1
  118. package/dist/core/commands/mad-sks-command.js +2 -6
  119. package/dist/core/commands/release-command.js +11 -1
  120. package/dist/core/commands/telegram-command.js +46 -6
  121. package/dist/core/doctor/doctor-readiness-matrix.js +9 -7
  122. package/dist/core/doctor/skill-legacy-surface.js +5 -5
  123. package/dist/core/evidence/v2/evidence-key.js +30 -3
  124. package/dist/core/feature-fixtures.js +8 -1
  125. package/dist/core/feature-registry.js +3 -2
  126. package/dist/core/hooks-runtime/stop-finalization.js +11 -1
  127. package/dist/core/hooks-runtime/subagent-context.js +15 -1
  128. package/dist/core/hooks-runtime/subagent-skill-availability-contract.js +1 -1
  129. package/dist/core/hooks-runtime/tool-output-quarantine.js +1 -1
  130. package/dist/core/hooks-runtime.js +73 -87
  131. package/dist/core/image-ux-review/imagegen-adapter.js +108 -94
  132. package/dist/core/image-ux-review/real-callout-extractor.js +144 -14
  133. package/dist/core/imagegen/desktop-bridge-imagegen-target.js +77 -0
  134. package/dist/core/imagegen/imagegen-capability.js +43 -151
  135. package/dist/core/init/skills/filesystem.js +89 -0
  136. package/dist/core/init/skills/inventory.js +97 -0
  137. package/dist/core/init/skills/manifest.js +151 -0
  138. package/dist/core/init/skills.js +5 -325
  139. package/dist/core/init.js +0 -63
  140. package/dist/core/install/installed-package-smoke.js +1 -1
  141. package/dist/core/managed-assets/managed-assets-manifest.js +0 -1
  142. package/dist/core/policy/latest-version-guidance.js +15 -2
  143. package/dist/core/preflight/parallel-preflight-engine.js +27 -51
  144. package/dist/core/provider/provider-badge.js +9 -4
  145. package/dist/core/provider/provider-context.js +57 -107
  146. package/dist/core/providers/openrouter/openrouter-account.js +3 -1
  147. package/dist/core/providers/openrouter/openrouter-secret-store.js +91 -22
  148. package/dist/core/release/desktop-bridge-release-evidence.js +457 -0
  149. package/dist/core/release/gate-manifest.js +0 -1
  150. package/dist/core/release/main-push-guard.js +13 -0
  151. package/dist/core/release/main-push-receipt.js +11 -0
  152. package/dist/core/release/physical-release-gates.js +664 -61
  153. package/dist/core/release/publish-preflight.js +3 -3
  154. package/dist/core/release/release-gate-batch-runner.js +19 -6
  155. package/dist/core/release/release-gate-dag.js +33 -6
  156. package/dist/core/release/release-gate-node.js +1 -3
  157. package/dist/core/release/release-gate-output-contract.js +55 -0
  158. package/dist/core/release/release-pack-contract.js +1 -1
  159. package/dist/core/release/release-pack-receipt.js +209 -8
  160. package/dist/core/release/release-real-contract.js +1 -1
  161. package/dist/core/release/stage-publish.js +106 -28
  162. package/dist/core/retention/temp-lease.js +204 -0
  163. package/dist/core/retention.js +18 -195
  164. package/dist/core/routes.js +1 -2
  165. package/dist/core/safety/intent-contract/intent-contract.js +3 -3
  166. package/dist/core/subagents/naruto-host-credentials.js +6 -1
  167. package/dist/core/subagents/official-subagent-config.js +27 -9
  168. package/dist/core/subagents/official-subagent-runner.js +14 -31
  169. package/dist/core/subagents/wave-lifecycle.js +36 -8
  170. package/dist/core/subagents/wave-parent-guidance.js +2 -1
  171. package/dist/core/telegram/doctor.js +2 -2
  172. package/dist/core/telegram/liveness.js +10 -4
  173. package/dist/core/triwiki/context-graph/compiler/index.js +18 -18
  174. package/dist/core/update/update-migration-state/fast-mode-config.js +172 -0
  175. package/dist/core/update/update-migration-state/session-state-split.js +247 -0
  176. package/dist/core/update/update-migration-state/simple-stages.js +46 -0
  177. package/dist/core/update/update-migration-state.js +4 -481
  178. package/dist/core/version.js +1 -1
  179. package/dist/native/sks-menubar/Sources/OperationCoordinator.swift +28 -4
  180. package/dist/native/sks-menubar/Sources/OperationModels.swift +112 -2
  181. package/dist/native/sks-menubar/Sources/ProviderRouteExplanation.swift +21 -0
  182. package/dist/native/sks-menubar/Sources/ProvidersBridgeCatalog.swift +140 -0
  183. package/dist/native/sks-menubar/Sources/ProvidersOpenRouter.swift +107 -470
  184. package/dist/native/sks-menubar/Sources/ProvidersReliability.swift +27 -197
  185. package/dist/native/sks-menubar/Sources/ProvidersRoutingTruth.swift +335 -269
  186. package/dist/native/sks-menubar/Sources/ProvidersViewController.swift +233 -437
  187. package/dist/native/sks-menubar/Sources/RemoteCodingViewController.swift +16 -7
  188. package/dist/native/sks-menubar/Sources/SecureProcessEnvelope.swift +39 -9
  189. package/dist/native/sks-menubar/Sources/TelegramSupport.swift +56 -0
  190. package/dist/scripts/canonical-test-runner.js +7 -1
  191. package/dist/scripts/check-runtime-schemas.js +7 -2
  192. package/dist/scripts/codex-sdk-real-smoke-check.js +3 -1
  193. package/dist/scripts/desktop-bridge-capabilities-check.js +123 -0
  194. package/dist/scripts/{codex-lb-desktop-bridge-latency-check.js → desktop-bridge-latency-check.js} +61 -16
  195. package/dist/scripts/desktop-bridge-real-evidence-check.js +64 -0
  196. package/dist/scripts/{codex-lb-desktop-bridge-check.js → desktop-bridge-transport-check.js} +92 -155
  197. package/dist/scripts/desktop-bridge-transport-client.js +116 -0
  198. package/dist/scripts/desktop-bridge-unification-check.js +276 -0
  199. package/dist/scripts/doctor-fixes-codex-app-fast-ui-check.js +12 -8
  200. package/dist/scripts/gate-policy-audit-check.js +52 -2
  201. package/dist/scripts/provider-badge-context-check.js +55 -12
  202. package/dist/scripts/publish-preflight.js +1 -2
  203. package/dist/scripts/release-affected-selector-check.js +1 -2
  204. package/dist/scripts/release-aggressive-resource-governor-check.js +1 -1
  205. package/dist/scripts/release-cache-glob-hashing-check.js +1 -0
  206. package/dist/scripts/release-cache-version-neutral-fixture-check.js +1 -0
  207. package/dist/scripts/release-full-parallelism-blackbox.js +1 -1
  208. package/dist/scripts/release-gate-batch-runner-check.js +9 -0
  209. package/dist/scripts/release-gate-dag-runner-check.js +6 -0
  210. package/dist/scripts/release-gate-dag-runner.js +4 -2
  211. package/dist/scripts/release-metadata-check.js +16 -3
  212. package/dist/scripts/release-pack-receipt.js +29 -6
  213. package/dist/scripts/release-physical-gates-check.js +39 -0
  214. package/dist/scripts/release-real-check.js +7 -5
  215. package/package.json +6 -8
  216. package/release-gates.v2.json +156 -157
  217. package/runtime-required-scripts.json +11 -11
  218. package/schemas/codex/desktop-bridge-status-v3.schema.json +286 -0
  219. package/schemas/codex/desktop-capabilities-v3.schema.json +198 -0
  220. package/schemas/release/release-gate-node.schema.json +2 -3
  221. package/dist/cli/codex-lb-setup-warning-output.js +0 -17
  222. package/dist/cli/install-helpers-codex-lb-chain.js +0 -529
  223. package/dist/commands/codex-lb.js +0 -1232
  224. package/dist/core/architecture-hardening/migration/migration.js +0 -111
  225. package/dist/core/codex-app/auxiliary-oauth-policy.js +0 -36
  226. package/dist/core/codex-app/catalog-compat/catalog-service.js +0 -104
  227. package/dist/core/codex-app/child-policy/child-policy.js +0 -35
  228. package/dist/core/codex-app/desktop-routing-snapshot.js +0 -233
  229. package/dist/core/codex-app/glm-model-profile.js +0 -1
  230. package/dist/core/codex-app/glm-profile-installer.js +0 -191
  231. package/dist/core/codex-app/glm-profile-schema.js +0 -42
  232. package/dist/core/codex-app/multi-provider-router.js +0 -391
  233. package/dist/core/codex-app/openrouter-activate.js +0 -405
  234. package/dist/core/codex-app/openrouter-model-catalog.js +0 -217
  235. package/dist/core/codex-app/provider-child-policy.js +0 -64
  236. package/dist/core/codex-app/provider-mode.js +0 -91
  237. package/dist/core/codex-app/provider-session-policy.js +0 -85
  238. package/dist/core/codex-app/session-policy/session-pinning.js +0 -68
  239. package/dist/core/codex-control/codex-lb-launch-recovery.js +0 -319
  240. package/dist/core/codex-lb/codex-lb-setup.js +0 -293
  241. package/dist/core/codex-lb/codex-lb-tool-catalog.js +0 -456
  242. package/dist/core/codex-lb/codex-lb-tool-output-recovery.js +0 -290
  243. package/dist/core/codex-lb/desktop-center-credentials.js +0 -1083
  244. package/dist/core/codex-lb/desktop-mode.js +0 -32
  245. package/dist/core/codex-lb/desktop-real-evidence.js +0 -168
  246. package/dist/core/codex-lb/legacy-migration.js +0 -576
  247. package/dist/core/codex-lb/native-openai-transport/transport.js +0 -68
  248. package/dist/core/codex-lb/provider-routing/provider-router.js +0 -58
  249. package/dist/core/codex-lb/routing-truth.js +0 -327
  250. package/dist/core/imagegen/codex-lb-imagegen-target.js +0 -92
  251. package/dist/native/sks-menubar/Sources/ProvidersConnectTest.swift +0 -118
  252. package/dist/native/sks-menubar/Sources/ProvidersFastMode.swift +0 -17
  253. package/dist/native/sks-menubar/Sources/ProvidersMultiProvider.swift +0 -331
  254. package/dist/native/sks-menubar/Sources/ProvidersRoleModels.swift +0 -260
  255. package/dist/scripts/codex-lb-catalog-passthrough-check.js +0 -120
  256. package/dist/scripts/codex-lb-desktop-auth-invariant-check.js +0 -169
  257. package/dist/scripts/codex-lb-desktop-capabilities-check.js +0 -287
  258. package/dist/scripts/codex-lb-desktop-real-evidence-check.js +0 -123
  259. package/dist/scripts/codex-lb-fast-mode-truth-check.js +0 -114
  260. package/dist/scripts/codex-lb-fast-ui-preservation-check.js +0 -152
  261. package/dist/scripts/codex-lb-gpt56-fast-profile-check.js +0 -231
@@ -0,0 +1,457 @@
1
+ import crypto from 'node:crypto';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ export const DESKTOP_BRIDGE_RELEASE_EVIDENCE_SCHEMA = 'sks.desktop-bridge-release-evidence.v1';
5
+ export const DESKTOP_BRIDGE_PRODUCTION_ADAPTER_RECEIPT_SCHEMA = 'sks.desktop-bridge-production-adapter-receipt.v1';
6
+ export const DESKTOP_BRIDGE_RELEASE_PROVIDERS = ['codex-lb', 'openrouter'];
7
+ export const DESKTOP_BRIDGE_RELEASE_DEEP_CAPABILITIES = [
8
+ 'fast_mode',
9
+ 'image_generation',
10
+ 'computer_use',
11
+ 'browser_use',
12
+ 'voice_mode',
13
+ 'plugins',
14
+ 'auxiliary_surfaces'
15
+ ];
16
+ const SHA256_RE = /^[a-f0-9]{64}$/i;
17
+ const ID_RE = /^[a-z0-9][a-z0-9._:/-]{2,159}$/i;
18
+ const MAX_EVIDENCE_FILE_BYTES = 16 * 1024 * 1024;
19
+ const MIN_NATIVE_SCREENSHOT_WIDTH = 640;
20
+ const MIN_NATIVE_SCREENSHOT_HEIGHT = 360;
21
+ const MAX_RELEASE_EVIDENCE_AGE_MS = 7 * 24 * 60 * 60 * 1000;
22
+ const MAX_RELEASE_EVIDENCE_FUTURE_SKEW_MS = 5 * 60 * 1000;
23
+ export function desktopBridgeReleaseSourceIdentitySha256(version, sourceCommit) {
24
+ return sha256(Buffer.from(`sks.desktop-bridge-release-source.v1\n${version}\n${sourceCommit.toLowerCase()}\n`));
25
+ }
26
+ export function desktopBridgeDeepArtifactManifestSha256(value) {
27
+ const artifacts = Array.isArray(value) ? value : [];
28
+ const rows = artifacts.map((entry) => ({
29
+ provider_id: String(entry?.provider_id || ''),
30
+ capability: String(entry?.capability || ''),
31
+ artifact_path: String(entry?.artifact_path || ''),
32
+ artifact_sha256: String(entry?.artifact_sha256 || '').toLowerCase(),
33
+ producer_receipt_id: String(entry?.producer_receipt_id || '')
34
+ })).sort((left, right) => canonicalJson(left).localeCompare(canonicalJson(right)));
35
+ return sha256(Buffer.from(canonicalJson(rows)));
36
+ }
37
+ export function inspectDesktopBridgeReleaseEvidence(input) {
38
+ const evidenceRoot = path.resolve(input.evidenceRoot);
39
+ const blockers = [];
40
+ const reportFile = resolveEvidenceFile(evidenceRoot, input.reportPath);
41
+ const reportBytes = reportFile ? readRegularFile(reportFile, 'report', blockers) : null;
42
+ const report = reportBytes ? parseJson(reportBytes, 'report', blockers) : null;
43
+ const reportSha256 = reportBytes ? sha256(reportBytes) : null;
44
+ const sourceIdentitySha256 = desktopBridgeReleaseSourceIdentitySha256(input.expectedVersion, input.expectedSourceCommit);
45
+ if (!reportFile)
46
+ blockers.push('desktop_bridge_release_report_path_invalid');
47
+ if (report?.schema !== DESKTOP_BRIDGE_RELEASE_EVIDENCE_SCHEMA)
48
+ blockers.push('desktop_bridge_release_report_schema_invalid');
49
+ if (report?.ok !== true || report?.status !== 'passed' || report?.release_authorizing !== true) {
50
+ blockers.push('desktop_bridge_release_report_not_authorizing');
51
+ }
52
+ if (report?.evidence_kind !== 'real'
53
+ || report?.fixture !== false
54
+ || report?.mock !== false
55
+ || report?.synthetic !== false)
56
+ blockers.push('desktop_bridge_release_report_not_real');
57
+ if (report?.capture_platform !== 'darwin' || report?.native_runtime !== 'desktop-bridge') {
58
+ blockers.push('desktop_bridge_release_platform_invalid');
59
+ }
60
+ if (report?.package_version !== input.expectedVersion)
61
+ blockers.push('desktop_bridge_release_version_mismatch');
62
+ if (report?.source_commit !== input.expectedSourceCommit)
63
+ blockers.push('desktop_bridge_release_source_commit_mismatch');
64
+ if (report?.source_identity_sha256 !== sourceIdentitySha256)
65
+ blockers.push('desktop_bridge_release_source_identity_mismatch');
66
+ const now = input.now?.getTime() ?? Date.now();
67
+ if (!validFreshDate(report?.captured_at, now))
68
+ blockers.push('desktop_bridge_release_capture_time_invalid');
69
+ if (!Array.isArray(report?.blockers) || report.blockers.length > 0)
70
+ blockers.push('desktop_bridge_release_report_blockers_present');
71
+ if (containsSecretMaterial(report))
72
+ blockers.push('desktop_bridge_release_secret_material_present');
73
+ const providerIds = validateProviders(report?.providers, blockers);
74
+ validateOAuth(report?.oauth, blockers);
75
+ validateWebSocket(report?.websocket, blockers);
76
+ const screenshotPath = String(report?.native_ui?.screenshot_path || '');
77
+ const screenshot = validateBoundArtifact({
78
+ evidenceRoot,
79
+ relativePath: screenshotPath,
80
+ expectedSha256: report?.native_ui?.screenshot_sha256,
81
+ label: 'native_screenshot',
82
+ blockers
83
+ });
84
+ if (report?.native_ui?.schema !== 'sks.desktop-bridge-native-ui-evidence.v1'
85
+ || report?.native_ui?.app !== 'sks-menubar'
86
+ || report?.native_ui?.visible_provider_ids?.length !== DESKTOP_BRIDGE_RELEASE_PROVIDERS.length
87
+ || !sameStrings(report?.native_ui?.visible_provider_ids, DESKTOP_BRIDGE_RELEASE_PROVIDERS)
88
+ || report?.native_ui?.fixture !== false
89
+ || report?.native_ui?.mock !== false
90
+ || report?.native_ui?.synthetic !== false)
91
+ blockers.push('desktop_bridge_release_native_ui_contract_invalid');
92
+ if (screenshot.bytes && !validNativeScreenshot(screenshot.bytes))
93
+ blockers.push('desktop_bridge_release_native_screenshot_invalid');
94
+ const deepArtifacts = Array.isArray(report?.deep_artifacts) ? report.deep_artifacts : [];
95
+ validateDeepArtifacts(deepArtifacts, evidenceRoot, blockers);
96
+ const adapter = validateProductionAdapterReceipt({
97
+ value: report?.production_adapter,
98
+ evidenceRoot,
99
+ expectedVersion: input.expectedVersion,
100
+ expectedSourceCommit: input.expectedSourceCommit,
101
+ expectedSourceIdentitySha256: sourceIdentitySha256,
102
+ now,
103
+ deepArtifacts,
104
+ blockers
105
+ });
106
+ return {
107
+ schema: 'sks.desktop-bridge-release-evidence-inspection.v1',
108
+ ok: blockers.length === 0,
109
+ report_path: reportFile ? relative(evidenceRoot, reportFile) : input.reportPath,
110
+ report_sha256: reportSha256,
111
+ adapter_receipt_path: adapter.path,
112
+ adapter_receipt_sha256: adapter.sha256,
113
+ adapter_id: adapter.adapter_id,
114
+ adapter_version: adapter.adapter_version,
115
+ adapter_run_id: adapter.run_id,
116
+ adapter_receipt_id: adapter.receipt_id,
117
+ native_screenshot_path: screenshot.path,
118
+ native_screenshot_sha256: screenshot.sha256,
119
+ providers: providerIds,
120
+ deep_artifact_count: deepArtifacts.length,
121
+ blockers: unique(blockers)
122
+ };
123
+ }
124
+ function validateProviders(value, blockers) {
125
+ if (!isRecord(value) || !sameStrings(Object.keys(value), DESKTOP_BRIDGE_RELEASE_PROVIDERS)) {
126
+ blockers.push('desktop_bridge_release_provider_inventory_invalid');
127
+ return [];
128
+ }
129
+ const verified = [];
130
+ for (const providerId of DESKTOP_BRIDGE_RELEASE_PROVIDERS) {
131
+ const provider = value[providerId];
132
+ const valid = isRecord(provider)
133
+ && provider.provider_id === providerId
134
+ && provider.enabled === true
135
+ && provider.credential_state === 'ready'
136
+ && /^sha256:[a-f0-9]{64}$/i.test(String(provider.credential_fingerprint || ''))
137
+ && provider.auth_verified === true
138
+ && provider.catalog_verified === true
139
+ && provider.text_response_verified === true
140
+ && provider.no_fallback_verified === true
141
+ && sameStrings(provider.deep_capabilities, DESKTOP_BRIDGE_RELEASE_DEEP_CAPABILITIES)
142
+ && Array.isArray(provider.blockers)
143
+ && provider.blockers.length === 0;
144
+ if (!valid)
145
+ blockers.push(`desktop_bridge_release_provider_invalid:${providerId}`);
146
+ else
147
+ verified.push(providerId);
148
+ }
149
+ return verified;
150
+ }
151
+ function validateOAuth(value, blockers) {
152
+ if (!isRecord(value)
153
+ || value.schema !== 'sks.desktop-bridge-oauth-preservation-evidence.v1'
154
+ || !SHA256_RE.test(String(value.auth_before_sha256 || ''))
155
+ || value.auth_before_sha256 !== value.auth_after_sha256
156
+ || !SHA256_RE.test(String(value.semantic_identity_before_sha256 || ''))
157
+ || value.semantic_identity_before_sha256 !== value.semantic_identity_after_sha256
158
+ || value.semantic_identity_preserved !== true
159
+ || value.auth_file_bytes_preserved !== true
160
+ || value.oauth_forwarded_to_provider !== false
161
+ || value.fixture !== false
162
+ || value.mock !== false
163
+ || value.synthetic !== false)
164
+ blockers.push('desktop_bridge_release_oauth_preservation_invalid');
165
+ }
166
+ function validateWebSocket(value, blockers) {
167
+ if (!isRecord(value)
168
+ || value.schema !== 'sks.desktop-bridge-websocket-release-evidence.v1'
169
+ || value.upgrade_verified !== true
170
+ || value.protocol_verified !== true
171
+ || value.frame_round_trip_verified !== true
172
+ || value.clean_close_verified !== true
173
+ || value.fixture !== false
174
+ || value.mock !== false
175
+ || value.synthetic !== false
176
+ || !Number.isFinite(value.latency_ms)
177
+ || Number(value.latency_ms) < 0)
178
+ blockers.push('desktop_bridge_release_websocket_invalid');
179
+ }
180
+ function validateDeepArtifacts(value, evidenceRoot, blockers) {
181
+ const expected = new Set(DESKTOP_BRIDGE_RELEASE_PROVIDERS.flatMap((providerId) => DESKTOP_BRIDGE_RELEASE_DEEP_CAPABILITIES.map((capability) => `${providerId}:${capability}`)));
182
+ const seen = new Set();
183
+ const paths = new Set();
184
+ for (const artifact of value) {
185
+ const providerId = String(artifact?.provider_id || '');
186
+ const capability = String(artifact?.capability || '');
187
+ const key = `${providerId}:${capability}`;
188
+ if (!expected.has(key)) {
189
+ blockers.push(`desktop_bridge_release_deep_artifact_unknown:${key}`);
190
+ continue;
191
+ }
192
+ if (seen.has(key))
193
+ blockers.push(`desktop_bridge_release_deep_artifact_duplicate:${key}`);
194
+ seen.add(key);
195
+ if (artifact?.schema !== 'sks.desktop-bridge-deep-artifact.v1'
196
+ || artifact?.evidence_kind !== 'real'
197
+ || artifact?.attempted !== true
198
+ || artifact?.verified !== true
199
+ || artifact?.stale !== false
200
+ || artifact?.fixture !== false
201
+ || artifact?.mock !== false
202
+ || artifact?.synthetic !== false
203
+ || !ID_RE.test(String(artifact?.producer_receipt_id || ''))) {
204
+ blockers.push(`desktop_bridge_release_deep_artifact_invalid:${key}`);
205
+ }
206
+ const bound = validateBoundArtifact({
207
+ evidenceRoot,
208
+ relativePath: String(artifact?.artifact_path || ''),
209
+ expectedSha256: artifact?.artifact_sha256,
210
+ label: `deep_artifact:${key}`,
211
+ blockers
212
+ });
213
+ if (bound.bytes && containsSecretBytes(bound.bytes))
214
+ blockers.push(`desktop_bridge_release_deep_artifact_secret_material:${key}`);
215
+ if (bound.path && paths.has(bound.path))
216
+ blockers.push(`desktop_bridge_release_deep_artifact_path_reused:${bound.path}`);
217
+ if (bound.path)
218
+ paths.add(bound.path);
219
+ }
220
+ for (const key of expected) {
221
+ if (!seen.has(key))
222
+ blockers.push(`desktop_bridge_release_deep_artifact_missing:${key}`);
223
+ }
224
+ }
225
+ function validateProductionAdapterReceipt(input) {
226
+ const adapter = input.value;
227
+ if (!isRecord(adapter)
228
+ || adapter.schema !== 'sks.desktop-bridge-production-adapter-binding.v1'
229
+ || !ID_RE.test(String(adapter.adapter_id || ''))
230
+ || !ID_RE.test(String(adapter.adapter_version || ''))
231
+ || !ID_RE.test(String(adapter.run_id || ''))
232
+ || !ID_RE.test(String(adapter.receipt_id || ''))
233
+ || adapter.execution_mode !== 'production'
234
+ || adapter.fixture !== false
235
+ || adapter.mock !== false
236
+ || adapter.synthetic !== false) {
237
+ input.blockers.push('desktop_bridge_release_production_adapter_invalid');
238
+ }
239
+ const receipt = validateBoundArtifact({
240
+ evidenceRoot: input.evidenceRoot,
241
+ relativePath: String(adapter?.receipt_path || ''),
242
+ expectedSha256: adapter?.receipt_sha256,
243
+ label: 'production_adapter_receipt',
244
+ blockers: input.blockers
245
+ });
246
+ const parsed = receipt.bytes ? parseJson(receipt.bytes, 'production_adapter_receipt', input.blockers) : null;
247
+ if (parsed?.schema !== DESKTOP_BRIDGE_PRODUCTION_ADAPTER_RECEIPT_SCHEMA
248
+ || parsed?.ok !== true
249
+ || parsed?.release_authorizing !== true
250
+ || parsed?.execution_mode !== 'production'
251
+ || parsed?.adapter_id !== adapter?.adapter_id
252
+ || parsed?.adapter_version !== adapter?.adapter_version
253
+ || parsed?.run_id !== adapter?.run_id
254
+ || parsed?.receipt_id !== adapter?.receipt_id
255
+ || parsed?.package_version !== input.expectedVersion
256
+ || parsed?.source_commit !== input.expectedSourceCommit
257
+ || parsed?.source_identity_sha256 !== input.expectedSourceIdentitySha256
258
+ || parsed?.fixture !== false
259
+ || parsed?.mock !== false
260
+ || parsed?.synthetic !== false
261
+ || parsed?.redacted !== true
262
+ || parsed?.secrets_present !== false
263
+ || !sameStrings(parsed?.provider_ids, DESKTOP_BRIDGE_RELEASE_PROVIDERS)
264
+ || parsed?.artifact_manifest_sha256 !== desktopBridgeDeepArtifactManifestSha256(input.deepArtifacts)
265
+ || !validFreshDate(parsed?.executed_at, input.now)
266
+ || !Array.isArray(parsed?.blockers)
267
+ || parsed.blockers.length > 0
268
+ || containsSecretMaterial(parsed))
269
+ input.blockers.push('desktop_bridge_release_production_adapter_receipt_invalid');
270
+ const mismatchedProducer = input.deepArtifacts.some((artifact) => artifact?.producer_receipt_id !== adapter?.receipt_id);
271
+ if (mismatchedProducer)
272
+ input.blockers.push('desktop_bridge_release_deep_artifact_producer_mismatch');
273
+ return {
274
+ path: receipt.path,
275
+ sha256: receipt.sha256,
276
+ adapter_id: ID_RE.test(String(parsed?.adapter_id || '')) ? String(parsed.adapter_id) : null,
277
+ adapter_version: ID_RE.test(String(parsed?.adapter_version || '')) ? String(parsed.adapter_version) : null,
278
+ run_id: ID_RE.test(String(parsed?.run_id || '')) ? String(parsed.run_id) : null,
279
+ receipt_id: ID_RE.test(String(parsed?.receipt_id || '')) ? String(parsed.receipt_id) : null
280
+ };
281
+ }
282
+ function validateBoundArtifact(input) {
283
+ const file = resolveEvidenceFile(input.evidenceRoot, input.relativePath);
284
+ if (!file) {
285
+ input.blockers.push(`desktop_bridge_release_${input.label}_path_invalid`);
286
+ return { path: null, sha256: null, bytes: null };
287
+ }
288
+ const bytes = readRegularFile(file, input.label, input.blockers);
289
+ if (!bytes)
290
+ return { path: relative(input.evidenceRoot, file), sha256: null, bytes: null };
291
+ const actual = sha256(bytes);
292
+ if (!SHA256_RE.test(String(input.expectedSha256 || '')) || actual !== String(input.expectedSha256).toLowerCase()) {
293
+ input.blockers.push(`desktop_bridge_release_${input.label}_hash_mismatch`);
294
+ }
295
+ return { path: relative(input.evidenceRoot, file), sha256: actual, bytes };
296
+ }
297
+ function resolveEvidenceFile(root, relativePath) {
298
+ if (!relativePath || path.isAbsolute(relativePath))
299
+ return null;
300
+ const file = path.resolve(root, relativePath);
301
+ const rel = path.relative(path.resolve(root), file);
302
+ return rel && !rel.startsWith('..') && !path.isAbsolute(rel) ? file : null;
303
+ }
304
+ function readRegularFile(file, label, blockers) {
305
+ try {
306
+ const stat = fs.lstatSync(file);
307
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.size < 1 || stat.size > MAX_EVIDENCE_FILE_BYTES) {
308
+ blockers.push(`desktop_bridge_release_${label}_file_invalid`);
309
+ return null;
310
+ }
311
+ return fs.readFileSync(file);
312
+ }
313
+ catch {
314
+ blockers.push(`desktop_bridge_release_${label}_missing`);
315
+ return null;
316
+ }
317
+ }
318
+ function validNativeScreenshot(bytes) {
319
+ const signature = Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]);
320
+ if (bytes.length < signature.length + 12 || !bytes.subarray(0, signature.length).equals(signature))
321
+ return false;
322
+ let offset = signature.length;
323
+ let chunkIndex = 0;
324
+ let sawHeader = false;
325
+ let sawImageData = false;
326
+ let sawEnd = false;
327
+ while (offset < bytes.length) {
328
+ if (sawEnd || offset + 12 > bytes.length)
329
+ return false;
330
+ const length = bytes.readUInt32BE(offset);
331
+ const chunkEnd = offset + 12 + length;
332
+ if (chunkEnd > bytes.length)
333
+ return false;
334
+ const typeBytes = bytes.subarray(offset + 4, offset + 8);
335
+ const type = typeBytes.toString('ascii');
336
+ if (!/^[A-Za-z]{4}$/.test(type))
337
+ return false;
338
+ const data = bytes.subarray(offset + 8, offset + 8 + length);
339
+ const expectedCrc = bytes.readUInt32BE(offset + 8 + length);
340
+ if (pngCrc32(Buffer.concat([typeBytes, data])) !== expectedCrc)
341
+ return false;
342
+ if (chunkIndex === 0 && type !== 'IHDR')
343
+ return false;
344
+ if (type === 'IHDR') {
345
+ if (sawHeader || length !== 13)
346
+ return false;
347
+ sawHeader = true;
348
+ const width = data.readUInt32BE(0);
349
+ const height = data.readUInt32BE(4);
350
+ const bitDepth = data[8];
351
+ const colorType = data[9];
352
+ const validBitDepth = (colorType === 0 && [1, 2, 4, 8, 16].includes(bitDepth))
353
+ || (colorType === 2 && [8, 16].includes(bitDepth))
354
+ || (colorType === 3 && [1, 2, 4, 8].includes(bitDepth))
355
+ || ([4, 6].includes(colorType) && [8, 16].includes(bitDepth));
356
+ if (width < MIN_NATIVE_SCREENSHOT_WIDTH
357
+ || height < MIN_NATIVE_SCREENSHOT_HEIGHT
358
+ || !validBitDepth
359
+ || data[10] !== 0
360
+ || data[11] !== 0
361
+ || ![0, 1].includes(data[12]))
362
+ return false;
363
+ }
364
+ else if (!sawHeader) {
365
+ return false;
366
+ }
367
+ else if (type === 'IDAT') {
368
+ if (length < 1 || sawEnd)
369
+ return false;
370
+ sawImageData = true;
371
+ }
372
+ else if (type === 'IEND') {
373
+ if (length !== 0 || !sawImageData)
374
+ return false;
375
+ sawEnd = true;
376
+ }
377
+ offset = chunkEnd;
378
+ chunkIndex += 1;
379
+ }
380
+ return sawHeader && sawImageData && sawEnd && offset === bytes.length;
381
+ }
382
+ function pngCrc32(bytes) {
383
+ let crc = 0xffffffff;
384
+ for (const byte of bytes) {
385
+ crc ^= byte;
386
+ for (let bit = 0; bit < 8; bit += 1) {
387
+ crc = (crc >>> 1) ^ (0xedb88320 & -(crc & 1));
388
+ }
389
+ }
390
+ return (crc ^ 0xffffffff) >>> 0;
391
+ }
392
+ function parseJson(bytes, label, blockers) {
393
+ try {
394
+ const parsed = JSON.parse(bytes.toString('utf8'));
395
+ if (!isRecord(parsed))
396
+ throw new Error('not_object');
397
+ return parsed;
398
+ }
399
+ catch {
400
+ blockers.push(`desktop_bridge_release_${label}_json_invalid`);
401
+ return null;
402
+ }
403
+ }
404
+ function containsSecretMaterial(value) {
405
+ const visit = (entry) => {
406
+ if (Array.isArray(entry))
407
+ return entry.some(visit);
408
+ if (!isRecord(entry)) {
409
+ return typeof entry === 'string' && /\b(?:sk|or|sess|key)-[A-Za-z0-9_-]{8,}\b|Bearer\s+[A-Za-z0-9._~+/-]{8,}/i.test(entry);
410
+ }
411
+ for (const [key, child] of Object.entries(entry)) {
412
+ if (/(?:authorization|api[_-]?key|access[_-]?token|refresh[_-]?token|password|cookie|secret_value|credential_value)/i.test(key))
413
+ return true;
414
+ if (visit(child))
415
+ return true;
416
+ }
417
+ return false;
418
+ };
419
+ return visit(value);
420
+ }
421
+ function containsSecretBytes(bytes) {
422
+ if (bytes.includes(0))
423
+ return false;
424
+ const text = bytes.toString('utf8');
425
+ return /(?:"|')?(?:authorization|api[_-]?key|access[_-]?token|refresh[_-]?token|password|cookie|secret_value|credential_value)(?:"|')?\s*[:=]/i.test(text)
426
+ || /\b(?:sk|or|sess|key)-[A-Za-z0-9_-]{8,}\b|Bearer\s+[A-Za-z0-9._~+/-]{8,}/i.test(text);
427
+ }
428
+ function sameStrings(value, expected) {
429
+ if (!Array.isArray(value) || value.length !== expected.length)
430
+ return false;
431
+ return JSON.stringify(value.map(String).sort()) === JSON.stringify([...expected].sort());
432
+ }
433
+ function validFreshDate(value, now) {
434
+ const timestamp = typeof value === 'string' ? Date.parse(value) : Number.NaN;
435
+ return Number.isFinite(timestamp)
436
+ && timestamp <= now + MAX_RELEASE_EVIDENCE_FUTURE_SKEW_MS
437
+ && now - timestamp <= MAX_RELEASE_EVIDENCE_AGE_MS;
438
+ }
439
+ function relative(root, file) {
440
+ return path.relative(path.resolve(root), path.resolve(file)).split(path.sep).join('/');
441
+ }
442
+ function sha256(bytes) {
443
+ return crypto.createHash('sha256').update(bytes).digest('hex');
444
+ }
445
+ function canonicalJson(value) {
446
+ if (Array.isArray(value))
447
+ return `[${value.map(canonicalJson).join(',')}]`;
448
+ if (isRecord(value))
449
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`).join(',')}}`;
450
+ return JSON.stringify(value) ?? 'null';
451
+ }
452
+ function isRecord(value) {
453
+ return Boolean(value && typeof value === 'object' && !Array.isArray(value));
454
+ }
455
+ function unique(values) {
456
+ return [...new Set(values)];
457
+ }
@@ -76,7 +76,6 @@ export function affectedGlobsFor(id) {
76
76
  case 'postinstall':
77
77
  return [
78
78
  'src/cli/install-helpers.ts',
79
- 'src/cli/install-helpers-codex-lb-selftest.ts',
80
79
  'src/cli/install-helpers-install-support.ts',
81
80
  'src/core/init.ts',
82
81
  'src/core/install/installed-package-smoke.ts',
@@ -3,6 +3,7 @@ import { readMacosMenubarProof, validateMacosMenubarProofArtifacts } from './mac
3
3
  import { fileSha256, gitOk, gitText, readJson, relative, unique } from './release-proof-io.js';
4
4
  import { releaseOriginIdentity } from './release-origin.js';
5
5
  import { releaseProofDir, validateLocalReleasePackBinding } from './release-pack-receipt.js';
6
+ import { validatePhysicalReleaseGateInspection } from './physical-release-gates.js';
6
7
  import { validateFullReleaseStamp } from './release-stamp-proof.js';
7
8
  import { RELEASE_UPGRADE_BASELINE_SHA256, RELEASE_UPGRADE_BASELINE_VERSION, releaseUpgradeExpectedVersion, releaseUpgradeProofFilename } from './release-upgrade-baseline.js';
8
9
  export const MAIN_PUSH_GUARD_SCHEMA = 'sks.release-main-push-guard.v1';
@@ -92,6 +93,17 @@ export function inspectMainPushGuard(input) {
92
93
  upgradeReportSha256: upgrade.sha256,
93
94
  targetTarballSha256: pack?.sha256
94
95
  }).blockers);
96
+ if (input.requirePhysicalProof !== true)
97
+ blockers.push('physical_proof_requirement_missing');
98
+ const physical = input.requirePhysicalProof && head
99
+ ? validatePhysicalReleaseGateInspection({
100
+ root: input.root,
101
+ version: input.expectedVersion,
102
+ sourceCommit: head
103
+ })
104
+ : null;
105
+ if (physical && !physical.ok)
106
+ blockers.push(...physical.blockers.map((blocker) => `physical_proof:${blocker}`));
95
107
  if (input.requireCleanTree !== true)
96
108
  blockers.push('clean_tree_requirement_missing');
97
109
  return {
@@ -108,6 +120,7 @@ export function inspectMainPushGuard(input) {
108
120
  pack_proof: input.requirePackProof ? path.relative(input.root, path.join(proofDir, 'pack-receipt.json')) : null,
109
121
  upgrade_proof: upgrade,
110
122
  macos_proof: input.requireMacosProof ? path.relative(input.root, path.join(proofDir, 'macos-menubar-proof.json')) : null,
123
+ physical_proof: physical?.path || null,
111
124
  force_push_allowed: false,
112
125
  blockers: unique(blockers),
113
126
  checked_at: new Date().toISOString()
@@ -6,6 +6,7 @@ import { gitOk, gitText, readJson } from './release-proof-io.js';
6
6
  import { releaseProofDir, validateLocalReleasePackBinding } from './release-pack-receipt.js';
7
7
  import { validateFullReleaseStamp } from './release-stamp-proof.js';
8
8
  import { releaseOriginIdentity } from './release-origin.js';
9
+ import { validatePhysicalReleaseGateInspection } from './physical-release-gates.js';
9
10
  export const MAIN_PUSH_RECEIPT_SCHEMA = 'sks.main-push-receipt.v1';
10
11
  export function inspectMainPushReceipt(input) {
11
12
  const blockers = [];
@@ -77,6 +78,15 @@ export function inspectMainPushReceipt(input) {
77
78
  });
78
79
  if (!macosValidation.ok)
79
80
  blockers.push(...macosValidation.blockers);
81
+ const physical = validatePhysicalReleaseGateInspection({
82
+ root: input.root,
83
+ version: input.version,
84
+ sourceCommit: head
85
+ });
86
+ if (!physical.ok)
87
+ blockers.push(...physical.blockers.map((blocker) => `physical_proof:${blocker}`));
88
+ if (guard?.physical_proof !== physical.path)
89
+ blockers.push('pre_push_guard_physical_proof_mismatch');
80
90
  return {
81
91
  schema: MAIN_PUSH_RECEIPT_SCHEMA,
82
92
  ok: blockers.length === 0,
@@ -94,6 +104,7 @@ export function inspectMainPushReceipt(input) {
94
104
  pack_proof: packProof,
95
105
  upgrade_proof: upgrade,
96
106
  macos_proof: macosProof,
107
+ physical_proof: physical.path,
97
108
  blockers: [...new Set(blockers)]
98
109
  };
99
110
  }