@tokenoftrust/storefront-runner 1.4.2-rc.0 → 2.0.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 (363) hide show
  1. package/apps/storefront/astro.config.mjs +3 -3
  2. package/apps/storefront/env.d.ts +54 -5
  3. package/apps/storefront/integrations/materialize-guard.mjs +12 -14
  4. package/apps/storefront/migrations-apps/0004_deep_morph.sql +36 -0
  5. package/apps/storefront/migrations-apps/0005_common_mystique.sql +23 -0
  6. package/apps/storefront/migrations-apps/0006_broad_microchip.sql +16 -0
  7. package/apps/storefront/migrations-apps/0007_brave_outlaw_kid.sql +15 -0
  8. package/apps/storefront/migrations-apps/0008_blue_dazzler.sql +11 -0
  9. package/apps/storefront/migrations-apps/0009_bored_shinobi_shaw.sql +15 -0
  10. package/apps/storefront/migrations-apps/0010_ws4_verified_provider_measurement.sql +35 -0
  11. package/apps/storefront/migrations-apps/meta/0004_snapshot.json +1474 -0
  12. package/apps/storefront/migrations-apps/meta/0005_snapshot.json +1617 -0
  13. package/apps/storefront/migrations-apps/meta/0006_snapshot.json +1716 -0
  14. package/apps/storefront/migrations-apps/meta/0007_snapshot.json +1812 -0
  15. package/apps/storefront/migrations-apps/meta/0008_snapshot.json +1881 -0
  16. package/apps/storefront/migrations-apps/meta/0009_snapshot.json +1979 -0
  17. package/apps/storefront/migrations-apps/meta/_journal.json +42 -0
  18. package/apps/storefront/public/apps/tot.demo.analytics/0.1.0/entry.js +42 -0
  19. package/apps/storefront/public/platform/amplitude-http/v1/entry.mjs +19 -0
  20. package/apps/storefront/public/platform/google-measurement/v1/entry.mjs +19 -0
  21. package/apps/storefront/public/shared/commerce-chrome.css +20 -2
  22. package/apps/storefront/scripts/build-v84-clean-clone-standalone.mjs +68 -0
  23. package/apps/storefront/scripts/deny-v84-clean-clone-standalone-capabilities.mjs +111 -0
  24. package/apps/storefront/scripts/deny-v84-dogfood-capabilities.mjs +2 -0
  25. package/apps/storefront/scripts/deny-v84-lifecycle-capabilities.mjs +247 -0
  26. package/apps/storefront/scripts/dogfood-v84-nonportable-routes.ts +73 -0
  27. package/apps/storefront/scripts/fixed-v84-native-install-producer.ts +79 -0
  28. package/apps/storefront/scripts/generated/v84-clean-clone-replay.bundle.mjs +10982 -0
  29. package/apps/storefront/scripts/import-v84-through-ws2.ts +38 -0
  30. package/apps/storefront/scripts/initialize-v84-lifecycle-tooling-dependency.ts +2 -0
  31. package/apps/storefront/scripts/initialize-v84-lifecycle-tooling.ts +4 -0
  32. package/apps/storefront/scripts/install-v84-native-through-ws1.ts +185 -0
  33. package/apps/storefront/scripts/prove-clone-isolation.ts +506 -0
  34. package/apps/storefront/scripts/replay-v84-clean-clone-pass.ts +148 -0
  35. package/apps/storefront/scripts/replay-v84-clean-clone-standalone.ts +35 -0
  36. package/apps/storefront/scripts/replay-v84-clean-clone.ts +214 -0
  37. package/apps/storefront/scripts/run-fixed-v84-native-install-producer.mjs +18 -0
  38. package/apps/storefront/scripts/run-v84-clone-isolation-proof.mjs +18 -0
  39. package/apps/storefront/scripts/run-v84-clone-lifecycle-proof.mjs +18 -0
  40. package/apps/storefront/scripts/run-v84-import-through-ws2-proof.mjs +17 -0
  41. package/apps/storefront/scripts/run-v84-nonportable-route-dogfood.mjs +15 -0
  42. package/apps/storefront/scripts/sanitize-v84-proof-environment.mjs +21 -0
  43. package/apps/storefront/scripts/v84CleanCloneGraphPin.ts +42 -0
  44. package/apps/storefront/scripts/v84CleanCloneSourceGraph.ts +145 -0
  45. package/apps/storefront/scripts/validate-v84-clone-lifecycle.ts +18 -0
  46. package/apps/storefront/src/components/Img.astro +1 -1
  47. package/apps/storefront/src/components/admin/AdminBlogTab.astro +19 -16
  48. package/apps/storefront/src/components/admin/AdminIntegrationsTab.astro +105 -0
  49. package/apps/storefront/src/components/admin/AdminPublishTab.astro +1057 -412
  50. package/apps/storefront/src/components/admin/AdminSettingsTab.astro +2 -2
  51. package/apps/storefront/src/components/admin/orders/OrdersWorkspace.astro +5 -5
  52. package/apps/storefront/src/components/chrome/NavDropdown.astro +12 -0
  53. package/apps/storefront/src/components/chrome/SiteFooter.astro +7 -2
  54. package/apps/storefront/src/components/chrome/SiteHeader.astro +46 -10
  55. package/apps/storefront/src/components/compliance/AdultSignatureNotice.astro +1 -1
  56. package/apps/storefront/src/components/compliance/ComplianceNotice.astro +1 -2
  57. package/apps/storefront/src/components/compliance/ExciseTaxNotice.astro +1 -2
  58. package/apps/storefront/src/components/compliance/PactActNotice.astro +1 -1
  59. package/apps/storefront/src/components/compliance/Prop65Warning.astro +1 -2
  60. package/apps/storefront/src/components/compliance/PurchaseLimitNotice.astro +2 -3
  61. package/apps/storefront/src/components/compliance/ShippingRestrictionNotice.astro +2 -2
  62. package/apps/storefront/src/components/compliance/StateEligibilityNotice.astro +2 -3
  63. package/apps/storefront/src/components/content/TrustStrip.astro +4 -4
  64. package/apps/storefront/src/components/islands/MobileNav.tsx +26 -1
  65. package/apps/storefront/src/components/islands/VariantSelector.tsx +27 -2
  66. package/apps/storefront/src/components/islands/useCheckoutHandoffCorrelation.ts +75 -0
  67. package/apps/storefront/src/components/membership/IllustrativeLabel.astro +1 -2
  68. package/apps/storefront/src/components/membership/TierCards.astro +2 -2
  69. package/apps/storefront/src/components/membership/TierComparisonTable.astro +2 -2
  70. package/apps/storefront/src/components/subscription/SavingsExplainer.astro +2 -2
  71. package/apps/storefront/src/config/adminTenantLookup.ts +35 -0
  72. package/apps/storefront/src/config/devTenantSeed.ts +9 -9
  73. package/apps/storefront/src/config/resolver.ts +4 -4
  74. package/apps/storefront/src/layouts/Layout.astro +100 -20
  75. package/apps/storefront/src/lib/activity/candidateSubmitLease.ts +87 -0
  76. package/apps/storefront/src/lib/activity/changeActorAttribution.ts +86 -6
  77. package/apps/storefront/src/lib/activity/deployVersion.ts +1 -1
  78. package/apps/storefront/src/lib/admin/adminShell.ts +2 -0
  79. package/apps/storefront/src/lib/admin/envelope.ts +1 -2
  80. package/apps/storefront/src/lib/apps/adminService.ts +10 -0
  81. package/apps/storefront/src/lib/apps/adminSession.ts +1 -1
  82. package/apps/storefront/src/lib/apps/appVersionStore.ts +281 -0
  83. package/apps/storefront/src/lib/apps/consentConfigStore.ts +228 -0
  84. package/apps/storefront/src/lib/apps/gtmMigrationInstall.ts +447 -0
  85. package/apps/storefront/src/lib/apps/gtmMigrationReport.ts +367 -0
  86. package/apps/storefront/src/lib/apps/gtmMigrationTab.ts +315 -0
  87. package/apps/storefront/src/lib/apps/integrationLifecycle.ts +614 -0
  88. package/apps/storefront/src/lib/apps/integrationLifecycleController.ts +125 -0
  89. package/apps/storefront/src/lib/apps/integrationReadModel.ts +563 -0
  90. package/apps/storefront/src/lib/apps/integrationsTab.ts +547 -0
  91. package/apps/storefront/src/lib/apps/integrationsView.ts +106 -0
  92. package/apps/storefront/src/lib/apps/managedAnalyticsService.ts +599 -0
  93. package/apps/storefront/src/lib/apps/orders/orderConversionD1.ts +150 -0
  94. package/apps/storefront/src/lib/apps/orders/orderForwardReceiver.ts +8 -0
  95. package/apps/storefront/src/lib/apps/orders/ordersStore.ts +1 -1
  96. package/apps/storefront/src/lib/apps/orders/verifiedProviderMeasurement.ts +117 -0
  97. package/apps/storefront/src/lib/apps/registryService.ts +264 -10
  98. package/apps/storefront/src/lib/apps/tenantIntegrationMaterialization.ts +170 -0
  99. package/apps/storefront/src/lib/apps/v84CleanCloneReplayContext.ts +16 -0
  100. package/apps/storefront/src/lib/apps/v84CloneLifecycleCacheEvidence.ts +105 -0
  101. package/apps/storefront/src/lib/apps/v84CloneLifecycleEvidence.ts +177 -0
  102. package/apps/storefront/src/lib/apps/v84CloneLifecycleMaterialization.ts +251 -0
  103. package/apps/storefront/src/lib/apps/v84CloneLifecycleSemantics.ts +241 -0
  104. package/apps/storefront/src/lib/apps/v84CloneMigrationEvidence.ts +211 -0
  105. package/apps/storefront/src/lib/apps/v84CloneNativeInstallEvidence.ts +409 -0
  106. package/apps/storefront/src/lib/apps/v84NonportableCodeCoaching.ts +368 -0
  107. package/apps/storefront/src/lib/apps/v84NonportableRouteContract.ts +188 -0
  108. package/apps/storefront/src/lib/apps/v84NonportableRouteDogfood.ts +291 -0
  109. package/apps/storefront/src/lib/apps/ws1ManagedAnalyticsClient.ts +95 -0
  110. package/apps/storefront/src/lib/auth/adminApiGuard.ts +66 -0
  111. package/apps/storefront/src/lib/auth/adminEntry.ts +2 -2
  112. package/apps/storefront/src/lib/auth/adminLanding.ts +88 -0
  113. package/apps/storefront/src/lib/blog/collection.ts +97 -10
  114. package/apps/storefront/src/lib/blog/markdown.ts +1 -1
  115. package/apps/storefront/src/lib/blog/provider.ts +57 -3
  116. package/apps/storefront/src/lib/blog/types.ts +9 -9
  117. package/apps/storefront/src/lib/chrome/examples/tokenoftrust.chrome-assignments.example.json +6 -0
  118. package/apps/storefront/src/lib/chrome/examples/tokenoftrust.chrome.example.json +79 -0
  119. package/apps/storefront/src/lib/chrome/model.ts +48 -253
  120. package/apps/storefront/src/lib/chrome/navCurrent.ts +29 -0
  121. package/apps/storefront/src/lib/chrome/parseConfig.ts +18 -32
  122. package/apps/storefront/src/lib/chrome/variant.ts +39 -0
  123. package/apps/storefront/src/lib/commerce/checkoutHandoffCorrelation.ts +105 -0
  124. package/apps/storefront/src/lib/compliance/tamper-sentinel-boot.ts +152 -0
  125. package/apps/storefront/src/lib/compliance/tamper-sentinel.ts +327 -0
  126. package/apps/storefront/src/lib/content/index.ts +5 -5
  127. package/apps/storefront/src/lib/content-edit/applyDiff.ts +1 -1
  128. package/apps/storefront/src/lib/content-edit/route.ts +1 -1
  129. package/apps/storefront/src/lib/d1/catalog.ts +12 -0
  130. package/apps/storefront/src/lib/d1/schema-apps.ts +276 -0
  131. package/apps/storefront/src/lib/dev/cockpit/ask.ts +49 -0
  132. package/apps/storefront/src/lib/dev/cockpit/clickToSource.ts +71 -0
  133. package/apps/storefront/src/lib/dev/cockpit/copyCommand.ts +227 -0
  134. package/apps/storefront/src/lib/dev/cockpit/files.ts +249 -0
  135. package/apps/storefront/src/lib/dev/cockpit/hostedActivity.ts +500 -0
  136. package/apps/storefront/src/lib/dev/cockpit/infoPopover.ts +12 -0
  137. package/apps/storefront/src/lib/dev/cockpit/mcpCopy.ts +34 -0
  138. package/apps/storefront/src/lib/dev/cockpit/monitor.ts +107 -0
  139. package/apps/storefront/src/lib/dev/cockpit/stepper.ts +116 -0
  140. package/apps/storefront/src/lib/dev/cockpit/themeToggle.ts +23 -0
  141. package/apps/storefront/src/lib/dev/runtimeStore.ts +1 -1
  142. package/apps/storefront/src/lib/edgeCache.ts +18 -6
  143. package/apps/storefront/src/lib/email/candidateConflictEmail.ts +80 -0
  144. package/apps/storefront/src/lib/integration/browserEnvironment.ts +137 -0
  145. package/apps/storefront/src/lib/integration/managedInstallDeclarations.ts +72 -0
  146. package/apps/storefront/src/lib/integration/nonceStamp.ts +49 -0
  147. package/apps/storefront/src/lib/integration/tenantDeclarations.ts +116 -0
  148. package/apps/storefront/src/lib/membership/eligibility.ts +1 -1
  149. package/apps/storefront/src/lib/membership/model.ts +1 -2
  150. package/apps/storefront/src/lib/newsletter/confirmationEmail.ts +2 -2
  151. package/apps/storefront/src/lib/newsletter/consent.ts +2 -2
  152. package/apps/storefront/src/lib/newsletter/send.ts +3 -3
  153. package/apps/storefront/src/lib/previewReload.ts +57 -1
  154. package/apps/storefront/src/lib/publish/adminPublishTab.ts +1775 -669
  155. package/apps/storefront/src/lib/publish/buildStream.ts +269 -0
  156. package/apps/storefront/src/lib/publish/collapsePersistence.ts +72 -0
  157. package/apps/storefront/src/lib/publish/lifecycleState.ts +369 -0
  158. package/apps/storefront/src/lib/publish/liveReleaseSummary.ts +29 -0
  159. package/apps/storefront/src/lib/publish/mergeDoctorOnFailure.ts +78 -0
  160. package/apps/storefront/src/lib/publish/mergeHealthBanner.ts +62 -0
  161. package/apps/storefront/src/lib/publish/mergeRowFindings.ts +124 -0
  162. package/apps/storefront/src/lib/publish/mergeSupportEscalation.ts +75 -0
  163. package/apps/storefront/src/lib/publish/publish-guard.ts +88 -0
  164. package/apps/storefront/src/lib/publish/publishFormat.ts +165 -0
  165. package/apps/storefront/src/lib/publish/publishHero.ts +177 -0
  166. package/apps/storefront/src/lib/publish/reviewRelease/changeState.ts +66 -0
  167. package/apps/storefront/src/lib/publish/reviewRelease/copy.ts +141 -0
  168. package/apps/storefront/src/lib/publish/reviewRelease/index.ts +41 -0
  169. package/apps/storefront/src/lib/publish/reviewRelease/permissions.ts +47 -0
  170. package/apps/storefront/src/lib/publish/reviewRelease/releaseState.ts +42 -0
  171. package/apps/storefront/src/lib/publish/reviewRelease/types.ts +59 -0
  172. package/apps/storefront/src/lib/publish/reviewRelease/viewModel.ts +440 -0
  173. package/apps/storefront/src/lib/publish/reviewReleaseWorkspace/actions.ts +161 -0
  174. package/apps/storefront/src/lib/publish/reviewReleaseWorkspace/controller.ts +325 -0
  175. package/apps/storefront/src/lib/publish/reviewReleaseWorkspace/render.ts +241 -0
  176. package/apps/storefront/src/lib/publish/shipWorkspace.ts +22 -3
  177. package/apps/storefront/src/lib/publish/sseRoute.ts +119 -0
  178. package/apps/storefront/src/lib/publish/streamLogConsole.ts +142 -0
  179. package/apps/storefront/src/lib/publish/versionNumber.ts +52 -0
  180. package/apps/storefront/src/lib/rawChrome.ts +125 -47
  181. package/apps/storefront/src/lib/rawMarketingHtml.ts +74 -3
  182. package/apps/storefront/src/lib/seo/alternates.ts +1 -1
  183. package/apps/storefront/src/lib/social/notify.ts +4 -4
  184. package/apps/storefront/src/lib/storyblok/content-model.ts +7 -33
  185. package/apps/storefront/src/lib/storyblok/provider.ts +168 -60
  186. package/apps/storefront/src/lib/subscription/model.ts +4 -4
  187. package/apps/storefront/src/lib/the-build/provider.ts +9 -4
  188. package/apps/storefront/src/middleware/index.ts +273 -51
  189. package/apps/storefront/src/pages/[...slug].astro +9 -4
  190. package/apps/storefront/src/pages/admin/review-release.astro +265 -0
  191. package/apps/storefront/src/pages/admin/select.astro +96 -0
  192. package/apps/storefront/src/pages/admin.astro +16 -2
  193. package/apps/storefront/src/pages/api/activity.ts +8 -8
  194. package/apps/storefront/src/pages/api/admin/activity-alerts.ts +5 -20
  195. package/apps/storefront/src/pages/api/admin/orders/[id].ts +7 -2
  196. package/apps/storefront/src/pages/api/admin/orders.ts +8 -2
  197. package/apps/storefront/src/pages/api/apps/admin/gtm-migration-install.ts +174 -0
  198. package/apps/storefront/src/pages/api/apps/admin/gtm-migration.ts +96 -0
  199. package/apps/storefront/src/pages/api/apps/admin/integration-lifecycle.ts +118 -0
  200. package/apps/storefront/src/pages/api/apps/admin/integrations.ts +89 -0
  201. package/apps/storefront/src/pages/api/apps/admin/platform-adapters.ts +85 -0
  202. package/apps/storefront/src/pages/api/apps/internal/order-forward.ts +74 -2
  203. package/apps/storefront/src/pages/api/commerce/checkout-handoff.ts +77 -0
  204. package/apps/storefront/src/pages/api/compliance/tamper.ts +88 -0
  205. package/apps/storefront/src/pages/api/integrations/v1/[operation].ts +108 -0
  206. package/apps/storefront/src/pages/api/rum/vitals.ts +1 -2
  207. package/apps/storefront/src/pages/blog/[slug].astro +5 -5
  208. package/apps/storefront/src/pages/blog/author/[author].astro +3 -3
  209. package/apps/storefront/src/pages/blog/category/[category].astro +2 -2
  210. package/apps/storefront/src/pages/blog/index.astro +2 -2
  211. package/apps/storefront/src/pages/blog/tag/[tag].astro +2 -2
  212. package/apps/storefront/src/pages/cockpit.astro +61 -1362
  213. package/apps/storefront/src/pages/index.astro +10 -5
  214. package/apps/storefront/src/pages/llms.txt.ts +1 -1
  215. package/apps/storefront/src/pages/products/[handle].astro +7 -6
  216. package/apps/storefront/src/pages/sitemap.xml.ts +2 -2
  217. package/apps/storefront/src/pages/style-guide/[tenant]/[theme].astro +31 -27
  218. package/apps/storefront/src/pages/style-guide/[tenant]/chrome/[theme].astro +1 -1
  219. package/apps/storefront/src/pages/tenants/[id]/[...path].ts +38 -2
  220. package/apps/storefront/src/pages/the-build/[slug].astro +4 -4
  221. package/apps/storefront/src/pages/the-build/index.astro +2 -2
  222. package/apps/storefront/src/pages/the-build/rss.xml.ts +2 -2
  223. package/apps/storefront/src/styles/admin.css +27 -1
  224. package/apps/storefront/tsconfig.json +1 -1
  225. package/package.json +1 -1
  226. package/packages/public-runtime/package.json +2 -1
  227. package/packages/public-runtime/schemas/managed-analytics/v1/adapter-definition.schema.json +427 -0
  228. package/packages/public-runtime/schemas/managed-analytics/v1/create-integration-install-request.schema.json +161 -0
  229. package/packages/public-runtime/schemas/managed-analytics/v1/create-migration-draft-request.schema.json +157 -0
  230. package/packages/public-runtime/schemas/managed-analytics/v1/delete-integration-install-request.schema.json +84 -0
  231. package/packages/public-runtime/schemas/managed-analytics/v1/delete-migration-draft-request.schema.json +84 -0
  232. package/packages/public-runtime/schemas/managed-analytics/v1/error-envelope.schema.json +180 -0
  233. package/packages/public-runtime/schemas/managed-analytics/v1/get-adapter-definition-request.schema.json +52 -0
  234. package/packages/public-runtime/schemas/managed-analytics/v1/get-integration-install-request.schema.json +52 -0
  235. package/packages/public-runtime/schemas/managed-analytics/v1/get-integration-revision-request.schema.json +79 -0
  236. package/packages/public-runtime/schemas/managed-analytics/v1/get-migration-draft-request.schema.json +52 -0
  237. package/packages/public-runtime/schemas/managed-analytics/v1/integration-install.schema.json +167 -0
  238. package/packages/public-runtime/schemas/managed-analytics/v1/integration-revision.schema.json +208 -0
  239. package/packages/public-runtime/schemas/managed-analytics/v1/list-adapter-definitions-request.schema.json +53 -0
  240. package/packages/public-runtime/schemas/managed-analytics/v1/list-integration-installs-request.schema.json +53 -0
  241. package/packages/public-runtime/schemas/managed-analytics/v1/list-integration-revisions-request.schema.json +82 -0
  242. package/packages/public-runtime/schemas/managed-analytics/v1/migration-draft.schema.json +218 -0
  243. package/packages/public-runtime/schemas/managed-analytics/v1/mutation-request.schema.json +52 -0
  244. package/packages/public-runtime/schemas/managed-analytics/v1/mutation-success-envelope.schema.json +49 -0
  245. package/packages/public-runtime/schemas/managed-analytics/v1/read-request.schema.json +20 -0
  246. package/packages/public-runtime/schemas/managed-analytics/v1/read-success-envelope.schema.json +45 -0
  247. package/packages/public-runtime/schemas/managed-analytics/v1/revise-integration-install-request.schema.json +156 -0
  248. package/packages/public-runtime/schemas/managed-analytics/v1/set-integration-install-status-request.schema.json +92 -0
  249. package/packages/public-runtime/schemas/managed-analytics/v1/update-migration-draft-request.schema.json +184 -0
  250. package/packages/public-runtime/scripts/generate-managed-analytics-api-v1-schemas.mjs +13 -0
  251. package/packages/public-runtime/src/activity/catalog.ts +41 -37
  252. package/packages/public-runtime/src/activity/event.ts +6 -6
  253. package/packages/public-runtime/src/activity/index.ts +2 -2
  254. package/packages/public-runtime/src/activity/redaction.ts +4 -4
  255. package/packages/public-runtime/src/candidate-index.ts +42 -8
  256. package/packages/public-runtime/src/checkout-orders.ts +2 -2
  257. package/packages/public-runtime/src/checkout-style-publish.ts +2 -2
  258. package/packages/public-runtime/src/checkout-style.ts +7 -7
  259. package/packages/public-runtime/src/checkout.ts +3 -3
  260. package/packages/public-runtime/src/chrome.ts +777 -0
  261. package/packages/public-runtime/src/compliance-obligations.ts +310 -0
  262. package/packages/public-runtime/src/csp.ts +99 -0
  263. package/packages/public-runtime/src/customization-runtime.ts +32 -1
  264. package/packages/public-runtime/src/destination-webhook/contract.ts +353 -0
  265. package/packages/public-runtime/src/embed-catalog.d.mts +9 -0
  266. package/packages/public-runtime/src/embed-catalog.mjs +40 -0
  267. package/packages/public-runtime/src/evidence.ts +288 -0
  268. package/packages/public-runtime/src/gtm-migration/bounds.ts +138 -0
  269. package/packages/public-runtime/src/gtm-migration/disposition-rules.ts +361 -0
  270. package/packages/public-runtime/src/gtm-migration/dispositions.ts +181 -0
  271. package/packages/public-runtime/src/gtm-migration/draft-generator.ts +400 -0
  272. package/packages/public-runtime/src/gtm-migration/graph.ts +468 -0
  273. package/packages/public-runtime/src/gtm-migration/index.ts +95 -0
  274. package/packages/public-runtime/src/gtm-migration/parse.ts +410 -0
  275. package/packages/public-runtime/src/gtm-migration/references.ts +266 -0
  276. package/packages/public-runtime/src/gtm-migration/types.ts +86 -0
  277. package/packages/public-runtime/src/index.ts +16 -1
  278. package/packages/public-runtime/src/integration/assurance-decision.ts +259 -0
  279. package/packages/public-runtime/src/integration/assurance.ts +228 -0
  280. package/packages/public-runtime/src/integration/candidate-evidence.ts +377 -0
  281. package/packages/public-runtime/src/integration/commerce-broker.ts +497 -0
  282. package/packages/public-runtime/src/integration/consent-broker.ts +337 -0
  283. package/packages/public-runtime/src/integration/consent-cmp-demand.ts +115 -0
  284. package/packages/public-runtime/src/integration/consent-config.ts +260 -0
  285. package/packages/public-runtime/src/integration/consent-preview.ts +125 -0
  286. package/packages/public-runtime/src/integration/correlation-token.ts +444 -0
  287. package/packages/public-runtime/src/integration/csp-compiler.ts +267 -0
  288. package/packages/public-runtime/src/integration/csp.ts +105 -0
  289. package/packages/public-runtime/src/integration/digest.ts +43 -0
  290. package/packages/public-runtime/src/integration/environment.ts +228 -0
  291. package/packages/public-runtime/src/integration/events-catalog.ts +186 -0
  292. package/packages/public-runtime/src/integration/events.ts +701 -0
  293. package/packages/public-runtime/src/integration/g2-action-boundary.ts +106 -0
  294. package/packages/public-runtime/src/integration/index.ts +90 -0
  295. package/packages/public-runtime/src/integration/interim-bridge.ts +138 -0
  296. package/packages/public-runtime/src/integration/lifecycle-boot.ts +317 -0
  297. package/packages/public-runtime/src/integration/lifecycle-runtime.ts +393 -0
  298. package/packages/public-runtime/src/integration/lifecycle.ts +94 -0
  299. package/packages/public-runtime/src/integration/managed-analytics-api-v1-safety.d.mts +2 -0
  300. package/packages/public-runtime/src/integration/managed-analytics-api-v1-safety.mjs +10 -0
  301. package/packages/public-runtime/src/integration/managed-analytics-api-v1.schemas.ts +382 -0
  302. package/packages/public-runtime/src/integration/managed-analytics-api-v1.ts +684 -0
  303. package/packages/public-runtime/src/integration/managed-analytics-bridge.ts +383 -0
  304. package/packages/public-runtime/src/integration/managed-analytics-value-safety.ts +14 -0
  305. package/packages/public-runtime/src/integration/managed-analytics.ts +277 -0
  306. package/packages/public-runtime/src/integration/manifest.ts +470 -0
  307. package/packages/public-runtime/src/integration/native-amplitude.ts +362 -0
  308. package/packages/public-runtime/src/integration/native-ga4.ts +352 -0
  309. package/packages/public-runtime/src/integration/observability.ts +451 -0
  310. package/packages/public-runtime/src/integration/order-conversion.ts +0 -0
  311. package/packages/public-runtime/src/integration/phases.ts +182 -0
  312. package/packages/public-runtime/src/integration/plan.ts +112 -0
  313. package/packages/public-runtime/src/integration/platform-adapter-runtime.ts +146 -0
  314. package/packages/public-runtime/src/integration/platform-adapters.ts +671 -0
  315. package/packages/public-runtime/src/integration/promotion-gate.ts +451 -0
  316. package/packages/public-runtime/src/integration/provider-checkout-extension.ts +425 -0
  317. package/packages/public-runtime/src/integration/receipt-measurement.ts +370 -0
  318. package/packages/public-runtime/src/integration/regulated-parent-cert.ts +311 -0
  319. package/packages/public-runtime/src/integration/render-phases.ts +267 -0
  320. package/packages/public-runtime/src/integration/resolve.ts +465 -0
  321. package/packages/public-runtime/src/integration/result.ts +239 -0
  322. package/packages/public-runtime/src/integration/secrets.ts +92 -0
  323. package/packages/public-runtime/src/integration/tamper-evidence.ts +205 -0
  324. package/packages/public-runtime/src/integration/tamper-recovery.ts +127 -0
  325. package/packages/public-runtime/src/integration/version.ts +92 -0
  326. package/packages/public-runtime/src/integration-capabilities.ts +520 -0
  327. package/packages/public-runtime/src/membership.ts +2 -2
  328. package/packages/public-runtime/src/raw-html-policy.ts +2 -4
  329. package/packages/public-runtime/src/regulated-commerce/broker/consent-dedupe.ts +144 -0
  330. package/packages/public-runtime/src/regulated-commerce/correlation/contract.ts +177 -0
  331. package/packages/public-runtime/src/regulated-commerce/diagnostics/local-dispatch.ts +24 -0
  332. package/packages/public-runtime/src/regulated-commerce/diagnostics/read-model.ts +69 -0
  333. package/packages/public-runtime/src/regulated-commerce/dispatch/core.ts +134 -0
  334. package/packages/public-runtime/src/regulated-commerce/events/contract.ts +113 -0
  335. package/packages/public-runtime/src/regulated-commerce/ledger/core.ts +81 -0
  336. package/packages/public-runtime/src/regulated-commerce/mappings/ga4-ads.ts +87 -0
  337. package/packages/public-runtime/src/regulated-commerce/provider-order/bridge.ts +52 -0
  338. package/packages/public-runtime/src/regulated-commerce/purchase-truth/contract.ts +252 -0
  339. package/packages/public-runtime/src/regulated-commerce/sources/accepted-browser-operation.ts +67 -0
  340. package/packages/public-runtime/src/regulated-commerce/testing/fake-destination.ts +93 -0
  341. package/packages/public-runtime/src/static-bundle.ts +5 -5
  342. package/packages/public-runtime/src/tenant-assets.ts +143 -4
  343. package/packages/public-runtime/src/tenant.ts +45 -9
  344. package/packages/public-runtime/tests/fixtures/integration/browser-environment.example.json +8 -0
  345. package/packages/public-runtime/tests/fixtures/integration/commerce-event.example.json +44 -0
  346. package/packages/public-runtime/tests/fixtures/integration/commerce-order-event.example.json +44 -0
  347. package/packages/public-runtime/tests/fixtures/integration/compliance-assurance-record.example.json +50 -0
  348. package/packages/public-runtime/tests/fixtures/integration/integration-manifest-v2.example.json +120 -0
  349. package/packages/public-runtime/tests/fixtures/integration/managed-analytics-v1/fake-adapter-catalog.json +35 -0
  350. package/packages/public-runtime/tests/fixtures/integration/tenant-action-registry.example.json +11 -0
  351. package/packages/public-runtime/tests/fixtures/integration/tenant-local-example/README.md +22 -0
  352. package/packages/public-runtime/tests/fixtures/integration/tenant-local-example/entry.js +30 -0
  353. package/packages/public-runtime/tests/fixtures/integration/tenant-local-example/manifest.json +75 -0
  354. package/packages/public-runtime/tests/fixtures/integration/tenant-local-example/public-config.json +3 -0
  355. package/packages/public-runtime/tests/fixtures/regulated-commerce/fake-destinations.ts +38 -0
  356. package/packages/public-runtime/tests/gtm-migration/fixtures/gtm-sample-container-v84.provenance.json +29 -0
  357. package/packages/public-runtime/tests/gtm-migration/fixtures/gtm-sample-container-v84.redacted.json +3397 -0
  358. package/scripts/dev/file-browser.mjs +2 -2
  359. package/scripts/dev/file-writer.mjs +2 -2
  360. package/scripts/dev/integration-guardrails.mjs +498 -0
  361. package/scripts/dev/safe-path.mjs +2 -2
  362. package/scripts/dev/tenant-source-root.mjs +1 -1
  363. package/scripts/tot-dev.mjs +2 -2
