@warpgogol/werkstatt-shared 0.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 (403) hide show
  1. package/package.json +352 -0
  2. package/src/checks/index.ts +24 -0
  3. package/src/checks/lib/astro-site-url.ts +30 -0
  4. package/src/checks/lib/i18n.ts +30 -0
  5. package/src/checks/result-helpers.ts +102 -0
  6. package/src/checks/suppressions-config.ts +195 -0
  7. package/src/index.ts +14 -0
  8. package/src/integration/README.md +38 -0
  9. package/src/integration/adapters.ts +143 -0
  10. package/src/integration/crm-buffer.ts +491 -0
  11. package/src/integration/dispatch.ts +106 -0
  12. package/src/integration/funnel.ts +379 -0
  13. package/src/integration/index.ts +56 -0
  14. package/src/integration/lifecycle.ts +155 -0
  15. package/src/integration/orchestration.ts +439 -0
  16. package/src/integration/port-barrel.ts +124 -0
  17. package/src/integration/port.ts +143 -0
  18. package/src/integration/qstash.ts +134 -0
  19. package/src/integration/sharding.ts +133 -0
  20. package/src/integration/tests/deliver-event.test.ts +52 -0
  21. package/src/integration/tests/dispatch.test.ts +88 -0
  22. package/src/integration/tests/funnel-bridge.test.ts +46 -0
  23. package/src/integration/tests/hub-runtime.test.ts +128 -0
  24. package/src/integration/tests/lifecycle.test.ts +69 -0
  25. package/src/integration/tests/qstash.test.ts +83 -0
  26. package/src/integration/tests/sharding.test.ts +64 -0
  27. package/src/integration/vitest.config.ts +8 -0
  28. package/src/integration-adapter-supabase-crm/adapter.ts +437 -0
  29. package/src/integration-adapter-supabase-crm/client.ts +605 -0
  30. package/src/integration-adapter-supabase-crm/index.ts +28 -0
  31. package/src/integration-adapter-supabase-crm/pipedrive-sync-target.ts +482 -0
  32. package/src/integration-adapter-supabase-crm/supabase-rest.ts +89 -0
  33. package/src/integration-adapter-supabase-crm/tenant-registry.ts +334 -0
  34. package/src/integration-adapter-supabase-crm/tests/change-balance.pbt.test.ts +83 -0
  35. package/src/integration-adapter-supabase-crm/tests/funnel-persistence.test.ts +409 -0
  36. package/src/integration-adapter-supabase-crm/tests/lifecycle-sync.test.ts +288 -0
  37. package/src/integration-adapter-supabase-crm/tests/stage-map.test.ts +80 -0
  38. package/src/integration-adapter-supabase-crm/vitest.config.ts +8 -0
  39. package/src/integration-adapter-supabase-crm/worker.ts +223 -0
  40. package/src/observability/conventions.ts +93 -0
  41. package/src/observability/env-resolver.ts +57 -0
  42. package/src/observability/index.ts +57 -0
  43. package/src/observability/metric-registry.ts +184 -0
  44. package/src/observability/otlp-converter.ts +125 -0
  45. package/src/observability/otlp-json.ts +135 -0
  46. package/src/observability/otlp-transport.ts +68 -0
  47. package/src/observability/pusher.ts +142 -0
  48. package/src/observability/redact.ts +27 -0
  49. package/src/observability/tests/conventions.test.ts +100 -0
  50. package/src/observability/tests/metric-registry.test.ts +117 -0
  51. package/src/observability/tests/otlp-converter.pbt.test.ts +77 -0
  52. package/src/observability/tests/otlp-converter.test.ts +157 -0
  53. package/src/observability/tests/otlp-json.test.ts +120 -0
  54. package/src/observability/tests/pusher.test.ts +75 -0
  55. package/src/observability/tests/redact.pbt.test.ts +71 -0
  56. package/src/observability/tests/redact.test.ts +37 -0
  57. package/src/observability/typed-refs.ts +137 -0
  58. package/src/observability/vitest.config.ts +8 -0
  59. package/src/ontology/analytics/matomo-binding.yaml +172 -0
  60. package/src/ontology/analytics/matomo-fleet.registry.yaml +26 -0
  61. package/src/ontology/analytics/messkanon.yaml +151 -0
  62. package/src/ontology/archetype-registry.ts +61 -0
  63. package/src/ontology/archetypes/components/brand-label.yaml +19 -0
  64. package/src/ontology/archetypes/components/copyright.yaml +19 -0
  65. package/src/ontology/archetypes/components/currency-aware-price-display.yaml +19 -0
  66. package/src/ontology/archetypes/components/currency-selector.yaml +19 -0
  67. package/src/ontology/archetypes/components/footer-promo.yaml +19 -0
  68. package/src/ontology/archetypes/components/lang-switcher.yaml +19 -0
  69. package/src/ontology/archetypes/components/layout.yaml +19 -0
  70. package/src/ontology/archetypes/components/live-photo.yaml +20 -0
  71. package/src/ontology/archetypes/components/material-credit.yaml +20 -0
  72. package/src/ontology/archetypes/components/media.yaml +21 -0
  73. package/src/ontology/archetypes/components/nachweis-card.yaml +34 -0
  74. package/src/ontology/archetypes/components/nachweis-detail.yaml +43 -0
  75. package/src/ontology/archetypes/components/nachweis-list.yaml +37 -0
  76. package/src/ontology/archetypes/components/nachweis-verify.yaml +31 -0
  77. package/src/ontology/archetypes/components/not-found.yaml +22 -0
  78. package/src/ontology/archetypes/components/offer-capacity.yaml +21 -0
  79. package/src/ontology/archetypes/components/passport-header.yaml +19 -0
  80. package/src/ontology/archetypes/components/passport-provenance.yaml +20 -0
  81. package/src/ontology/archetypes/components/passport-score-grid.yaml +20 -0
  82. package/src/ontology/archetypes/components/passport-star-map.yaml +20 -0
  83. package/src/ontology/archetypes/components/person-profile.yaml +20 -0
  84. package/src/ontology/archetypes/components/pulsar.yaml +20 -0
  85. package/src/ontology/archetypes/components/responsive-image.yaml +19 -0
  86. package/src/ontology/archetypes/components/scroll-to-top.yaml +22 -0
  87. package/src/ontology/archetypes/components/social-meta.yaml +20 -0
  88. package/src/ontology/archetypes/components/structured-data.yaml +19 -0
  89. package/src/ontology/archetypes/index.json +1003 -0
  90. package/src/ontology/archetypes/index.yaml +821 -0
  91. package/src/ontology/archetypes/sections/approach.yaml +23 -0
  92. package/src/ontology/archetypes/sections/article-list.yaml +30 -0
  93. package/src/ontology/archetypes/sections/audience-cards.yaml +30 -0
  94. package/src/ontology/archetypes/sections/breadcrumbs.yaml +21 -0
  95. package/src/ontology/archetypes/sections/chat-widget.yaml +37 -0
  96. package/src/ontology/archetypes/sections/comparison-cards.yaml +31 -0
  97. package/src/ontology/archetypes/sections/controlled-responsibility-block.yaml +34 -0
  98. package/src/ontology/archetypes/sections/credits.yaml +29 -0
  99. package/src/ontology/archetypes/sections/donation-card.yaml +53 -0
  100. package/src/ontology/archetypes/sections/donation-use.yaml +23 -0
  101. package/src/ontology/archetypes/sections/dynamic-status-block.yaml +35 -0
  102. package/src/ontology/archetypes/sections/faq-list.yaml +26 -0
  103. package/src/ontology/archetypes/sections/final-cta.yaml +53 -0
  104. package/src/ontology/archetypes/sections/hero-decision-card.yaml +65 -0
  105. package/src/ontology/archetypes/sections/hero.yaml +50 -0
  106. package/src/ontology/archetypes/sections/impact.yaml +23 -0
  107. package/src/ontology/archetypes/sections/markdown.yaml +43 -0
  108. package/src/ontology/archetypes/sections/mountain-journey.yaml +43 -0
  109. package/src/ontology/archetypes/sections/navigation.yaml +20 -0
  110. package/src/ontology/archetypes/sections/notausgang-block.yaml +41 -0
  111. package/src/ontology/archetypes/sections/open-source-registry.yaml +26 -0
  112. package/src/ontology/archetypes/sections/ownership-block.yaml +57 -0
  113. package/src/ontology/archetypes/sections/people.yaml +48 -0
  114. package/src/ontology/archetypes/sections/price-card.yaml +50 -0
  115. package/src/ontology/archetypes/sections/problem.yaml +23 -0
  116. package/src/ontology/archetypes/sections/send-message.yaml +63 -0
  117. package/src/ontology/archetypes/sections/service-metadata-block.yaml +40 -0
  118. package/src/ontology/archetypes/sections/social-proof.yaml +27 -0
  119. package/src/ontology/archetypes/sections/transparency.yaml +32 -0
  120. package/src/ontology/archetypes/sections/trust-strip.yaml +42 -0
  121. package/src/ontology/archetypes/sections/video-section.yaml +27 -0
  122. package/src/ontology/archetypes/sections/women.yaml +29 -0
  123. package/src/ontology/biome-token-projection.ts +229 -0
  124. package/src/ontology/biomes/check-concrete-blueprint.yaml +118 -0
  125. package/src/ontology/biomes/handwerk-material-warm.yaml +135 -0
  126. package/src/ontology/biomes/nonprofit-trust.yaml +123 -0
  127. package/src/ontology/blueprints/offer.yaml +39 -0
  128. package/src/ontology/blueprints/prompts/local-market-signal.md +13 -0
  129. package/src/ontology/blueprints/prompts/website-local-narrative.md +24 -0
  130. package/src/ontology/blueprints/ratgeber.yaml +62 -0
  131. package/src/ontology/blueprints/website-local.yaml +309 -0
  132. package/src/ontology/blueprints/website-service.yaml +84 -0
  133. package/src/ontology/capabilities/lead.submit.yaml +44 -0
  134. package/src/ontology/cosmic/index.ts +48 -0
  135. package/src/ontology/cosmic/moon-catalog.ts +173 -0
  136. package/src/ontology/cosmic/planet-catalog.ts +82 -0
  137. package/src/ontology/cosmic/star-catalog.ts +337 -0
  138. package/src/ontology/enums.ts +159 -0
  139. package/src/ontology/external-surfaces/index.ts +158 -0
  140. package/src/ontology/external-surfaces/jsonld-types.yaml +135 -0
  141. package/src/ontology/external-surfaces/sitemap-shape.yaml +6 -0
  142. package/src/ontology/external-surfaces/url-schema.yaml +95 -0
  143. package/src/ontology/growth/events/contact-email-click.yaml +21 -0
  144. package/src/ontology/growth/events/contact-form-submit.yaml +25 -0
  145. package/src/ontology/growth/events/contact-phone-click.yaml +21 -0
  146. package/src/ontology/growth/events/contact-route-click.yaml +21 -0
  147. package/src/ontology/growth/events/contact-submit.yaml +28 -0
  148. package/src/ontology/growth/events/contact-whatsapp-click.yaml +21 -0
  149. package/src/ontology/growth/events/cta-click.yaml +30 -0
  150. package/src/ontology/growth/events/donation-confirmed.yaml +32 -0
  151. package/src/ontology/growth/events/donation-form-start.yaml +21 -0
  152. package/src/ontology/growth/events/donation-form-submit.yaml +29 -0
  153. package/src/ontology/growth/events/donation-intent.yaml +29 -0
  154. package/src/ontology/growth/events/form-error.yaml +27 -0
  155. package/src/ontology/growth/events/form-start.yaml +21 -0
  156. package/src/ontology/growth/events/form-submit.yaml +21 -0
  157. package/src/ontology/growth/events/outbound-click.yaml +25 -0
  158. package/src/ontology/growth/events/page-view.yaml +24 -0
  159. package/src/ontology/growth/events/passport-view.yaml +28 -0
  160. package/src/ontology/growth/events/star-map-navigate.yaml +30 -0
  161. package/src/ontology/index.ts +165 -0
  162. package/src/ontology/manifest.ts +344 -0
  163. package/src/ontology/operations/index.ts +1 -0
  164. package/src/ontology/schemas/biome.ts +303 -0
  165. package/src/ontology/schemas/capability.ts +104 -0
  166. package/src/ontology/schemas/constellation.ts +114 -0
  167. package/src/ontology/schemas/dns-records.ts +53 -0
  168. package/src/ontology/schemas/index.ts +95 -0
  169. package/src/ontology/schemas/manifest-resolver.ts +123 -0
  170. package/src/ontology/schemas/page-entry.ts +213 -0
  171. package/src/ontology/schemas/section-archetype.ts +109 -0
  172. package/src/ontology/schemas/site-family.ts +98 -0
  173. package/src/ontology/schemas/system/growth.ts +80 -0
  174. package/src/ontology/schemas/system/integrations.ts +143 -0
  175. package/src/ontology/schemas/system/manifest.ts +492 -0
  176. package/src/ontology/schemas/system/page-output.ts +99 -0
  177. package/src/ontology/schemas/system/release.ts +58 -0
  178. package/src/ontology/schemas/system/text.ts +58 -0
  179. package/src/ontology/schemas/system.ts +53 -0
  180. package/src/ontology/shared-section-props/body-fragments.ts +182 -0
  181. package/src/ontology/shared-section-props/catalog.ts +195 -0
  182. package/src/ontology/shared-section-props/common.ts +178 -0
  183. package/src/ontology/shared-section-props/index.ts +34 -0
  184. package/src/ontology/shared-section-props/visual-header.ts +163 -0
  185. package/src/ontology/site-families/charity-donation-trust/cultural-rules.yaml +6 -0
  186. package/src/ontology/site-families/charity-donation-trust/family.yaml +44 -0
  187. package/src/ontology/site-families/charity-donation-trust/linguistic-rules.yaml +6 -0
  188. package/src/ontology/site-families/check-quality-operator/cultural-rules.yaml +6 -0
  189. package/src/ontology/site-families/check-quality-operator/family.yaml +40 -0
  190. package/src/ontology/site-families/check-quality-operator/linguistic-rules.yaml +6 -0
  191. package/src/ontology/site-families/handwerk-trust-engineering/cultural-rules.yaml +6 -0
  192. package/src/ontology/site-families/handwerk-trust-engineering/family.yaml +53 -0
  193. package/src/ontology/site-families/handwerk-trust-engineering/linguistic-rules.yaml +6 -0
  194. package/src/ontology/tests/catalogs.pbt.test.ts +89 -0
  195. package/src/ontology/tests/enums.test.ts +203 -0
  196. package/src/ontology/tests/sternsystem-owner.test.ts +63 -0
  197. package/src/ontology/vitest.config.ts +8 -0
  198. package/src/passport/dht-sign.test.ts +99 -0
  199. package/src/passport/dht-sign.ts +73 -0
  200. package/src/passport/identity-sign.test.ts +134 -0
  201. package/src/passport/identity-sign.ts +85 -0
  202. package/src/passport/index.ts +53 -0
  203. package/src/passport/key-rotate.ts +133 -0
  204. package/src/passport/schema.ts +198 -0
  205. package/src/passport/sign.ts +225 -0
  206. package/src/passport/tests/schema.pbt.test.ts +93 -0
  207. package/src/passport/tests/schema.test.ts +222 -0
  208. package/src/passport/vitest.config.ts +8 -0
  209. package/src/share/agent/api-catalog.ts +77 -0
  210. package/src/share/agent/capability.ts +68 -0
  211. package/src/share/agent/dns-aid.test.ts +74 -0
  212. package/src/share/agent/dns-aid.ts +53 -0
  213. package/src/share/agent/fleet-catalog.ts +149 -0
  214. package/src/share/agent/index.ts +29 -0
  215. package/src/share/agent/knowledge.ts +96 -0
  216. package/src/share/agent/manifest.ts +126 -0
  217. package/src/share/agent/mcp-card.ts +63 -0
  218. package/src/share/agent/omit-empty.ts +77 -0
  219. package/src/share/agent/openapi.ts +157 -0
  220. package/src/share/agent/proof.ts +61 -0
  221. package/src/share/attribution-display.ts +86 -0
  222. package/src/share/check-hints.ts +38 -0
  223. package/src/share/content/entity-id.ts +65 -0
  224. package/src/share/content/index.ts +16 -0
  225. package/src/share/content/merge.ts +86 -0
  226. package/src/share/content/resolve-field-path.ts +39 -0
  227. package/src/share/content/substitute-deep.ts +47 -0
  228. package/src/share/content-discipline/index.ts +14 -0
  229. package/src/share/content-discipline/parsers.ts +66 -0
  230. package/src/share/content-discipline/types.ts +118 -0
  231. package/src/share/content-reference.ts +333 -0
  232. package/src/share/counter-utils.ts +75 -0
  233. package/src/share/css-value-normalize.ts +48 -0
  234. package/src/share/dev-props-validator.ts +131 -0
  235. package/src/share/entitlement.ts +172 -0
  236. package/src/share/env.d.ts +73 -0
  237. package/src/share/feature-policy.ts +367 -0
  238. package/src/share/formula-eval.ts +364 -0
  239. package/src/share/fs/index.ts +96 -0
  240. package/src/share/i18n/localization.ts +57 -0
  241. package/src/share/image-provider.ts +314 -0
  242. package/src/share/index.ts +86 -0
  243. package/src/share/knowledge/claim.ts +129 -0
  244. package/src/share/knowledge/derivation.ts +55 -0
  245. package/src/share/knowledge/freshness.ts +127 -0
  246. package/src/share/knowledge/index.ts +23 -0
  247. package/src/share/knowledge/ledger.ts +222 -0
  248. package/src/share/knowledge/plan.ts +122 -0
  249. package/src/share/knowledge/source.ts +170 -0
  250. package/src/share/legal/translation-policy.ts +133 -0
  251. package/src/share/material-credits.ts +181 -0
  252. package/src/share/middleware/language-redirect.ts +49 -0
  253. package/src/share/offer-capacity.ts +149 -0
  254. package/src/share/onboarding-yaml/index.ts +162 -0
  255. package/src/share/page.ts +351 -0
  256. package/src/share/redirects.test.ts +62 -0
  257. package/src/share/redirects.ts +54 -0
  258. package/src/share/rfc0042-utils.ts +95 -0
  259. package/src/share/runtime-context.ts +70 -0
  260. package/src/share/schemas/claim-records.ts +69 -0
  261. package/src/share/schemas/claims.ts +150 -0
  262. package/src/share/schemas/effects.ts +212 -0
  263. package/src/share/schemas/features.ts +147 -0
  264. package/src/share/schemas/horizontal-align.ts +22 -0
  265. package/src/share/schemas/icon-color.ts +27 -0
  266. package/src/share/schemas/index.ts +43 -0
  267. package/src/share/schemas/live-photo.ts +53 -0
  268. package/src/share/schemas/material-credit.ts +292 -0
  269. package/src/share/schemas/media.ts +220 -0
  270. package/src/share/schemas/navigation.ts +74 -0
  271. package/src/share/schemas/page-base.ts +33 -0
  272. package/src/share/schemas/participant.ts +247 -0
  273. package/src/share/schemas/person.ts +24 -0
  274. package/src/share/schemas/print.ts +93 -0
  275. package/src/share/schemas/section-background.ts +106 -0
  276. package/src/share/schemas/section-body.ts +138 -0
  277. package/src/share/schemas/section-cards.ts +37 -0
  278. package/src/share/schemas/section-cta.ts +74 -0
  279. package/src/share/schemas/section-header.ts +77 -0
  280. package/src/share/schemas/section-image.ts +77 -0
  281. package/src/share/schemas/section-motion.ts +52 -0
  282. package/src/share/schemas/section-shell.ts +63 -0
  283. package/src/share/schemas/section-stats.ts +37 -0
  284. package/src/share/schemas/site-background.ts +78 -0
  285. package/src/share/schemas/standard-list-item.ts +38 -0
  286. package/src/share/scripts/external-links.ts +45 -0
  287. package/src/share/scripts/gsap-counter.ts +168 -0
  288. package/src/share/scripts/gsap-mountain-journey.ts +236 -0
  289. package/src/share/scripts/gsap-parallax.ts +50 -0
  290. package/src/share/scripts/gsap-reveal.ts +65 -0
  291. package/src/share/scripts/gsap-stagger.ts +54 -0
  292. package/src/share/scripts/index.ts +25 -0
  293. package/src/share/scripts/inline-number-animation.ts +120 -0
  294. package/src/share/scripts/lenis.ts +109 -0
  295. package/src/share/scripts/live-photos.ts +250 -0
  296. package/src/share/scripts/lordicon.ts +94 -0
  297. package/src/share/scripts/orchestrator.ts +138 -0
  298. package/src/share/scripts/scheduler.ts +53 -0
  299. package/src/share/scripts/video-player.ts +116 -0
  300. package/src/share/semantic/ai.ts +140 -0
  301. package/src/share/semantic/block-extraction.ts +52 -0
  302. package/src/share/semantic/block-extractors/index.ts +502 -0
  303. package/src/share/semantic/breadcrumbs.ts +120 -0
  304. package/src/share/semantic/build-page.ts +309 -0
  305. package/src/share/semantic/business-projection.ts +278 -0
  306. package/src/share/semantic/derived-prices-loader.ts +36 -0
  307. package/src/share/semantic/extract.ts +118 -0
  308. package/src/share/semantic/feed.ts +124 -0
  309. package/src/share/semantic/ids.ts +76 -0
  310. package/src/share/semantic/image-sitemap.ts +153 -0
  311. package/src/share/semantic/index.ts +36 -0
  312. package/src/share/semantic/jsonld/article.ts +47 -0
  313. package/src/share/semantic/jsonld/breadcrumb.ts +47 -0
  314. package/src/share/semantic/jsonld/collection-list.ts +30 -0
  315. package/src/share/semantic/jsonld/context.ts +46 -0
  316. package/src/share/semantic/jsonld/faq.ts +49 -0
  317. package/src/share/semantic/jsonld/initiative.ts +53 -0
  318. package/src/share/semantic/jsonld/organization.ts +101 -0
  319. package/src/share/semantic/jsonld/person.ts +71 -0
  320. package/src/share/semantic/jsonld/service.ts +80 -0
  321. package/src/share/semantic/jsonld/shared.ts +31 -0
  322. package/src/share/semantic/jsonld/types.ts +18 -0
  323. package/src/share/semantic/jsonld/webpage.ts +98 -0
  324. package/src/share/semantic/jsonld/website.ts +27 -0
  325. package/src/share/semantic/jsonld.ts +75 -0
  326. package/src/share/semantic/llms-policy.ts +74 -0
  327. package/src/share/semantic/llms.ts +394 -0
  328. package/src/share/semantic/markdown-hygiene.ts +68 -0
  329. package/src/share/semantic/markdown-twin-provenance.ts +242 -0
  330. package/src/share/semantic/models.ts +402 -0
  331. package/src/share/semantic/organization-profile.ts +160 -0
  332. package/src/share/semantic/output-projection.ts +131 -0
  333. package/src/share/semantic/page-builders/markdown-page.ts +84 -0
  334. package/src/share/semantic/page-markdown.ts +234 -0
  335. package/src/share/semantic/page-utils.ts +125 -0
  336. package/src/share/semantic/price-marker-resolver.ts +92 -0
  337. package/src/share/semantic/robots.ts +127 -0
  338. package/src/share/semantic/update-stamp.ts +136 -0
  339. package/src/share/shared-context.ts +177 -0
  340. package/src/share/string-utils.ts +19 -0
  341. package/src/share/tests/api-catalog.test.ts +97 -0
  342. package/src/share/tests/breadcrumbs.test.ts +126 -0
  343. package/src/share/tests/build-page-price-markers.test.ts +160 -0
  344. package/src/share/tests/capability.test.ts +107 -0
  345. package/src/share/tests/claim.test.ts +90 -0
  346. package/src/share/tests/content-ref-index.test.ts +328 -0
  347. package/src/share/tests/create-dev-props-validator.test.ts +38 -0
  348. package/src/share/tests/derivation.test.ts +39 -0
  349. package/src/share/tests/dev-props-validator.test.ts +88 -0
  350. package/src/share/tests/fleet-catalog.test.ts +134 -0
  351. package/src/share/tests/formula-eval.test.ts +619 -0
  352. package/src/share/tests/freshness.test.ts +60 -0
  353. package/src/share/tests/hero-section-numbering-parity.test.ts +51 -0
  354. package/src/share/tests/image-sitemap.test.ts +101 -0
  355. package/src/share/tests/jsonld-service.test.ts +282 -0
  356. package/src/share/tests/knowledge.test.ts +86 -0
  357. package/src/share/tests/ledger.test.ts +125 -0
  358. package/src/share/tests/llms-0789.test.ts +63 -0
  359. package/src/share/tests/manifest.test.ts +100 -0
  360. package/src/share/tests/markdown-twin-provenance.test.ts +108 -0
  361. package/src/share/tests/mcp-card.test.ts +57 -0
  362. package/src/share/tests/onboarding-yaml.test.ts +111 -0
  363. package/src/share/tests/ontology-role-by-cosmic-name.test.ts +28 -0
  364. package/src/share/tests/openapi.test.ts +116 -0
  365. package/src/share/tests/organization-jsonld.test.ts +74 -0
  366. package/src/share/tests/output-projection.test.ts +61 -0
  367. package/src/share/tests/plan.test.ts +97 -0
  368. package/src/share/tests/price-marker-resolver.test.ts +141 -0
  369. package/src/share/tests/proof.test.ts +72 -0
  370. package/src/share/tests/resolve-field-path.test.ts +52 -0
  371. package/src/share/tests/source.test.ts +81 -0
  372. package/src/share/tests/substitute-deep.test.ts +65 -0
  373. package/src/share/tests/text-normalize.pbt.test.ts +143 -0
  374. package/src/share/tests/text-normalize.test.ts +285 -0
  375. package/src/share/tests/twin-path.test.ts +43 -0
  376. package/src/share/text-normalize.ts +548 -0
  377. package/src/share/text-position.ts +19 -0
  378. package/src/share/types/hls-js-light.d.ts +16 -0
  379. package/src/share/visibility.ts +167 -0
  380. package/src/share/vitest.config.ts +8 -0
  381. package/src/share/wrap-inline-numbers.ts +139 -0
  382. package/src/surface/blueprint-schema.ts +314 -0
  383. package/src/surface/blueprint-types.ts +256 -0
  384. package/src/surface/blueprint.ts +300 -0
  385. package/src/surface/breaker.ts +57 -0
  386. package/src/surface/decision-composer.ts +156 -0
  387. package/src/surface/eligibility.ts +372 -0
  388. package/src/surface/evidence-records.ts +97 -0
  389. package/src/surface/fleet.ts +60 -0
  390. package/src/surface/geo.ts +170 -0
  391. package/src/surface/governance.ts +146 -0
  392. package/src/surface/index.ts +216 -0
  393. package/src/surface/io/index.ts +18 -0
  394. package/src/surface/io/surface-module-context-io.ts +60 -0
  395. package/src/surface/io/visibility-outcomes-io.ts +46 -0
  396. package/src/surface/module-context.ts +120 -0
  397. package/src/surface/substance.ts +161 -0
  398. package/src/surface/tests/eligibility.pbt.test.ts +137 -0
  399. package/src/surface/tests/eligibility.test.ts +302 -0
  400. package/src/surface/types.ts +289 -0
  401. package/src/surface/visibility.ts +57 -0
  402. package/src/surface/vitest.config.ts +8 -0
  403. package/tsconfig.json +17 -0
