@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,120 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>
4
+ RFC-0271: typed, schema-validated operating contexts for Programmatic Surface modules.
5
+ A module context declares which Blueprints it owns, which entitlement gates them, and which
6
+ locale is the canonical generation/review source before any derived public translation.
7
+ </purpose>
8
+ <non-goals>
9
+ <item>Do not read system.md or entitlements; kernel commands own I/O.</item>
10
+ <item>Do not redefine Blueprint axes, levels, or route policy.</item>
11
+ </non-goals>
12
+ </MODULE_CONTRACT>
13
+ <CHANGE_SUMMARY>
14
+ <item>RFC-0271: add module context contracts for masterLocale, publishedLocales, entitlement, glossary refs, translator-note refs, and generation/approval policy.</item>
15
+ <item>RFC-0277: add stage and urlPolicy fields for PSEO lifecycle governance.</item>
16
+ </CHANGE_SUMMARY>
17
+ */
18
+
19
+ import { z } from "zod";
20
+
21
+ export const moduleSiteModeSchema = z.enum(["bodenstation", "sternsystem"]);
22
+
23
+ export const pseoStageSchema = z.enum(["internalCapability", "managedVisibility", "productModule"]);
24
+
25
+ export const urlPolicySchema = z.enum(["nonDestruction"]);
26
+
27
+ export const moduleReviewPolicySchema = z.object({
28
+ firstNPerTemplateField: z.number().int().min(0).optional(),
29
+ sampleAfterStabilization: z.number().min(0).max(1).optional(),
30
+ claims: z.enum(["human", "sample", "machine"]).optional(),
31
+ });
32
+
33
+ export const surfaceModuleContextSchema = z.object({
34
+ id: z.string().min(1).optional(),
35
+ entitlement: z.string().min(1),
36
+ blueprints: z.array(z.string().min(1)).min(1),
37
+ masterLocale: z.string().min(2),
38
+ publishedLocales: z.array(z.string().min(2)).default([]),
39
+ stage: pseoStageSchema.optional(),
40
+ urlPolicy: urlPolicySchema.optional(),
41
+ context: z
42
+ .object({
43
+ siteMode: moduleSiteModeSchema.optional(),
44
+ operatorLanguage: z.string().min(2).optional(),
45
+ audience: z.string().min(1).optional(),
46
+ forbiddenClaims: z.array(z.string().min(1)).optional(),
47
+ sourceBoundaries: z.array(z.string().min(1)).optional(),
48
+ voice: z.record(z.string(), z.unknown()).optional(),
49
+ })
50
+ .default({}),
51
+ indexBudget: z
52
+ .object({
53
+ publicName: z.literal("managedCoverage").optional(),
54
+ maxIndexable: z.number().int().min(0).optional(),
55
+ regionalGateDepths: z.array(z.number().int().min(0)).optional(),
56
+ })
57
+ .optional(),
58
+ generation: z
59
+ .object({
60
+ provider: z.string().min(1).optional(),
61
+ modelPolicy: z.string().min(1).optional(),
62
+ normalBuildCallsLlm: z.literal(false).default(false),
63
+ })
64
+ .default({ normalBuildCallsLlm: false }),
65
+ approval: z
66
+ .object({
67
+ requireHumanApproval: z.boolean().default(true),
68
+ requireReadyForTranslation: z.boolean().default(true),
69
+ })
70
+ .default({ requireHumanApproval: true, requireReadyForTranslation: true }),
71
+ localization: z
72
+ .object({
73
+ glossaryRefs: z.record(z.string(), z.string()).optional(),
74
+ translatorNoteRefs: z.record(z.string(), z.string()).optional(),
75
+ reviewPolicy: z.record(z.string(), moduleReviewPolicySchema).optional(),
76
+ })
77
+ .optional(),
78
+ });
79
+
80
+ export const surfaceModulesSchema = z.record(z.string(), surfaceModuleContextSchema);
81
+
82
+ export type SurfaceModuleContext = z.infer<typeof surfaceModuleContextSchema> & { id: string };
83
+ export type SurfaceModules = Record<string, SurfaceModuleContext>;
84
+ export type PseoStage = z.infer<typeof pseoStageSchema>;
85
+ export type UrlPolicy = z.infer<typeof urlPolicySchema>;
86
+
87
+ export interface BlueprintModuleClaim {
88
+ blueprint: string;
89
+ modules: string[];
90
+ }
91
+
92
+ export function normalizeSurfaceModules(value: unknown): SurfaceModules {
93
+ const parsed = surfaceModulesSchema.parse(value ?? {});
94
+ const modules: SurfaceModules = {};
95
+ for (const [id, context] of Object.entries(parsed)) {
96
+ modules[id] = { ...context, id };
97
+ }
98
+ return modules;
99
+ }
100
+
101
+ export function findModuleForBlueprint(
102
+ modules: SurfaceModules,
103
+ blueprintId: string,
104
+ ): SurfaceModuleContext | undefined {
105
+ return Object.values(modules).find((module) => module.blueprints.includes(blueprintId));
106
+ }
107
+
108
+ export function findDuplicateBlueprintClaims(modules: SurfaceModules): BlueprintModuleClaim[] {
109
+ const claims = new Map<string, string[]>();
110
+ for (const module of Object.values(modules)) {
111
+ for (const blueprint of module.blueprints) {
112
+ const owners = claims.get(blueprint) ?? [];
113
+ owners.push(module.id);
114
+ claims.set(blueprint, owners);
115
+ }
116
+ }
117
+ return [...claims.entries()]
118
+ .filter(([, modulesForBlueprint]) => modulesForBlueprint.length > 1)
119
+ .map(([blueprint, modulesForBlueprint]) => ({ blueprint, modules: modulesForBlueprint }));
120
+ }
@@ -0,0 +1,161 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>
4
+ [RFC-0194] Page Substance Score: a deterministic build-time measure of whether a generated page
5
+ is substantively unique, not a near-duplicate template with a swapped noun. Composed from four
6
+ components — independent data blocks, unique-vs-family token ratio, signal blocks, and internal
7
+ link diversity. A page below the Blueprint's substanceMin is forced to noindex regardless of how
8
+ many records matched it. Pure — no I/O, no LLM.
9
+ </purpose>
10
+ <non-goals>
11
+ <item>Do not call an LLM or the network — the gate must be deterministic.</item>
12
+ <item>Do not mutate page content to raise a score.</item>
13
+ </non-goals>
14
+ </MODULE_CONTRACT>
15
+ <CHANGE_SUMMARY>
16
+ <item>RFC-0194: initial scorer.</item>
17
+ <item>RFC-0274: walk nested visible props so substance/duplicate checks see rendered semantic text.</item>
18
+ </CHANGE_SUMMARY>
19
+ */
20
+
21
+ import type { PageEntry } from "./types.ts";
22
+
23
+ export interface SubstanceComponents {
24
+ independentBlocks: number;
25
+ uniqueTokenRatio: number; // 0..1
26
+ signalBlocks: number;
27
+ linkDiversity: number;
28
+ }
29
+
30
+ export interface SubstanceScore {
31
+ value: number; // 0..100
32
+ components: SubstanceComponents;
33
+ }
34
+
35
+ /** Lowercase word tokens of length > 3 (cheap, deterministic, language-agnostic). */
36
+ export function tokenize(text: string): string[] {
37
+ return (text.toLowerCase().match(/[a-zà-ÿ0-9]+/gi) ?? []).filter((t) => t.length > 3);
38
+ }
39
+
40
+ const NON_VISIBLE_TEXT_KEYS = new Set([
41
+ "id",
42
+ "slug",
43
+ "pageId",
44
+ "href",
45
+ "url",
46
+ "src",
47
+ "source",
48
+ "image",
49
+ "imageName",
50
+ "leadImage",
51
+ "backgroundImage",
52
+ "poster",
53
+ "photo",
54
+ "video",
55
+ "variant",
56
+ "kind",
57
+ "type",
58
+ "use",
59
+ ]);
60
+
61
+ function collectVisibleText(value: unknown, key = ""): string[] {
62
+ if (typeof value === "string") {
63
+ const trimmed = value.trim();
64
+ if (!trimmed) return [];
65
+ if (NON_VISIBLE_TEXT_KEYS.has(key)) return [];
66
+ if (/^(\/|https?:|mailto:|tel:)/i.test(trimmed)) return [];
67
+ return [trimmed];
68
+ }
69
+ if (Array.isArray(value)) return value.flatMap((item) => collectVisibleText(item, key));
70
+ if (value && typeof value === "object") {
71
+ const out: string[] = [];
72
+ for (const [childKey, childValue] of Object.entries(value as Record<string, unknown>)) {
73
+ out.push(...collectVisibleText(childValue, childKey));
74
+ }
75
+ return out;
76
+ }
77
+ return [];
78
+ }
79
+
80
+ /** Concatenate a page's rendered semantic text, including nested visible block props. */
81
+ export function pageText(page: PageEntry): string {
82
+ const parts: string[] = [page.title, page.description].filter(Boolean);
83
+ for (const block of page.blocks) {
84
+ parts.push(...collectVisibleText(block.props));
85
+ }
86
+ return parts.join(" ");
87
+ }
88
+
89
+ /** token → number of pages whose token set contains it. */
90
+ export function buildTokenDocFreq(pages: readonly PageEntry[]): Map<string, number> {
91
+ const freq = new Map<string, number>();
92
+ for (const page of pages) {
93
+ const seen = new Set(tokenize(pageText(page)));
94
+ for (const token of seen) freq.set(token, (freq.get(token) ?? 0) + 1);
95
+ }
96
+ return freq;
97
+ }
98
+
99
+ /** Count distinct internal-link targets referenced in a page's block props. */
100
+ function countLinkTargets(page: PageEntry): number {
101
+ const targets = new Set<string>();
102
+ const visit = (value: unknown): void => {
103
+ if (typeof value === "string") {
104
+ if (/^(\/|https?:)/.test(value)) targets.add(value);
105
+ return;
106
+ }
107
+ if (Array.isArray(value)) {
108
+ for (const item of value) visit(item);
109
+ } else if (value && typeof value === "object") {
110
+ for (const v of Object.values(value as Record<string, unknown>)) visit(v);
111
+ }
112
+ };
113
+ for (const block of page.blocks) visit(block.props);
114
+ return targets.size;
115
+ }
116
+
117
+ /**
118
+ * Score a page's substance. `docFreq`/`totalPages` come from the family baseline (buildTokenDocFreq);
119
+ * a token is "unique" when it appears in at most ceil(totalPages * 0.5) pages. `signalBlockIds` are
120
+ * block `type`s the Blueprint marks as substance-bearing; when omitted, any block with a non-empty
121
+ * `lead`/`body` counts as a signal.
122
+ */
123
+ export function scoreSubstance(
124
+ page: PageEntry,
125
+ ctx: { docFreq: Map<string, number>; totalPages: number; signalBlockIds?: string[] },
126
+ ): SubstanceScore {
127
+ const independentBlocks = page.blocks.length;
128
+
129
+ const tokens = tokenize(pageText(page));
130
+ const distinct = new Set(tokens);
131
+ const uniqueThreshold = Math.max(1, Math.ceil(ctx.totalPages * 0.5));
132
+ let uniqueCount = 0;
133
+ for (const token of distinct) {
134
+ if ((ctx.docFreq.get(token) ?? 0) <= uniqueThreshold) uniqueCount += 1;
135
+ }
136
+ const uniqueTokenRatio = distinct.size === 0 ? 0 : uniqueCount / distinct.size;
137
+
138
+ const signalSet = ctx.signalBlockIds ? new Set(ctx.signalBlockIds) : null;
139
+ let signalBlocks = 0;
140
+ for (const block of page.blocks) {
141
+ const props = (block.props ?? {}) as Record<string, unknown>;
142
+ const isSignal = signalSet
143
+ ? signalSet.has(block.type ?? block.use ?? "")
144
+ : collectVisibleText(props).join(" ").length > 40;
145
+ if (isSignal) signalBlocks += 1;
146
+ }
147
+
148
+ const linkDiversity = countLinkTargets(page);
149
+
150
+ const value = Math.round(
151
+ Math.min(100, independentBlocks * 12) * 0.3 +
152
+ uniqueTokenRatio * 100 * 0.4 +
153
+ Math.min(100, signalBlocks * 18) * 0.2 +
154
+ Math.min(100, linkDiversity * 20) * 0.1,
155
+ );
156
+
157
+ return {
158
+ value,
159
+ components: { independentBlocks, uniqueTokenRatio, signalBlocks, linkDiversity },
160
+ };
161
+ }
@@ -0,0 +1,137 @@
1
+ import { test, expect } from "vitest";
2
+ import fc from "fast-check";
3
+ import {
4
+ normalizeSegment,
5
+ matchesRecord,
6
+ countMatching,
7
+ buildRecordIndex,
8
+ countMatchingIndexed,
9
+ pathKey,
10
+ enumerateCandidateTuples,
11
+ buildEligibilityMatrix,
12
+ type AxisFieldMap,
13
+ } from "../eligibility.ts";
14
+ import type { SurfaceAxis, SurfaceRecord, EligibilityPolicy } from "../types.ts";
15
+
16
+ const SEGMENT_PATTERN = /^[a-z0-9-]+$/;
17
+
18
+ const defaultPolicy: EligibilityPolicy = {
19
+ minRecordsPerDepth: { 0: 1, 1: 1, 2: 1 },
20
+ noindexBelowPerDepth: {},
21
+ redirectPolicy: "nearest-ancestor",
22
+ trailingSlash: true,
23
+ segmentPattern: SEGMENT_PATTERN,
24
+ };
25
+
26
+ test("PBT: normalizeSegment is idempotent", () => {
27
+ fc.assert(
28
+ fc.property(
29
+ fc.stringMatching(SEGMENT_PATTERN).map((s) => s.replace(/_/g, "-")),
30
+ (s) => {
31
+ const once = normalizeSegment(s, SEGMENT_PATTERN);
32
+ const twice = normalizeSegment(once, SEGMENT_PATTERN);
33
+ expect(twice).toBe(once);
34
+ },
35
+ ),
36
+ );
37
+ });
38
+
39
+ test("PBT: countMatchingIndexed matches countMatching for any tuple", () => {
40
+ const _axes: SurfaceAxis[] = [
41
+ { id: "trade", universe: ["elektriker", "friseur", "baker"] },
42
+ { id: "region", universe: ["berlin", "hamburg", "munich"] },
43
+ ];
44
+ const axisFieldMap: AxisFieldMap = { trade: "trade", region: "region" };
45
+ const records: SurfaceRecord[] = [
46
+ { trade: "elektriker", region: "berlin", status: "active" },
47
+ { trade: "elektriker", region: "hamburg", status: "active" },
48
+ { trade: "friseur", region: "berlin", status: "active" },
49
+ { trade: "friseur", region: "hamburg", status: "archived" },
50
+ { trade: "baker", region: "munich", status: "active" },
51
+ ];
52
+ const index = buildRecordIndex(records, axisFieldMap);
53
+
54
+ const tupleArb = fc.record({
55
+ trade: fc.constantFrom("elektriker", "friseur", "baker", undefined),
56
+ region: fc.constantFrom("berlin", "hamburg", "munich", undefined),
57
+ });
58
+
59
+ fc.assert(
60
+ fc.property(tupleArb, (tuple) => {
61
+ const linear = countMatching(records, tuple, axisFieldMap);
62
+ const indexed = countMatchingIndexed(tuple, axisFieldMap, index);
63
+ expect(indexed).toBe(linear);
64
+ }),
65
+ );
66
+ });
67
+
68
+ test("PBT: pathKey is deterministic for the same input", () => {
69
+ const axisOrder = ["a", "b", "c"];
70
+ const tupleArb = fc.record({
71
+ a: fc.constantFrom("x", "y", undefined),
72
+ b: fc.constantFrom("z", "w", undefined),
73
+ c: fc.constantFrom("q", "r", undefined),
74
+ });
75
+ const depthArb = fc.integer({ min: 0, max: 3 });
76
+
77
+ fc.assert(
78
+ fc.property(tupleArb, depthArb, (tuple, depth) => {
79
+ const k1 = pathKey(depth, tuple, axisOrder);
80
+ const k2 = pathKey(depth, tuple, axisOrder);
81
+ expect(k1).toBe(k2);
82
+ }),
83
+ );
84
+ });
85
+
86
+ test("PBT: enumerateCandidateTuples count equals product of universe sizes", () => {
87
+ const universeArb = fc.array(fc.stringMatching(SEGMENT_PATTERN), { minLength: 1, maxLength: 5 });
88
+ const axesArb = fc.array(
89
+ fc.record({ id: fc.stringMatching(SEGMENT_PATTERN), universe: universeArb }),
90
+ { minLength: 1, maxLength: 3 },
91
+ );
92
+
93
+ fc.assert(
94
+ fc.property(axesArb, (axes) => {
95
+ const depth = axes.length;
96
+ const tuples = [...enumerateCandidateTuples(axes, depth)];
97
+ const expected = axes.reduce((acc, a) => acc * a.universe.length, 1);
98
+ expect(tuples).toHaveLength(expected);
99
+ }),
100
+ );
101
+ });
102
+
103
+ test("PBT: buildEligibilityMatrix entries are ordered by depth", () => {
104
+ const axes: SurfaceAxis[] = [
105
+ { id: "trade", universe: ["elektriker", "friseur"] },
106
+ { id: "region", universe: ["berlin", "hamburg"] },
107
+ ];
108
+ const axisFieldMap: AxisFieldMap = { trade: "trade", region: "region" };
109
+ const records: SurfaceRecord[] = [
110
+ { trade: "elektriker", region: "berlin", status: "active" },
111
+ { trade: "friseur", region: "hamburg", status: "active" },
112
+ ];
113
+
114
+ fc.assert(
115
+ fc.property(fc.boolean(), (forceGate) => {
116
+ const matrix = buildEligibilityMatrix(axes, axisFieldMap, records, defaultPolicy, {
117
+ forceNonIndexableDepths: forceGate ? [2] : [],
118
+ });
119
+ for (let i = 1; i < matrix.entries.length; i++) {
120
+ expect(matrix.entries[i]!.depth).toBeGreaterThanOrEqual(matrix.entries[i - 1]!.depth);
121
+ }
122
+ }),
123
+ );
124
+ });
125
+
126
+ test("PBT: matchesRecord with empty tuple always returns true", () => {
127
+ const recordArb: fc.Arbitrary<SurfaceRecord> = fc.record({
128
+ field: fc.string(),
129
+ status: fc.constantFrom("active", "archived"),
130
+ });
131
+
132
+ fc.assert(
133
+ fc.property(recordArb, (record) => {
134
+ expect(matchesRecord(record, {}, {})).toBe(true);
135
+ }),
136
+ );
137
+ });