@@ -0,0 +1,451 @@
1
+ /**
2
+ * The unifying, fail-closed integration PROMOTION gate (ext-policy-06).
3
+ *
4
+ * ONE gate that an integration promotion must pass before its plan can reach a
5
+ * staged/live pointer. It does not invent a second opinion — it COMPOSES the
6
+ * fail-closed verifiers each upstream card already owns and refuses promotion on
7
+ * ANY of their failures:
8
+ *
9
+ * - ext-policy-02 {@link compileIntegrationCspFromPlan} — the plan's curated
10
+ * profiles + advanced origins must compile under the exact-origin grammar; a
11
+ * wildcard / bare scheme / `unsafe-*` / `strict-dynamic` / unknown directive is
12
+ * an INVALID policy and is rejected here, before any flip.
13
+ * - ext-policy-03 the consent broker's {@link ConsentSnapshot} — every
14
+ * non-essential purpose the plan depends on must be eligible under a well-formed
15
+ * (default-deny, `unknownState:"block"`) snapshot; a forged/absent snapshot
16
+ * fails closed.
17
+ * - ext-policy-04 {@link verifyObligationCoverage} — the SERVER-derived required
18
+ * obligation set (never the candidate's declaration) must be completely,
19
+ * unambiguously covered; a regulated tenant cannot ship with an omitted duty.
20
+ * - ext-policy-05 {@link decideAssurance} — an elevated-parent integration needs
21
+ * an approvable assurance record; the regulated floor is non-waivable.
22
+ * - ext-kernel-06 {@link verifyCandidatePromotable} (which calls
23
+ * {@link verifyServedParity}) — the evidence must EQUAL what a mount actually
24
+ * served; an unobserved served output, a forged asset, secret material, or a
25
+ * `live` candidate blocks.
26
+ * - ext-prereq-03 {@link verifyPromotionEvidence} — the compliance-evidence check
27
+ * set (age_gate / excise / jurisdiction) must be complete, matching, fresh, and
28
+ * all-passing against the server-derived {@link REQUIRED_FOR_PROMOTE}.
29
+ *
30
+ * Fail-closed and non-short-circuiting: every composed verdict runs and EVERY reason
31
+ * is accumulated, so the diagnostics are complete and actionable. `ok` is true only
32
+ * when nothing objected.
33
+ *
34
+ * VERSION-BOUND (the rollback-safety property): every artifact the gate reads — the
35
+ * plan, its freshly-compiled CSP, and the candidate evidence — must bind to the SAME
36
+ * `planRevision` (and the caller's `expectedPlanRevision`, when given). A stale
37
+ * artifact left over from a superseded version carries a different revision and is
38
+ * rejected, so a promote — or a rollback that re-promotes a prior version — can never
39
+ * ride another version's cached CSP/evidence.
40
+ *
41
+ * SECRET-SAFE DIAGNOSTICS: the assembled diagnostics are scanned with
42
+ * {@link findForbiddenFields} before they leave the gate; a diagnostic payload that
43
+ * names secret material is redacted AND turns the verdict closed, so an operator
44
+ * report can never leak a nonce/token/credential.
45
+ */
46
+ import {
47
+ verifyObligationCoverage,
48
+ resolveObligationIds,
49
+ isRegulated,
50
+ type ObligationTenant,
51
+ } from "../compliance-obligations.js";
52
+ import { verifyCandidatePromotable } from "./candidate-evidence.js";
53
+ import type {
54
+ IntegrationCandidateEvidence,
55
+ ServedObservation,
56
+ } from "./candidate-evidence.js";
57
+ import { decideAssurance } from "./assurance-decision.js";
58
+ import type { AssuranceDecisionContext } from "./assurance-decision.js";
59
+ import {
60
+ decideRegulatedParentCert,
61
+ type RegulatedParentCertification,
62
+ } from "./regulated-parent-cert.js";
63
+ import {
64
+ compileIntegrationCspFromPlan,
65
+ type IntegrationCspAdditions,
66
+ } from "./csp-compiler.js";
67
+ import { findForbiddenFields } from "./secrets.js";
68
+ import {
69
+ defaultConsentSnapshot,
70
+ parseConsentSnapshot,
71
+ isPurposeEligible,
72
+ type ConsentSnapshot,
73
+ } from "./consent-broker.js";
74
+ import type { EffectivePlan } from "./plan.js";
75
+ import type { ComplianceAssuranceRecord } from "./assurance.js";
76
+ import type { ContractViolation } from "./result.js";
77
+ import {
78
+ verifyPromotionEvidence,
79
+ REQUIRED_FOR_PROMOTE,
80
+ PROMOTION_EVIDENCE_MAX_AGE_MS,
81
+ type PromotionEvidenceCheck,
82
+ } from "../evidence.js";
83
+
84
+ /** Everything the unifying gate needs to decide whether an integration may promote. */
85
+ export interface IntegrationPromotionGateInput {
86
+ /**
87
+ * The version this promotion is FOR. When set, the plan, its compiled CSP, and the
88
+ * candidate evidence must all bind to this exact revision — the rollback-safety
89
+ * anchor. Omit to only require the three artifacts agree with each other.
90
+ */
91
+ expectedPlanRevision?: string;
92
+
93
+ /** The tenant's authoritative config — the ONLY source of the required obligations + regulated classification. */
94
+ tenant: ObligationTenant;
95
+
96
+ /** The resolved effective plan for the candidate being promoted (ext-kernel-03). */
97
+ plan: EffectivePlan | null | undefined;
98
+
99
+ /** Curated CSP profile slugs declared across the plan's integrations (ext-policy-02). */
100
+ cspProfiles?: readonly string[];
101
+
102
+ /** The candidate evidence derived from the plan (ext-kernel-06). */
103
+ candidateEvidence: IntegrationCandidateEvidence | null | undefined;
104
+
105
+ /**
106
+ * What a mount ACTUALLY served for this candidate — the parity anchor
107
+ * {@link verifyServedParity} re-derives against (ext-kernel-06). `null` = the
108
+ * served output was not observed, itself a blocker (parity cannot be asserted).
109
+ */
110
+ served: ServedObservation | null;
111
+
112
+ /**
113
+ * A forge-response integrity failure from the reconcile that produced this
114
+ * candidate (ext-prereq-02), if one occurred. A forged/unreadable forge response
115
+ * can never become promotable.
116
+ */
117
+ forgeIntegrityError?: string | null;
118
+
119
+ /**
120
+ * The obligation ids the candidate/app DECLARES it satisfies. Verified against the
121
+ * server-derived floor ({@link resolveObligationIds}) — never trusted as the
122
+ * required set itself (ext-policy-04).
123
+ */
124
+ declaredObligationIds: readonly string[] | null | undefined;
125
+
126
+ /** The compliance-evidence checks measured for this candidate (ext-prereq-03). */
127
+ complianceChecks: readonly PromotionEvidenceCheck[] | null | undefined;
128
+ /** The compliance evidence's `generated_at` (ISO) — required to evaluate freshness. */
129
+ complianceGeneratedAt?: string;
130
+
131
+ /** The promote instant (ms epoch) freshness is measured against. */
132
+ now?: number;
133
+ /** Max compliance-evidence age before STALE (ms). Defaults to {@link PROMOTION_EVIDENCE_MAX_AGE_MS}. */
134
+ maxAgeMs?: number;
135
+
136
+ /**
137
+ * The SERVER-derived consent snapshot the plan's non-essential `consentNeeds` must
138
+ * each be eligible under (ext-policy-03). Absent ⇒ the default-deny snapshot, so
139
+ * any dependent purpose blocks — consent defaults precede dependent code.
140
+ */
141
+ consentSnapshot?: ConsentSnapshot;
142
+
143
+ /** The elevated-integration assurance record, when one resolved (ext-policy-05). */
144
+ assurance?: ComplianceAssuranceRecord | null;
145
+ /**
146
+ * The decision context for {@link decideAssurance} (wall clock, counsel flag, the
147
+ * resolved material state). Required when an `assurance` record is present — an
148
+ * expiry/material-change verdict cannot be reached without it.
149
+ *
150
+ * NOTE: its `certifiedImmutable` is NOT read as a raw external input. The gate
151
+ * OVERRIDES it with the value {@link decideRegulatedParentCert} derives from
152
+ * `regulatedParentCert` below, so no caller can assert a regulated elevated-parent
153
+ * integration is certified without a cert that actually clears every clause.
154
+ */
155
+ assuranceContext?: AssuranceDecisionContext;
156
+ /**
157
+ * The regulated elevated-parent certification artifact (ext-policy-07), when one is
158
+ * supplied. It is the SINGLE ORIGIN of `certifiedImmutable`: the gate runs
159
+ * {@link decideRegulatedParentCert} against the plan's elevated-parent integration
160
+ * (its served content digest as the drift anchor, its app/version as the binding) and
161
+ * feeds the decision's boolean into the assurance context. Absent/failed ⇒ false ⇒
162
+ * a regulated elevated-parent integration is denied `regulated-cert-missing`.
163
+ */
164
+ regulatedParentCert?: RegulatedParentCertification | null;
165
+ }
166
+
167
+ /** One composed verdict, flattened to the `{ ok, blockers }` family the gate aggregates. */
168
+ export interface IntegrationGateSubVerdict {
169
+ ok: boolean;
170
+ blockers: string[];
171
+ }
172
+
173
+ /** The structured, secret-scanned diagnostics an operator reads to fix a blocked promotion. */
174
+ export interface IntegrationPromotionDiagnostics {
175
+ version: {
176
+ expected: string | null;
177
+ plan: string | null;
178
+ candidate: string | null;
179
+ csp: string | null;
180
+ consistent: boolean;
181
+ };
182
+ csp: IntegrationGateSubVerdict;
183
+ candidate: IntegrationGateSubVerdict;
184
+ obligations: IntegrationGateSubVerdict & { regulated: boolean; required: string[] };
185
+ compliance: IntegrationGateSubVerdict;
186
+ consent: IntegrationGateSubVerdict;
187
+ assurance: IntegrationGateSubVerdict;
188
+ /**
189
+ * The resolved per-integration public config under review — echoed so an operator
190
+ * can inspect exactly what the plan carries. This is the app-declared, nested,
191
+ * open-value structure the diagnostics secret-scan defends: a field naming secret
192
+ * material here (a leak the resolver should have caught) redacts the whole payload.
193
+ */
194
+ publicConfig: Record<string, Record<string, unknown>>;
195
+ }
196
+
197
+ export interface IntegrationPromotionVerdict {
198
+ /** True only when EVERY composed verifier passed and the diagnostics carried no secret. */
199
+ ok: boolean;
200
+ /** Every reason this integration may not promote (empty ⇔ ok). */
201
+ blockers: string[];
202
+ /**
203
+ * The structured diagnostics — secret-scanned. Replaced by `{ redacted: true }`
204
+ * (and the verdict forced closed) if any diagnostic field named secret material.
205
+ */
206
+ diagnostics: IntegrationPromotionDiagnostics | { redacted: true };
207
+ }
208
+
209
+ /**
210
+ * The single fail-CLOSED authority for "may this integration reach a staged/live
211
+ * pointer?". Composes the six upstream verifiers; refuses on any failure. See the
212
+ * file header for the property each clause holds.
213
+ */
214
+ export function verifyIntegrationPromotable(
215
+ input: IntegrationPromotionGateInput,
216
+ ): IntegrationPromotionVerdict {
217
+ const blockers: string[] = [];
218
+ const { plan, candidateEvidence } = input;
219
+
220
+ // ── Version binding (rollback-safety) ────────────────────────────────────
221
+ // A freshly-compiled CSP for THIS plan is the pre-release fail-closed floor
222
+ // (ext-policy-02): an invalid policy yields violations and no additions, and is
223
+ // rejected before any flip. Compiling here (not trusting the evidence's embedded
224
+ // additions) re-validates the plan's CSP independently at promote time.
225
+ const csp = plan
226
+ ? compileIntegrationCspFromPlan(plan, input.cspProfiles ?? [])
227
+ : null;
228
+
229
+ const expected = input.expectedPlanRevision ?? null;
230
+ const planRev = plan?.planRevision ?? null;
231
+ const candidateRev = candidateEvidence?.planRevision ?? null;
232
+ const cspRev = csp?.ok ? csp.value.planRevision : null;
233
+ const revs = [planRev, candidateRev, cspRev].filter((r): r is string => r != null);
234
+ const versionConsistent =
235
+ revs.length > 0 &&
236
+ revs.every((r) => r === revs[0]) &&
237
+ (expected == null || revs.every((r) => r === expected));
238
+ if (!versionConsistent) {
239
+ blockers.push(
240
+ `Version mismatch: plan="${planRev ?? "(absent)"}", candidate="${candidateRev ?? "(absent)"}", ` +
241
+ `csp="${cspRev ?? "(absent)"}"${expected ? `, expected="${expected}"` : ""} — every promotion ` +
242
+ `artifact must bind to one plan revision (a stale artifact from a superseded version is rejected).`,
243
+ );
244
+ }
245
+
246
+ // ── ext-policy-02: CSP fail-closed ───────────────────────────────────────
247
+ const cspSub: IntegrationGateSubVerdict = { ok: true, blockers: [] };
248
+ const cspViolations: ContractViolation[] = [];
249
+ if (!plan) {
250
+ cspSub.ok = false;
251
+ cspSub.blockers.push("No effective plan supplied — nothing to compile or promote.");
252
+ } else if (csp && !csp.ok) {
253
+ cspSub.ok = false;
254
+ for (const v of csp.violations) {
255
+ cspViolations.push(v);
256
+ cspSub.blockers.push(`Invalid integration CSP at ${v.path}: ${v.message}`);
257
+ }
258
+ } else if (csp?.ok && candidateEvidence) {
259
+ // Defense in depth: the promote-time recompile must equal the CSP the evidence
260
+ // (and therefore the served response) carries — otherwise the plan would ship a
261
+ // policy the operator never reviewed as evidence.
262
+ if (canonicalCspKey(csp.value.additions) !== canonicalCspKey(candidateEvidence.cspAdditions)) {
263
+ cspSub.ok = false;
264
+ cspSub.blockers.push(
265
+ "Recompiled integration CSP differs from the candidate evidence's CSP additions.",
266
+ );
267
+ }
268
+ }
269
+ blockers.push(...cspSub.blockers);
270
+
271
+ // ── ext-kernel-06: candidate ⇔ served parity, assets, secrets, not-live ──
272
+ const candidateSub: IntegrationGateSubVerdict = candidateEvidence
273
+ ? verifyCandidatePromotable(candidateEvidence, input.served, {
274
+ forgeIntegrityError: input.forgeIntegrityError,
275
+ })
276
+ : { ok: false, blockers: ["No candidate evidence supplied — parity with the served output is unprovable."] };
277
+ blockers.push(...candidateSub.blockers);
278
+
279
+ // ── ext-policy-04: obligation coverage (server-derived, regulated floor) ──
280
+ const obligationVerdict = verifyObligationCoverage(input.tenant, input.declaredObligationIds);
281
+ const obligationsSub = {
282
+ ok: obligationVerdict.ok,
283
+ blockers: obligationVerdict.blockers,
284
+ regulated: isRegulated(input.tenant),
285
+ required: resolveObligationIds(input.tenant),
286
+ };
287
+ blockers.push(...obligationsSub.blockers);
288
+
289
+ // ── ext-prereq-03: compliance evidence (age_gate / excise / jurisdiction) ─
290
+ const complianceVerdict = verifyPromotionEvidence(input.complianceChecks, {
291
+ requiredIds: REQUIRED_FOR_PROMOTE,
292
+ generatedAt: input.complianceGeneratedAt,
293
+ now: input.now,
294
+ maxAgeMs: input.maxAgeMs ?? PROMOTION_EVIDENCE_MAX_AGE_MS,
295
+ });
296
+ blockers.push(...complianceVerdict.blockers);
297
+
298
+ // ── ext-policy-03: consent order (defaults precede, unknown blocks) ───────
299
+ const consentSub = verifyConsentOrder(plan, input.consentSnapshot);
300
+ blockers.push(...consentSub.blockers);
301
+
302
+ // ── ext-policy-05: assurance for an elevated-parent integration ───────────
303
+ // `certifiedImmutable` has a SINGLE ORIGIN: derive it from the certification decision
304
+ // (never trust a raw external flag on the context) and OVERRIDE the context with it,
305
+ // so no caller can bypass the decision by asserting `certifiedImmutable: true`.
306
+ const derivedCertifiedImmutable = deriveRegulatedParentCertified(
307
+ plan,
308
+ input.tenant,
309
+ input.regulatedParentCert,
310
+ );
311
+ const assuranceContext: AssuranceDecisionContext | undefined = input.assuranceContext
312
+ ? { ...input.assuranceContext, certifiedImmutable: derivedCertifiedImmutable }
313
+ : input.assuranceContext;
314
+ const assuranceSub = verifyAssurance(plan, input.assurance, assuranceContext);
315
+ blockers.push(...assuranceSub.blockers);
316
+
317
+ // ── Assemble + secret-scan the diagnostics ───────────────────────────────
318
+ const diagnostics: IntegrationPromotionDiagnostics = {
319
+ version: { expected, plan: planRev, candidate: candidateRev, csp: cspRev, consistent: versionConsistent },
320
+ csp: { ok: cspSub.ok, blockers: cspSub.blockers },
321
+ candidate: candidateSub,
322
+ obligations: obligationsSub,
323
+ compliance: complianceVerdict,
324
+ consent: consentSub,
325
+ assurance: assuranceSub,
326
+ publicConfig: plan?.publicConfig ?? {},
327
+ };
328
+
329
+ // The diagnostics are an operator-facing, potentially-serialized surface. Any field
330
+ // whose NAME denotes secret material (a leak from a composed verifier's payload) is
331
+ // never allowed out: redact the whole payload and fail the gate closed.
332
+ const forbidden = findForbiddenFields(diagnostics, "diagnostics");
333
+ if (forbidden.length > 0) {
334
+ blockers.push(
335
+ `Gate diagnostics named secret material (${forbidden.map((f) => f.path).join(", ")}) and were redacted.`,
336
+ );
337
+ return { ok: false, blockers, diagnostics: { redacted: true } };
338
+ }
339
+
340
+ return { ok: blockers.length === 0, blockers, diagnostics };
341
+ }
342
+
343
+ /**
344
+ * Every non-essential consent purpose the plan depends on must be eligible under a
345
+ * well-formed, default-deny snapshot. An absent snapshot is the default-deny floor
346
+ * (only `essential`), so any dependent purpose blocks — consent defaults precede
347
+ * dependent code. A forged/tampered snapshot (fails the canonical round-trip) blocks.
348
+ */
349
+ function verifyConsentOrder(
350
+ plan: EffectivePlan | null | undefined,
351
+ snapshot: ConsentSnapshot | undefined,
352
+ ): IntegrationGateSubVerdict {
353
+ const blockers: string[] = [];
354
+ if (!plan) return { ok: true, blockers };
355
+
356
+ const effective = snapshot ?? defaultConsentSnapshot();
357
+ // Fail closed on a forged snapshot: the canonical parse recomputes the snapshotId
358
+ // from the eligible set and rejects a mismatched, unknown-state, or unknown-purpose
359
+ // payload — a caller cannot smuggle in a snapshot that grants a purpose it should not.
360
+ if (parseConsentSnapshot(effective) === null) {
361
+ blockers.push("Consent snapshot is malformed or forged — its eligibility cannot be trusted.");
362
+ return { ok: false, blockers };
363
+ }
364
+ if (effective.unknownState !== "block") {
365
+ blockers.push("Consent snapshot does not fail closed on unknown state.");
366
+ }
367
+ for (const purpose of plan.consentNeeds) {
368
+ if (!isPurposeEligible(effective, purpose)) {
369
+ blockers.push(
370
+ `Consent purpose "${purpose}" is required by the plan but not eligible under the approved snapshot.`,
371
+ );
372
+ }
373
+ }
374
+ return { ok: blockers.length === 0, blockers };
375
+ }
376
+
377
+ /**
378
+ * Assurance gates ONLY elevated-parent integrations. A sandbox/broker plan has no
379
+ * assurance obligation (clean pass). An elevated-parent integration with no record
380
+ * fails closed; with a record, `decideAssurance` must approve it (the regulated floor
381
+ * stays non-waivable, the vendor cannot self-approve, expiry/material-change apply).
382
+ */
383
+ function verifyAssurance(
384
+ plan: EffectivePlan | null | undefined,
385
+ record: ComplianceAssuranceRecord | null | undefined,
386
+ context: AssuranceDecisionContext | undefined,
387
+ ): IntegrationGateSubVerdict {
388
+ const blockers: string[] = [];
389
+ const elevated = (plan?.integrations ?? []).some((i) => i.executionTier === "elevated-parent");
390
+
391
+ if (!elevated && !record) return { ok: true, blockers };
392
+
393
+ if (elevated && !record) {
394
+ blockers.push(
395
+ "An elevated-parent integration has no assurance record — full-parent authority cannot promote unacknowledged.",
396
+ );
397
+ return { ok: false, blockers };
398
+ }
399
+
400
+ if (record) {
401
+ if (!context) {
402
+ blockers.push("An assurance record is present but no decision context was supplied — expiry cannot be evaluated.");
403
+ return { ok: false, blockers };
404
+ }
405
+ const decision = decideAssurance(record, context);
406
+ if (!decision.ok) {
407
+ for (const denial of decision.denials) {
408
+ blockers.push(
409
+ `Assurance denied: ${denial.reason}${denial.subject ? ` (${denial.subject})` : ""}.`,
410
+ );
411
+ }
412
+ }
413
+ }
414
+ return { ok: blockers.length === 0, blockers };
415
+ }
416
+
417
+ /**
418
+ * Derive `certifiedImmutable` from the certification decision — the SINGLE ORIGIN of
419
+ * that flag (never a raw external boolean). Runs {@link decideRegulatedParentCert}
420
+ * against the plan's elevated-parent integration: its served content digest is the
421
+ * drift anchor and its app/version the binding, so a cert for a different artifact, an
422
+ * unpinned/mutable one, a drifted one, or one missing an adversarial obligation proof
423
+ * yields `false`. No elevated-parent integration ⇒ the flag is irrelevant and `false`
424
+ * (fail closed); a non-regulated tenant likewise decides `false` (the decision returns
425
+ * `not-regulated`), which the regulated-only assurance clause never consults.
426
+ */
427
+ function deriveRegulatedParentCertified(
428
+ plan: EffectivePlan | null | undefined,
429
+ tenant: ObligationTenant,
430
+ cert: RegulatedParentCertification | null | undefined,
431
+ ): boolean {
432
+ const elevated = (plan?.integrations ?? []).find((i) => i.executionTier === "elevated-parent");
433
+ if (!elevated) return false;
434
+ return decideRegulatedParentCert(cert, {
435
+ tenant,
436
+ servedDigest: elevated.digest,
437
+ binding: { appId: elevated.appId, version: elevated.version },
438
+ }).certifiedImmutable;
439
+ }
440
+
441
+ /**
442
+ * Canonical key for compiled CSP additions. The compiler already sorts + dedupes
443
+ * origins per directive and omits empty directives, so ordering by directive name
444
+ * yields an equality key two identical additions share exactly.
445
+ */
446
+ function canonicalCspKey(additions: IntegrationCspAdditions): string {
447
+ return Object.keys(additions)
448
+ .sort()
449
+ .map((d) => `${d}:${(additions[d as keyof IntegrationCspAdditions] ?? []).join(",")}`)
450
+ .join("|");
451
+ }