@@ -0,0 +1,256 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>
4
+ Blueprint type definitions extracted from blueprint.ts. Pure type
5
+ contracts for the declarative surface spec — no functions, no I/O.
6
+ </purpose>
7
+ <non-goals>
8
+ <item>Do not define functions — those live in blueprint.ts.</item>
9
+ </non-goals>
10
+ </MODULE_CONTRACT>
11
+ <CHANGE_SUMMARY>
12
+ <item>Architecture review 2026-07-14: extract blueprint type definitions from blueprint.ts.</item>
13
+ </CHANGE_SUMMARY>
14
+ */
15
+
16
+ /** A localized string map: lang → value. */
17
+ export type LocalizedString = Record<string, string>;
18
+
19
+ export interface BlueprintAxis {
20
+ id: string;
21
+ universe: { collection: string; field: string } | { provider: string };
22
+ match: { recordField: string };
23
+ }
24
+
25
+ export type GeoDepth = "full" | "twin-only" | "off";
26
+
27
+ export interface BlueprintLevelArticle {
28
+ publishedAt: string;
29
+ updatedAt?: string;
30
+ author?: string;
31
+ tags?: string[];
32
+ }
33
+
34
+ export interface BlueprintPillarHero {
35
+ eyebrow: LocalizedString;
36
+ heading: LocalizedString;
37
+ lead: LocalizedString;
38
+ primaryCta: { label: LocalizedString; target: string };
39
+ secondaryCta: { label: LocalizedString; target: string };
40
+ }
41
+
42
+ export interface BlueprintPillarAdaptationDimension {
43
+ heading: LocalizedString;
44
+ body: LocalizedString;
45
+ }
46
+
47
+ export interface BlueprintPillarAdaptation {
48
+ heading: LocalizedString;
49
+ dimensions: BlueprintPillarAdaptationDimension[];
50
+ }
51
+
52
+ export interface BlueprintPillarProductPrice {
53
+ heading: LocalizedString;
54
+ body: LocalizedString;
55
+ priceRef: string;
56
+ }
57
+
58
+ export interface BlueprintPillarFinalCta {
59
+ heading: LocalizedString;
60
+ body: LocalizedString;
61
+ primaryCta: { label: LocalizedString; target: string };
62
+ secondaryCta: { label: LocalizedString; target: string };
63
+ }
64
+
65
+ export interface BlueprintPillar {
66
+ hero: BlueprintPillarHero;
67
+ adaptation: BlueprintPillarAdaptation;
68
+ productPrice: BlueprintPillarProductPrice;
69
+ finalCta: BlueprintPillarFinalCta;
70
+ catalogHeading?: LocalizedString;
71
+ }
72
+
73
+ export interface ServicePublicationGate {
74
+ minServiceVariants: number;
75
+ minCustomerQuestions: number;
76
+ minPriceModels: number;
77
+ minFaq: number;
78
+ minPageStructure: number;
79
+ }
80
+
81
+ export interface BlueprintServiceConfig {
82
+ gate: ServicePublicationGate;
83
+ claimRestrictions: string[];
84
+ mode: "warn" | "fail";
85
+ }
86
+
87
+ export interface BlueprintLinkingParent {
88
+ surface: string;
89
+ depth: number;
90
+ joinField: string;
91
+ }
92
+
93
+ export interface IndustryPublicationGate {
94
+ minServiceCategories: number;
95
+ minCustomerJourneys: number;
96
+ minTrustSignals: number;
97
+ minArchitectureEntries: number;
98
+ minModuleMappings: number;
99
+ minUniqueFaq: number;
100
+ }
101
+
102
+ export interface BlueprintDossier {
103
+ gate: IndustryPublicationGate;
104
+ claimRestrictions: string[];
105
+ doorwayMaxFlaggedShare: number;
106
+ duplicateMaxSimilarity: number;
107
+ mode: "warn" | "fail";
108
+ }
109
+
110
+ export interface IntersectionGate {
111
+ minLocalServiceQuestions: number;
112
+ minScenarios: number;
113
+ minLocalEvidence: number;
114
+ minUniqueContentBlocks: number;
115
+ minUniqueFaq: number;
116
+ minSources: number;
117
+ }
118
+
119
+ export interface IntersectionSimilarity {
120
+ similarityToIndustryPage: number;
121
+ similarityToCityPage: number;
122
+ similarityToServicePage: number;
123
+ similarityToOtherIntersections: number;
124
+ }
125
+
126
+ export interface BlueprintIntersectionConfig {
127
+ gate: IntersectionGate;
128
+ similarity: IntersectionSimilarity;
129
+ substanceIndependenceThreshold: number;
130
+ mode: "warn" | "fail";
131
+ }
132
+
133
+ export interface BlueprintHubConfig {
134
+ cardFields: string[];
135
+ reservedSlugs: string[];
136
+ }
137
+
138
+ export interface BlueprintStatusGate {
139
+ allowedStatuses: string[];
140
+ excludedStatuses: string[];
141
+ }
142
+
143
+ export interface BlueprintLevel {
144
+ depth: number;
145
+ slug: LocalizedString;
146
+ redirectToPageId?: string;
147
+ constellation: string;
148
+ geo?: GeoDepth;
149
+ titleTemplate?: LocalizedString;
150
+ descriptionTemplate?: LocalizedString;
151
+ intro?: LocalizedString;
152
+ semanticType?: string;
153
+ article?: BlueprintLevelArticle;
154
+ pillar?: BlueprintPillar;
155
+ dossier?: BlueprintDossier;
156
+ service?: BlueprintServiceConfig;
157
+ intersection?: BlueprintIntersectionConfig;
158
+ hub?: BlueprintHubConfig;
159
+ }
160
+
161
+ export interface BlueprintLinking {
162
+ children?: { limit: number };
163
+ siblings?: { limit: number };
164
+ teasers?: { relevance?: Array<{ sharedAxis: string; weight: number }> };
165
+ parent?: BlueprintLinkingParent;
166
+ }
167
+
168
+ export interface BlueprintProjection {
169
+ title?: LocalizedString;
170
+ description?: LocalizedString | { ref: string };
171
+ }
172
+
173
+ export interface EnrichedFieldSpec {
174
+ field: string;
175
+ promptId: string;
176
+ maxTokens: number;
177
+ scopeDepth: number;
178
+ kind?: "field" | "narrative";
179
+ scope?: "tuple" | "record";
180
+ axis?: string;
181
+ }
182
+
183
+ export interface BlueprintDuplicatePolicy {
184
+ method?: "shingle" | "simhash";
185
+ maxSimilarityWithinCluster?: number;
186
+ }
187
+
188
+ export interface BlueprintEvidenceDepthPolicy {
189
+ approvedNarrative?: "required" | "optional";
190
+ requiredRecordFields?: readonly string[];
191
+ preferredEvidenceSources?: readonly string[];
192
+ minTupleSpecificFacts?: number;
193
+ minWerkEvidence?: number;
194
+ existenceSource?: "records" | "works";
195
+ freshness?: "valid-and-current" | "valid";
196
+ duplicate?: BlueprintDuplicatePolicy;
197
+ leadImage?: "required" | "warning" | "optional";
198
+ mode?: "error" | "warning";
199
+ }
200
+
201
+ export interface BlueprintDemandDepthPolicy {
202
+ minVolume?: number;
203
+ allowIntents?: readonly ("informational" | "commercial" | "transactional" | "navigational")[];
204
+ missing?: "noindex" | "do-not-emit";
205
+ staleAfterDays?: number;
206
+ }
207
+
208
+ export interface BlueprintDepthRolePolicy {
209
+ indexability: "index" | "navigation-noindex" | "evidence-gated";
210
+ canonicalTarget?: "tradeHub" | number;
211
+ follow?: boolean;
212
+ includeInSitemap?: boolean;
213
+ geo?: GeoDepth;
214
+ localEvidence?: {
215
+ minVerifiedFacts?: number;
216
+ minCitySpecificQa?: number;
217
+ minUniqueTokenShare?: number;
218
+ maxBodySimilarityWithinBranch?: number;
219
+ };
220
+ }
221
+
222
+ export interface BlueprintPolicy {
223
+ minRecordsPerDepth: Record<number, number>;
224
+ noindexBelowPerDepth?: Record<number, number>;
225
+ redirectPolicy?: "nearest-ancestor" | "root";
226
+ trailingSlash?: boolean;
227
+ maxStubDepth?: number;
228
+ substanceMin?: number;
229
+ substanceMinPerDepth?: Record<number, number>;
230
+ evidencePerDepth?: Record<number, BlueprintEvidenceDepthPolicy>;
231
+ demandPerDepth?: Record<number, BlueprintDemandDepthPolicy>;
232
+ depthRoles?: Record<number, BlueprintDepthRolePolicy>;
233
+ sitemapBudget?: number;
234
+ maxThinShare?: number;
235
+ regionalGateDepths?: readonly number[];
236
+ bake?: "inline" | "lazy";
237
+ statusGate?: BlueprintStatusGate;
238
+ }
239
+
240
+ export interface Blueprint {
241
+ id: string;
242
+ entitlement: string;
243
+ dataset: { collection: string; status?: string };
244
+ axes: BlueprintAxis[];
245
+ levels: BlueprintLevel[];
246
+ policy: BlueprintPolicy;
247
+ linking?: BlueprintLinking;
248
+ rotation?: { variantsByTupleHash: boolean };
249
+ projection?: BlueprintProjection;
250
+ freshness?: {
251
+ slaDaysPerDepth: Record<number, number>;
252
+ field: string;
253
+ mode?: "any" | "all" | "median";
254
+ };
255
+ enrichedFields?: EnrichedFieldSpec[];
256
+ }
@@ -0,0 +1,300 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>
4
+ [RFC-0192/0193] The Blueprint contract type (the declarative spec that configures one surface)
5
+ plus the pure helpers that turn a Blueprint + loaded datasets into the eligibility matrix and
6
+ the materialized VirtualRouteEntry[] (routes + redirect decisions). Framework-free. The runtime
7
+ Zod schema and the YAML files live in @warpgogol/werkstatt-shared/ontology (RFC-0193); block baking is added there.
8
+ </purpose>
9
+ <non-goals>
10
+ <item>Do not parse YAML or validate (ontology owns the Zod schema).</item>
11
+ <item>Do not read content or bake page blocks (the kernel command / RFC-0193 provider does).</item>
12
+ </non-goals>
13
+ </MODULE_CONTRACT>
14
+ <CHANGE_SUMMARY>
15
+ <item>RFC-0192: Blueprint type + entry assembly (no block baking yet).</item>
16
+ <item>RFC-0199: resolveSlug/routesFor/assembleEntries/generateEntries take a LocalizedUniverse so URL segments localize per language while identity stays on the neutral tuple.</item>
17
+ <item>RFC-0496: add BlueprintServiceConfig + ServicePublicationGate for website-service depth-1 service dossier configuration; add BlueprintLinkingParent for cross-surface parent linking.</item>
18
+ <item>RFC-0497: add BlueprintIntersectionConfig + IntersectionGate + IntersectionSimilarity for website-local depth-5 intersection gate configuration.</item>
19
+ <item>RFC-0500: add BlueprintHubConfig for depth-0 editorial knowledge hub configuration; add BlueprintStatusGate for record status filtering.</item>
20
+ </CHANGE_SUMMARY>
21
+ */
22
+
23
+ import {
24
+ buildEligibilityMatrix,
25
+ nearestLiveAncestor,
26
+ normalizeSegment,
27
+ pathKey,
28
+ type AxisFieldMap,
29
+ type EligibilityMatrix,
30
+ type MatrixEntry,
31
+ } from "./eligibility.ts";
32
+ import type {
33
+ AxisTuple,
34
+ EligibilityPolicy,
35
+ LocalizedUniverse,
36
+ SurfaceAxis,
37
+ SurfaceRecord,
38
+ VirtualRouteEntry,
39
+ } from "./types.ts";
40
+
41
+ import type {
42
+ LocalizedString,
43
+ BlueprintAxis,
44
+ GeoDepth,
45
+ BlueprintLevelArticle,
46
+ BlueprintPillarHero,
47
+ BlueprintPillarAdaptationDimension,
48
+ BlueprintPillarAdaptation,
49
+ BlueprintPillarProductPrice,
50
+ BlueprintPillarFinalCta,
51
+ BlueprintPillar,
52
+ ServicePublicationGate,
53
+ BlueprintServiceConfig,
54
+ BlueprintLinkingParent,
55
+ IndustryPublicationGate,
56
+ BlueprintDossier,
57
+ IntersectionGate,
58
+ IntersectionSimilarity,
59
+ BlueprintIntersectionConfig,
60
+ BlueprintHubConfig,
61
+ BlueprintStatusGate,
62
+ BlueprintLevel,
63
+ BlueprintLinking,
64
+ BlueprintProjection,
65
+ EnrichedFieldSpec,
66
+ BlueprintDuplicatePolicy,
67
+ BlueprintEvidenceDepthPolicy,
68
+ BlueprintDemandDepthPolicy,
69
+ BlueprintDepthRolePolicy,
70
+ BlueprintPolicy,
71
+ Blueprint,
72
+ } from "./blueprint-types.ts";
73
+
74
+ export type {
75
+ LocalizedString,
76
+ BlueprintAxis,
77
+ GeoDepth,
78
+ BlueprintLevelArticle,
79
+ BlueprintPillarHero,
80
+ BlueprintPillarAdaptationDimension,
81
+ BlueprintPillarAdaptation,
82
+ BlueprintPillarProductPrice,
83
+ BlueprintPillarFinalCta,
84
+ BlueprintPillar,
85
+ ServicePublicationGate,
86
+ BlueprintServiceConfig,
87
+ BlueprintLinkingParent,
88
+ IndustryPublicationGate,
89
+ BlueprintDossier,
90
+ IntersectionGate,
91
+ IntersectionSimilarity,
92
+ BlueprintIntersectionConfig,
93
+ BlueprintHubConfig,
94
+ BlueprintStatusGate,
95
+ BlueprintLevel,
96
+ BlueprintLinking,
97
+ BlueprintProjection,
98
+ EnrichedFieldSpec,
99
+ BlueprintDuplicatePolicy,
100
+ BlueprintEvidenceDepthPolicy,
101
+ BlueprintDemandDepthPolicy,
102
+ BlueprintDepthRolePolicy,
103
+ BlueprintPolicy,
104
+ Blueprint,
105
+ };
106
+
107
+ const DEFAULT_SEGMENT_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*$/;
108
+
109
+ /** Resolve the Blueprint policy into a concrete EligibilityPolicy. */
110
+ export function resolvePolicy(bp: Blueprint): EligibilityPolicy {
111
+ return {
112
+ minRecordsPerDepth: bp.policy.minRecordsPerDepth,
113
+ noindexBelowPerDepth: bp.policy.noindexBelowPerDepth ?? {},
114
+ redirectPolicy: bp.policy.redirectPolicy ?? "nearest-ancestor",
115
+ trailingSlash: bp.policy.trailingSlash ?? true,
116
+ segmentPattern: DEFAULT_SEGMENT_PATTERN,
117
+ };
118
+ }
119
+
120
+ export function buildAxisFieldMap(bp: Blueprint): AxisFieldMap {
121
+ const map: Record<string, string> = {};
122
+ for (const axis of bp.axes) map[axis.id] = axis.match.recordField;
123
+ return map;
124
+ }
125
+
126
+ /** Build SurfaceAxis[] from a Blueprint and the loaded value universes (axisId → slugs). */
127
+ export function buildAxes(
128
+ bp: Blueprint,
129
+ universes: Record<string, readonly string[]>,
130
+ ): SurfaceAxis[] {
131
+ return bp.axes.map((axis) => ({ id: axis.id, universe: universes[axis.id] ?? [] }));
132
+ }
133
+
134
+ /** Synthetic stable pageId for a (blueprint, depth, tuple). */
135
+ export function pageIdFor(
136
+ bp: Blueprint,
137
+ depth: number,
138
+ tuple: AxisTuple,
139
+ axisOrder: readonly string[],
140
+ ): string {
141
+ if (depth === 0) return `${bp.id}:_root`;
142
+ const values: string[] = [];
143
+ for (let i = 0; i < depth; i += 1) values.push(tuple[axisOrder[i]!] ?? "");
144
+ return `${bp.id}:${values.join(":")}`;
145
+ }
146
+
147
+ function levelByDepth(bp: Blueprint, depth: number): BlueprintLevel | undefined {
148
+ return bp.levels.find((level) => level.depth === depth);
149
+ }
150
+
151
+ function tradeHubDepth(bp: Blueprint): number {
152
+ for (const [depth, role] of Object.entries(bp.policy.depthRoles ?? {})) {
153
+ if (role.indexability === "index") return Number(depth);
154
+ }
155
+ return 1;
156
+ }
157
+
158
+ function canonicalTargetPageId(
159
+ bp: Blueprint,
160
+ entry: MatrixEntry,
161
+ axisOrder: readonly string[],
162
+ ): string | undefined {
163
+ const role = bp.policy.depthRoles?.[entry.depth];
164
+ if (role?.indexability !== "navigation-noindex") return undefined;
165
+ const targetDepth =
166
+ role.canonicalTarget === "tradeHub"
167
+ ? tradeHubDepth(bp)
168
+ : typeof role.canonicalTarget === "number"
169
+ ? role.canonicalTarget
170
+ : undefined;
171
+ if (targetDepth === undefined || targetDepth >= entry.depth) return undefined;
172
+ return pageIdFor(bp, targetDepth, entry.tuple, axisOrder);
173
+ }
174
+
175
+ /**
176
+ * Resolve a slug template ("website/{industry}/{city}") against a tuple for one language,
177
+ * normalizing each value. RFC-0199: each token's value is the per-language localized slug from
178
+ * `universe` when present, falling back to the neutral tuple value otherwise — so the identity key
179
+ * stays neutral while the emitted URL segment localizes.
180
+ */
181
+ export function resolveSlug(
182
+ template: string,
183
+ tuple: AxisTuple,
184
+ lang: string,
185
+ universe: LocalizedUniverse,
186
+ pattern: RegExp,
187
+ ): string {
188
+ return template.replace(/\{([a-zA-Z0-9_]+)\}/g, (_match, axisId: string) => {
189
+ const value = tuple[axisId];
190
+ if (value === undefined) return "";
191
+ const localized = universe[axisId]?.get(value)?.byLang?.[lang] ?? value;
192
+ return normalizeSegment(localized, pattern);
193
+ });
194
+ }
195
+
196
+ /** Localized routes (lang → slug) for one matrix entry. */
197
+ function routesFor(
198
+ bp: Blueprint,
199
+ entry: MatrixEntry,
200
+ langs: readonly string[],
201
+ pattern: RegExp,
202
+ universe: LocalizedUniverse,
203
+ ): Record<string, string> {
204
+ const level = levelByDepth(bp, entry.depth);
205
+ const routes: Record<string, string> = {};
206
+ if (!level) return routes;
207
+ for (const lang of langs) {
208
+ const template = level.slug[lang] ?? level.slug[langs[0]!] ?? "";
209
+ routes[lang] = resolveSlug(template, entry.tuple, lang, universe, pattern);
210
+ }
211
+ return routes;
212
+ }
213
+
214
+ /**
215
+ * Turn the eligibility matrix into materialized VirtualRouteEntry[] (routes + redirect targets).
216
+ * Block baking (entry.page) is layered on by the kernel command / RFC-0193 provider afterwards.
217
+ */
218
+ export function assembleEntries(
219
+ bp: Blueprint,
220
+ matrix: EligibilityMatrix,
221
+ langs: readonly string[],
222
+ policy: EligibilityPolicy,
223
+ localizedUniverse: LocalizedUniverse = {},
224
+ ): VirtualRouteEntry[] {
225
+ const result: VirtualRouteEntry[] = [];
226
+ for (const entry of matrix.entries) {
227
+ const pageId = pageIdFor(bp, entry.depth, entry.tuple, matrix.axisOrder);
228
+ const routes = routesFor(bp, entry, langs, policy.segmentPattern, localizedUniverse);
229
+ const level = levelByDepth(bp, entry.depth);
230
+ const role = bp.policy.depthRoles?.[entry.depth];
231
+ const navigationNoindex = role?.indexability === "navigation-noindex";
232
+ const geo = navigationNoindex ? (role.geo ?? "off") : (level?.geo ?? "full");
233
+ const forcedRedirectToPageId = level?.redirectToPageId;
234
+ const indexable = forcedRedirectToPageId ? false : entry.indexable;
235
+ const noindex = forcedRedirectToPageId || navigationNoindex ? true : entry.noindex;
236
+ const canonicalPageId = canonicalTargetPageId(bp, entry, matrix.axisOrder);
237
+ let redirectToPageId: string | undefined = forcedRedirectToPageId;
238
+ if (!indexable && !redirectToPageId) {
239
+ const ancestor = nearestLiveAncestor(entry, matrix, policy);
240
+ if (ancestor) {
241
+ redirectToPageId = pageIdFor(bp, ancestor.depth, ancestor.tuple, matrix.axisOrder);
242
+ }
243
+ }
244
+ result.push({
245
+ surfaceId: bp.id,
246
+ pageId,
247
+ routes,
248
+ axes: entry.tuple,
249
+ depth: entry.depth,
250
+ recordCount: entry.recordCount,
251
+ indexable,
252
+ noindex,
253
+ geo,
254
+ ...(redirectToPageId ? { redirectToPageId } : {}),
255
+ ...(canonicalPageId ? { canonicalPageId } : {}),
256
+ decision: forcedRedirectToPageId
257
+ ? {
258
+ ...(entry.decision ?? { recordGate: true, indexable: false, noindex: true }),
259
+ indexable: false,
260
+ noindex: true,
261
+ reason: "redirect-stub",
262
+ }
263
+ : navigationNoindex
264
+ ? {
265
+ ...(entry.decision ?? { recordGate: true, indexable: true, noindex: true }),
266
+ indexable,
267
+ noindex: true,
268
+ reason: "navigation-noindex",
269
+ }
270
+ : entry.decision,
271
+ });
272
+ }
273
+ return result;
274
+ }
275
+
276
+ /** Full pipeline: Blueprint + loaded data → VirtualRouteEntry[] (no baked pages). */
277
+ export function generateEntries(
278
+ bp: Blueprint,
279
+ data: {
280
+ records: readonly SurfaceRecord[];
281
+ universes: Record<string, readonly string[]>;
282
+ langs: readonly string[];
283
+ /** RFC-0199: per-language slug segments. Absent ⇒ neutral slugs only (legacy behavior). */
284
+ localizedUniverse?: LocalizedUniverse;
285
+ /** RFC-0240: whether the resolved entitlements unlock the regional-hub-or-higher `pseo` tier. */
286
+ regionalUnlocked?: boolean;
287
+ },
288
+ ): VirtualRouteEntry[] {
289
+ const policy = resolvePolicy(bp);
290
+ const axes = buildAxes(bp, data.universes);
291
+ const axisFieldMap = buildAxisFieldMap(bp);
292
+ const matrix = buildEligibilityMatrix(axes, axisFieldMap, data.records, policy, {
293
+ maxDepth: Math.max(0, ...bp.levels.map((level) => level.depth)),
294
+ maxStubDepth: bp.policy.maxStubDepth ?? 1,
295
+ forceNonIndexableDepths: data.regionalUnlocked ? [] : (bp.policy.regionalGateDepths ?? []),
296
+ });
297
+ return assembleEntries(bp, matrix, data.langs, policy, data.localizedUniverse ?? {});
298
+ }
299
+
300
+ export { pathKey };
@@ -0,0 +1,57 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>Maintains packages/surface/src/breaker.ts as an authored surface authored module so agents can evolve it without rediscovering local boundaries.</purpose>
4
+ <non-goals>
5
+ <item>Do not define URL deletion semantics; rollback consumers must obey URL non-destruction policy.</item>
6
+ </non-goals>
7
+ </MODULE_CONTRACT>
8
+ <CHANGE_SUMMARY>
9
+ <item>RFC-0283: initial implementation of circuit-breaker and reversible surface-state contracts.</item>
10
+ <item>RFC-0602: allow null createdAt in surfaceStateSchema for timestamp determinism.</item>
11
+ </CHANGE_SUMMARY>
12
+ */
13
+
14
+ import { z } from "zod";
15
+
16
+ export const surfaceStateStatusSchema = z.enum([
17
+ "candidate",
18
+ "shipped",
19
+ "lastKnownGood",
20
+ "rolledBack",
21
+ ]);
22
+
23
+ export const surfaceStateSchema = z.object({
24
+ id: z.string().min(1),
25
+ site: z.string().min(1),
26
+ createdAt: z.string().datetime().nullable(),
27
+ status: surfaceStateStatusSchema,
28
+ pageCount: z.number().int().nonnegative(),
29
+ indexableCount: z.number().int().nonnegative(),
30
+ artifactHash: z.string().min(1),
31
+ manifestHash: z.string().min(1),
32
+ });
33
+
34
+ export const tripwireActionSchema = z.enum(["freeze", "demote", "escalate", "rollback"]);
35
+
36
+ export const tripwireSchema = z.object({
37
+ id: z.string().min(1),
38
+ scope: z.string().min(1),
39
+ metric: z.string().min(1),
40
+ threshold: z.number(),
41
+ windowDays: z.number().int().positive(),
42
+ onTrip: z.array(tripwireActionSchema).min(1),
43
+ });
44
+
45
+ export const breakerVerdictSchema = z.object({
46
+ evaluatedAt: z.string().datetime(),
47
+ trippedTripwires: z.array(tripwireSchema),
48
+ affectedScopes: z.array(z.string().min(1)),
49
+ recommendedState: z.string().min(1).optional(),
50
+ blastRadius: z.number().int().nonnegative(),
51
+ });
52
+
53
+ export type SurfaceStateStatus = z.infer<typeof surfaceStateStatusSchema>;
54
+ export type SurfaceState = z.infer<typeof surfaceStateSchema>;
55
+ export type TripwireAction = z.infer<typeof tripwireActionSchema>;
56
+ export type Tripwire = z.infer<typeof tripwireSchema>;
57
+ export type BreakerVerdict = z.infer<typeof breakerVerdictSchema>;