@warpgogol/werkstatt-shared 0.14.1 → 0.15.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 (438) hide show
  1. package/README.md +23 -15
  2. package/README.uk.md +1 -1
  3. package/package.json +517 -766
  4. package/src/{share/agent → agent}/ard-catalog.ts +6 -1
  5. package/src/{share/agent → agent}/dns-aid.test.ts +2 -2
  6. package/src/{share/agent → agent}/manifest.ts +15 -1
  7. package/src/{share/agent → agent}/search.ts +6 -1
  8. package/src/{share → agent}/tests/api-catalog.test.ts +2 -2
  9. package/src/{share → agent}/tests/ard-catalog.test.ts +2 -2
  10. package/src/{share → agent}/tests/capability.test.ts +1 -1
  11. package/src/{share → agent}/tests/fleet-catalog.test.ts +1 -1
  12. package/src/{share → agent}/tests/knowledge.test.ts +2 -2
  13. package/src/{share → agent}/tests/manifest.test.ts +1 -1
  14. package/src/{share → agent}/tests/mcp-card.test.ts +2 -2
  15. package/src/{share → agent}/tests/openapi.test.ts +2 -2
  16. package/src/{share → agent}/tests/proof.test.ts +1 -1
  17. package/src/{share → attribution}/material-credits.ts +4 -4
  18. package/src/{share → checks}/check-hints.ts +6 -1
  19. package/src/checks/index.ts +4 -1
  20. package/src/checks/lib/astro-site-url.ts +6 -1
  21. package/src/checks/lib/i18n.ts +14 -0
  22. package/src/checks/result-helpers.ts +2 -2
  23. package/src/checks/tests/remediation-auto-populate.test.ts +1 -1
  24. package/src/{share → client-scripts}/counter-utils.ts +6 -2
  25. package/src/{share/scripts → client-scripts}/external-link-qr.ts +11 -16
  26. package/src/{share/scripts → client-scripts}/external-links.ts +12 -1
  27. package/src/{share/scripts → client-scripts}/gsap-counter.ts +8 -3
  28. package/src/client-scripts/index.ts +35 -0
  29. package/src/{share/scripts → client-scripts}/inline-number-animation.ts +1 -1
  30. package/src/{share/scripts → client-scripts}/lenis.ts +6 -1
  31. package/src/{share/scripts → client-scripts}/lordicon.ts +6 -1
  32. package/src/{share/scripts → client-scripts}/orchestrator.ts +10 -1
  33. package/src/{share/scripts → client-scripts}/scheduler.ts +6 -1
  34. package/src/client-scripts/scroll-spy.ts +106 -0
  35. package/src/client-scripts/tests/orchestrator.test.ts +47 -0
  36. package/src/client-scripts/tests/scroll-spy.test.ts +204 -0
  37. package/src/{share/scripts → client-scripts/tests}/video-player.test.ts +51 -31
  38. package/src/component/contracts.ts +206 -0
  39. package/src/component/index.ts +11 -0
  40. package/src/{share → content}/content-reference.ts +3 -3
  41. package/src/{share/content → content}/entity-id.ts +6 -3
  42. package/src/content/index.ts +3 -0
  43. package/src/{share/content → content}/merge.ts +6 -1
  44. package/src/content/system-manifest.test.ts +107 -0
  45. package/src/content/system-manifest.ts +12 -94
  46. package/src/{share → content}/tests/resolve-field-path.test.ts +1 -1
  47. package/src/{share → content}/tests/substitute-deep.test.ts +1 -1
  48. package/src/content-discipline/index.ts +19 -0
  49. package/src/{share/content-discipline → content-discipline}/parsers.ts +2 -2
  50. package/src/{share/env.d.ts → env.d.ts} +6 -3
  51. package/src/fingerprint/canonical-json.ts +731 -0
  52. package/src/fingerprint/index.ts +12 -0
  53. package/src/fingerprint/primitives.ts +72 -0
  54. package/src/{share/i18n → i18n}/localization.ts +6 -2
  55. package/src/integration/adapters.ts +10 -71
  56. package/src/integration/dispatch.ts +1 -1
  57. package/src/integration/funnel.ts +6 -1
  58. package/src/integration/index.ts +101 -4
  59. package/src/integration/lagebild-destination-adapter.ts +108 -0
  60. package/src/integration/lagebild-ingress.ts +7 -12
  61. package/src/integration/orchestration.ts +11 -10
  62. package/src/integration/tests/deliver-event.test.ts +1 -1
  63. package/src/integration/tests/dispatch.test.ts +4 -4
  64. package/src/integration/tests/hub-runtime.test.ts +22 -14
  65. package/src/integration/vitest.config.ts +1 -0
  66. package/src/kernel/desired-state.ts +227 -0
  67. package/src/kernel/diagnostic.ts +289 -0
  68. package/src/kernel/fs-atomic.ts +131 -0
  69. package/src/kernel/index.ts +15 -0
  70. package/src/kernel/tests/fs-atomic.test.ts +150 -0
  71. package/src/kernel/tests/workspace-io.test.ts +187 -0
  72. package/src/kernel/types.ts +459 -0
  73. package/src/kernel/workspace-io.ts +248 -0
  74. package/src/{share → knowledge}/tests/claim.test.ts +1 -1
  75. package/src/{share → knowledge}/tests/derivation.test.ts +1 -1
  76. package/src/{share → knowledge}/tests/freshness.test.ts +1 -1
  77. package/src/{share → knowledge}/tests/ledger.test.ts +1 -1
  78. package/src/{share → knowledge}/tests/plan.test.ts +1 -1
  79. package/src/{share → knowledge}/tests/source.test.ts +1 -1
  80. package/src/legal/index.ts +15 -0
  81. package/src/{share/middleware → middleware}/access-protection.ts +8 -8
  82. package/src/{share → node}/dev-props-validator.ts +6 -1
  83. package/src/{share → node}/import-scan.ts +23 -3
  84. package/src/{share → node}/semantic/derived-prices-loader.ts +4 -2
  85. package/src/{share → node}/semantic/markdown-twin-provenance.ts +1 -1
  86. package/src/{share/semantic → node}/tests/derived-prices-loader.test.ts +14 -1
  87. package/src/{share/semantic → node}/tests/markdown-twin-provenance.test.ts +1 -1
  88. package/src/observability/env-resolver.ts +6 -1
  89. package/src/observability/index.ts +6 -1
  90. package/src/observability/otlp-converter.ts +6 -1
  91. package/src/observability/otlp-transport.ts +6 -1
  92. package/src/observability/pusher.ts +6 -1
  93. package/src/observability/redact.ts +6 -1
  94. package/src/observability/typed-refs.ts +6 -2
  95. package/src/observability/vitest.config.ts +1 -0
  96. package/src/{share → offers}/formula-eval.ts +3 -3
  97. package/src/{share → offers}/tests/formula-eval.test.ts +2 -2
  98. package/src/onboarding/index.ts +1 -0
  99. package/src/{share → onboarding}/tests/onboarding-yaml.test.ts +1 -1
  100. package/src/ontology/archetype-registry.ts +6 -1
  101. package/src/ontology/archetypes/index.json +33 -1
  102. package/src/ontology/archetypes/index.yaml +27 -1
  103. package/src/ontology/archetypes/sections/entity-grid.yaml +46 -0
  104. package/src/ontology/archetypes/sections/exit-diagram.yaml +43 -0
  105. package/src/ontology/biome-token-projection.ts +6 -1
  106. package/src/ontology/cosmic/index.ts +6 -1
  107. package/src/ontology/cosmic/moon-catalog.ts +6 -1
  108. package/src/ontology/cosmic/planet-catalog.ts +6 -1
  109. package/src/ontology/cosmic/star-catalog.ts +6 -1
  110. package/src/ontology/enums.ts +6 -1
  111. package/src/ontology/external-surfaces/index.ts +1 -1
  112. package/src/ontology/index.ts +6 -2
  113. package/src/ontology/manifest.ts +7 -4
  114. package/src/ontology/operations/artifact-store.ts +45 -0
  115. package/src/ontology/operations/dht.ts +98 -0
  116. package/src/ontology/operations/handoff.ts +92 -0
  117. package/src/ontology/operations/index.ts +187 -1
  118. package/src/ontology/operations/leitstand.ts +99 -0
  119. package/src/ontology/operations/materialization.ts +90 -0
  120. package/src/ontology/operations/mission.ts +111 -0
  121. package/src/ontology/operations/naming-policy.ts +132 -0
  122. package/src/ontology/operations/notausgang.ts +64 -0
  123. package/src/ontology/operations/release.ts +121 -0
  124. package/src/ontology/operations/sternsystem.ts +192 -0
  125. package/src/ontology/operations/werkstatt.ts +48 -0
  126. package/src/ontology/schemas/biome.ts +7 -2
  127. package/src/ontology/schemas/capability.ts +1 -1
  128. package/src/ontology/schemas/constellation.ts +6 -1
  129. package/src/ontology/schemas/index.ts +6 -2
  130. package/src/ontology/schemas/manifest-resolver.ts +6 -1
  131. package/src/ontology/schemas/page-entry.ts +9 -5
  132. package/src/ontology/schemas/system/growth.ts +6 -1
  133. package/src/ontology/schemas/system/manifest.ts +40 -1
  134. package/src/ontology/schemas/system/page-output.ts +7 -6
  135. package/src/ontology/schemas/system/text.ts +15 -0
  136. package/src/ontology/schemas/system.ts +6 -2
  137. package/src/ontology/shared-section-props/body-fragments.ts +2 -0
  138. package/src/ontology/tests/sternsystem-owner.test.ts +1 -1
  139. package/src/ontology/vitest.config.ts +1 -0
  140. package/src/{share → page}/page.ts +13 -9
  141. package/src/{share → page}/tests/dev-props-validator.test.ts +1 -1
  142. package/src/{share → page}/tests/hero-section-numbering-parity.test.ts +1 -1
  143. package/src/passport/index.ts +6 -1
  144. package/src/passport/key-rotate.ts +10 -2
  145. package/src/passport/schema.ts +6 -1
  146. package/src/passport/sign.ts +8 -3
  147. package/src/passport/vitest.config.ts +1 -0
  148. package/src/pbt/index.test.ts +95 -0
  149. package/src/pbt/index.ts +251 -0
  150. package/src/plugin/plugin-contract.ts +1 -1
  151. package/src/{share → policy}/entitlement.ts +24 -4
  152. package/src/{share → policy}/feature-policy.ts +8 -3
  153. package/src/{share → policy}/visibility.ts +7 -2
  154. package/src/redirects/redirects.ts +117 -0
  155. package/src/{share → redirects/tests}/redirects.test.ts +1 -1
  156. package/src/remediation/remediation-catalog.ts +316 -0
  157. package/src/{share/routes → routes}/template-filter.ts +1 -1
  158. package/src/{share → runtime}/runtime-context.ts +7 -2
  159. package/src/{share → runtime}/shared-context.ts +1 -1
  160. package/src/{share/schemas → schemas}/claims.ts +2 -2
  161. package/src/{share/schemas → schemas}/effects.ts +6 -1
  162. package/src/{share/schemas → schemas}/features.ts +1 -1
  163. package/src/{share/schemas → schemas}/index.ts +3 -3
  164. package/src/{share/schemas → schemas}/navigation.ts +6 -1
  165. package/src/{share/schemas → schemas}/page-base.ts +6 -2
  166. package/src/{share/schemas → schemas}/person.ts +1 -1
  167. package/src/{share/schemas → schemas}/standard-list-item.ts +1 -1
  168. package/src/{share → sections}/rfc0042-utils.ts +1 -1
  169. package/src/{share/semantic → semantic}/block-extractors/index.ts +20 -1
  170. package/src/{share/semantic → semantic}/business-projection.ts +95 -1
  171. package/src/semantic/canonical-uri.ts +54 -0
  172. package/src/{share/semantic → semantic}/extract.ts +100 -1
  173. package/src/semantic/fact-extraction.test.ts +47 -0
  174. package/src/semantic/fact-extraction.ts +46 -0
  175. package/src/semantic/freshness.ts +67 -0
  176. package/src/{share/semantic → semantic}/ids.ts +6 -1
  177. package/src/{share/semantic → semantic}/index.ts +9 -2
  178. package/src/{share/semantic → semantic}/jsonld/breadcrumb.ts +6 -2
  179. package/src/{share/semantic → semantic}/jsonld/context.ts +6 -2
  180. package/src/{share/semantic → semantic}/jsonld/faq.ts +6 -2
  181. package/src/{share/semantic → semantic}/jsonld/initiative.ts +6 -1
  182. package/src/{share/semantic → semantic}/jsonld/organization.ts +6 -1
  183. package/src/{share/semantic → semantic}/jsonld/person.ts +6 -2
  184. package/src/{share/semantic → semantic}/jsonld/service.ts +6 -2
  185. package/src/semantic/jsonld/shared.ts +36 -0
  186. package/src/semantic/jsonld/types.ts +24 -0
  187. package/src/{share/semantic → semantic}/jsonld/webpage.ts +6 -1
  188. package/src/semantic/jsonld/website.ts +32 -0
  189. package/src/{share/semantic → semantic}/jsonld.ts +6 -1
  190. package/src/{share/semantic → semantic}/llms.ts +41 -3
  191. package/src/{share/semantic → semantic}/models.ts +26 -38
  192. package/src/{share/semantic → semantic}/organization-profile.ts +3 -0
  193. package/src/{share/semantic → semantic}/page-builders/markdown-page.ts +6 -3
  194. package/src/{share/semantic → semantic}/page-utils.ts +6 -3
  195. package/src/{share/tests/breadcrumbs.test.ts → semantic/tests/breadcrumbs-0229.test.ts} +1 -1
  196. package/src/{share → semantic}/tests/build-page-price-markers.test.ts +2 -2
  197. package/src/{share/semantic → semantic}/tests/business-projection.test.ts +179 -0
  198. package/src/semantic/tests/canonical-uri.test.ts +56 -0
  199. package/src/{share/semantic → semantic}/tests/extract.test.ts +83 -0
  200. package/src/semantic/tests/freshness.pbt.test.ts +108 -0
  201. package/src/{share/tests/image-sitemap.test.ts → semantic/tests/image-sitemap-0150.test.ts} +1 -1
  202. package/src/{share → semantic}/tests/jsonld-service.test.ts +2 -2
  203. package/src/{share → semantic}/tests/jsonld-video.test.ts +3 -3
  204. package/src/{share → semantic}/tests/jsonld-webpage.test.ts +3 -3
  205. package/src/{share → semantic}/tests/llms-0789.test.ts +2 -2
  206. package/src/{share/semantic → semantic}/tests/llms.test.ts +46 -0
  207. package/src/{share → semantic}/tests/organization-jsonld.test.ts +3 -3
  208. package/src/{share/tests/output-projection.test.ts → semantic/tests/output-projection-0143.test.ts} +1 -1
  209. package/src/{share/tests/price-marker-resolver.test.ts → semantic/tests/price-marker-resolver-0767.test.ts} +2 -2
  210. package/src/{share/semantic → semantic}/tests/price-marker-resolver.test.ts +4 -2
  211. package/src/semantic/tests/project-claims.pbt.test.ts +60 -0
  212. package/src/{share/semantic → semantic}/tests/split-sentences.test.ts +1 -1
  213. package/src/{share → semantic}/tests/twin-path.test.ts +1 -1
  214. package/src/signing/index.ts +13 -0
  215. package/src/signing/key.ts +139 -0
  216. package/src/signing/sign.ts +66 -0
  217. package/src/signing/types.ts +29 -0
  218. package/src/{share/slug → slug}/slug-url.ts +4 -1
  219. package/src/stack/run-tool.ts +108 -0
  220. package/src/stack/stack-checks.ts +124 -0
  221. package/src/stack/tests/run-tool.test.ts +138 -0
  222. package/src/stack/tests/stack-checks.test.ts +141 -0
  223. package/src/stack/tests/walk-files.test.ts +131 -0
  224. package/src/stack/walk-files.ts +114 -0
  225. package/src/surface/blueprint.ts +342 -66
  226. package/src/surface/decision-composer.ts +6 -1
  227. package/src/surface/geo.ts +6 -1
  228. package/src/surface/index.ts +11 -7
  229. package/src/surface/types.ts +2 -2
  230. package/src/surface/vitest.config.ts +1 -0
  231. package/src/tests/signing-core.test.ts +129 -0
  232. package/src/{share → text}/css-value-normalize.ts +6 -1
  233. package/src/text/string-utils.ts +24 -0
  234. package/src/{share → text}/tests/text-normalize.test.ts +5 -0
  235. package/src/{share → text}/text-normalize.ts +4 -3
  236. package/src/{share → text}/wrap-inline-numbers.ts +1 -1
  237. package/src/types/axiom-study.d.ts +36 -0
  238. package/src/types/hls-js-light.d.ts +21 -0
  239. package/src/types/qrcode-browser.d.ts +23 -0
  240. package/src/typography/fix.pbt.test.ts +208 -0
  241. package/src/typography/fix.ts +148 -0
  242. package/src/typography/index.ts +54 -0
  243. package/src/typography/locale-defaults.ts +97 -0
  244. package/src/typography/rules-tier1.test.ts +459 -0
  245. package/src/typography/rules-tier1.ts +925 -0
  246. package/src/typography/rules-tier2-locale.pbt.test.ts +190 -0
  247. package/src/typography/rules-tier2-locale.test.ts +286 -0
  248. package/src/typography/rules-tier2-locale.ts +399 -0
  249. package/src/typography/rules-tier2-structure.test.ts +330 -0
  250. package/src/typography/rules-tier2-structure.ts +378 -0
  251. package/src/typography/rules-tier3-advisory.test.ts +290 -0
  252. package/src/typography/rules-tier3-advisory.ts +239 -0
  253. package/src/typography/text-surface.test.ts +244 -0
  254. package/src/typography/text-surface.ts +448 -0
  255. package/src/index.ts +0 -14
  256. package/src/integration/port-barrel.ts +0 -105
  257. package/src/share/agent/tests/api-catalog.test.ts +0 -8
  258. package/src/share/agent/tests/ard-catalog.test.ts +0 -8
  259. package/src/share/agent/tests/capability.test.ts +0 -14
  260. package/src/share/agent/tests/fleet-catalog.test.ts +0 -15
  261. package/src/share/agent/tests/knowledge.test.ts +0 -20
  262. package/src/share/agent/tests/manifest.test.ts +0 -9
  263. package/src/share/agent/tests/mcp-card.test.ts +0 -8
  264. package/src/share/agent/tests/openapi.test.ts +0 -8
  265. package/src/share/agent/tests/proof.test.ts +0 -15
  266. package/src/share/content/index.ts +0 -16
  267. package/src/share/content-discipline/index.ts +0 -14
  268. package/src/share/index.ts +0 -86
  269. package/src/share/knowledge/tests/claim.test.ts +0 -11
  270. package/src/share/knowledge/tests/derivation.test.ts +0 -30
  271. package/src/share/knowledge/tests/freshness.test.ts +0 -18
  272. package/src/share/knowledge/tests/ledger.test.ts +0 -35
  273. package/src/share/knowledge/tests/plan.test.ts +0 -19
  274. package/src/share/knowledge/tests/source.test.ts +0 -19
  275. package/src/share/legal/index.ts +0 -1
  276. package/src/share/redirects.ts +0 -54
  277. package/src/share/remediation/remediation-catalog.ts +0 -196
  278. package/src/share/scripts/index.ts +0 -26
  279. package/src/share/scripts/tests/orchestrator.test.ts +0 -8
  280. package/src/share/semantic/jsonld/shared.ts +0 -31
  281. package/src/share/semantic/jsonld/types.ts +0 -19
  282. package/src/share/semantic/jsonld/website.ts +0 -27
  283. package/src/share/string-utils.ts +0 -19
  284. package/src/share/types/axiom-study.d.ts +0 -22
  285. package/src/share/types/hls-js-light.d.ts +0 -16
  286. package/src/share/types/qrcode-browser.d.ts +0 -18
  287. package/src/share/utility-registry.yaml +0 -50
  288. package/src/share/vitest.config.ts +0 -8
  289. package/src/surface/blueprint-schema.ts +0 -314
  290. package/src/surface/blueprint-types.ts +0 -256
  291. /package/src/{share/agent → agent}/api-catalog.ts +0 -0
  292. /package/src/{share/agent → agent}/capability.ts +0 -0
  293. /package/src/{share/agent → agent}/dns-aid.ts +0 -0
  294. /package/src/{share/agent → agent}/fleet-catalog.ts +0 -0
  295. /package/src/{share/agent → agent}/index.ts +0 -0
  296. /package/src/{share/agent → agent}/knowledge.ts +0 -0
  297. /package/src/{share/agent → agent}/mcp-card.ts +0 -0
  298. /package/src/{share/agent → agent}/omit-empty.ts +0 -0
  299. /package/src/{share/agent → agent}/openapi.ts +0 -0
  300. /package/src/{share/agent → agent}/proof.ts +0 -0
  301. /package/src/{share/agent → agent}/search.test.ts +0 -0
  302. /package/src/{share/agent → agent}/tests/omit-empty.test.ts +0 -0
  303. /package/src/{share → attribution}/attribution-display.ts +0 -0
  304. /package/src/{share/scripts → client-scripts}/gsap-mountain-journey.ts +0 -0
  305. /package/src/{share/scripts → client-scripts}/gsap-parallax.ts +0 -0
  306. /package/src/{share/scripts → client-scripts}/gsap-reveal.ts +0 -0
  307. /package/src/{share/scripts → client-scripts}/gsap-stagger.ts +0 -0
  308. /package/src/{share/scripts → client-scripts}/live-photos.ts +0 -0
  309. /package/src/{share/scripts → client-scripts}/tests/external-link-qr.test.ts +0 -0
  310. /package/src/{share/scripts → client-scripts}/tests/external-links.test.ts +0 -0
  311. /package/src/{share/scripts → client-scripts}/tests/gsap-counter.test.ts +0 -0
  312. /package/src/{share/scripts → client-scripts}/tests/gsap-mountain-journey.test.ts +0 -0
  313. /package/src/{share/scripts → client-scripts}/tests/gsap-parallax.test.ts +0 -0
  314. /package/src/{share/scripts → client-scripts}/tests/gsap-reveal.test.ts +0 -0
  315. /package/src/{share/scripts → client-scripts}/tests/gsap-stagger.test.ts +0 -0
  316. /package/src/{share/scripts → client-scripts}/tests/inline-number-animation.test.ts +0 -0
  317. /package/src/{share/scripts → client-scripts}/tests/lenis.test.ts +0 -0
  318. /package/src/{share/scripts → client-scripts}/tests/live-photos.test.ts +0 -0
  319. /package/src/{share/scripts → client-scripts}/tests/lordicon.test.ts +0 -0
  320. /package/src/{share/scripts → client-scripts}/tests/scheduler.test.ts +0 -0
  321. /package/src/{share/scripts → client-scripts}/video-player.ts +0 -0
  322. /package/src/{share/content → content}/resolve-field-path.ts +0 -0
  323. /package/src/{share/content → content}/substitute-deep.ts +0 -0
  324. /package/src/{share → content}/tests/content-ref-index.test.ts +0 -0
  325. /package/src/{share/content-discipline → content-discipline}/types.ts +0 -0
  326. /package/src/{share → image-provider}/image-provider.ts +0 -0
  327. /package/src/{share/knowledge → knowledge}/claim.ts +0 -0
  328. /package/src/{share/knowledge → knowledge}/derivation.ts +0 -0
  329. /package/src/{share/knowledge → knowledge}/freshness.ts +0 -0
  330. /package/src/{share/knowledge → knowledge}/index.ts +0 -0
  331. /package/src/{share/knowledge → knowledge}/ledger.ts +0 -0
  332. /package/src/{share/knowledge → knowledge}/plan.ts +0 -0
  333. /package/src/{share/knowledge → knowledge}/source.ts +0 -0
  334. /package/src/{share/legal → legal}/translation-policy.ts +0 -0
  335. /package/src/{share/middleware → middleware}/language-redirect.ts +0 -0
  336. /package/src/{share/middleware → middleware}/tests/access-protection.test.ts +0 -0
  337. /package/src/{share → node}/fs/index.ts +0 -0
  338. /package/src/{share/tests/markdown-twin-provenance.test.ts → node/tests/markdown-twin-provenance-0613.test.ts} +0 -0
  339. /package/src/{share → offers}/offer-capacity.ts +0 -0
  340. /package/src/{share/onboarding-yaml/index.ts → onboarding/yaml.ts} +0 -0
  341. /package/src/{share → ontology}/tests/ontology-role-by-cosmic-name.test.ts +0 -0
  342. /package/src/{share/routes → routes}/tests/template-filter.test.ts +0 -0
  343. /package/src/{share/schemas → schemas}/claim-records.ts +0 -0
  344. /package/src/{share/schemas → schemas}/horizontal-align.ts +0 -0
  345. /package/src/{share/schemas → schemas}/icon-color.ts +0 -0
  346. /package/src/{share/schemas → schemas}/live-photo.ts +0 -0
  347. /package/src/{share/schemas → schemas}/material-credit.ts +0 -0
  348. /package/src/{share/schemas → schemas}/media.ts +0 -0
  349. /package/src/{share/schemas → schemas}/participant.ts +0 -0
  350. /package/src/{share/schemas → schemas}/print.ts +0 -0
  351. /package/src/{share/schemas → schemas}/section-background.ts +0 -0
  352. /package/src/{share/schemas → schemas}/section-body.ts +0 -0
  353. /package/src/{share/schemas → schemas}/section-cards.ts +0 -0
  354. /package/src/{share/schemas → schemas}/section-cta.ts +0 -0
  355. /package/src/{share/schemas → schemas}/section-header.ts +0 -0
  356. /package/src/{share/schemas → schemas}/section-image.ts +0 -0
  357. /package/src/{share/schemas → schemas}/section-motion.ts +0 -0
  358. /package/src/{share/schemas → schemas}/section-shell.ts +0 -0
  359. /package/src/{share/schemas → schemas}/section-stats.ts +0 -0
  360. /package/src/{share/schemas → schemas}/site-background.ts +0 -0
  361. /package/src/{share/schemas → schemas}/tests/claim-records.test.ts +0 -0
  362. /package/src/{share/schemas → schemas}/tests/claims.test.ts +0 -0
  363. /package/src/{share/schemas → schemas}/tests/effects.test.ts +0 -0
  364. /package/src/{share/schemas → schemas}/tests/features.test.ts +0 -0
  365. /package/src/{share/schemas → schemas}/tests/horizontal-align.test.ts +0 -0
  366. /package/src/{share/schemas → schemas}/tests/icon-color.test.ts +0 -0
  367. /package/src/{share/schemas → schemas}/tests/live-photo.test.ts +0 -0
  368. /package/src/{share/schemas → schemas}/tests/material-credit.test.ts +0 -0
  369. /package/src/{share/schemas → schemas}/tests/media.test.ts +0 -0
  370. /package/src/{share/schemas → schemas}/tests/navigation.test.ts +0 -0
  371. /package/src/{share/schemas → schemas}/tests/page-base.test.ts +0 -0
  372. /package/src/{share/schemas → schemas}/tests/participant.test.ts +0 -0
  373. /package/src/{share/schemas → schemas}/tests/person.test.ts +0 -0
  374. /package/src/{share/schemas → schemas}/tests/print.test.ts +0 -0
  375. /package/src/{share/schemas → schemas}/tests/section-background.test.ts +0 -0
  376. /package/src/{share/schemas → schemas}/tests/section-body.test.ts +0 -0
  377. /package/src/{share/schemas → schemas}/tests/section-cards.test.ts +0 -0
  378. /package/src/{share/schemas → schemas}/tests/section-cta.test.ts +0 -0
  379. /package/src/{share/schemas → schemas}/tests/section-header.test.ts +0 -0
  380. /package/src/{share/schemas → schemas}/tests/section-image.test.ts +0 -0
  381. /package/src/{share/schemas → schemas}/tests/section-motion.test.ts +0 -0
  382. /package/src/{share/schemas → schemas}/tests/section-shell.test.ts +0 -0
  383. /package/src/{share/schemas → schemas}/tests/section-stats.test.ts +0 -0
  384. /package/src/{share/schemas → schemas}/tests/site-background.test.ts +0 -0
  385. /package/src/{share/schemas → schemas}/tests/standard-list-item.test.ts +0 -0
  386. /package/src/{share/semantic → semantic}/ai.ts +0 -0
  387. /package/src/{share/semantic → semantic}/block-extraction.ts +0 -0
  388. /package/src/{share/semantic → semantic}/breadcrumbs.ts +0 -0
  389. /package/src/{share/semantic → semantic}/build-page.ts +0 -0
  390. /package/src/{share/semantic → semantic}/feed.ts +0 -0
  391. /package/src/{share/semantic → semantic}/image-sitemap.ts +0 -0
  392. /package/src/{share/semantic → semantic}/jsonld/article.ts +0 -0
  393. /package/src/{share/semantic → semantic}/jsonld/collection-list.ts +0 -0
  394. /package/src/{share/semantic → semantic}/jsonld/tests/article.test.ts +0 -0
  395. /package/src/{share/semantic → semantic}/jsonld/tests/breadcrumb.test.ts +0 -0
  396. /package/src/{share/semantic → semantic}/jsonld/tests/collection-list.test.ts +0 -0
  397. /package/src/{share/semantic → semantic}/jsonld/tests/faq.test.ts +0 -0
  398. /package/src/{share/semantic → semantic}/jsonld/tests/initiative.test.ts +0 -0
  399. /package/src/{share/semantic → semantic}/jsonld/tests/organization.test.ts +0 -0
  400. /package/src/{share/semantic → semantic}/jsonld/tests/person.test.ts +0 -0
  401. /package/src/{share/semantic → semantic}/jsonld/tests/service.test.ts +0 -0
  402. /package/src/{share/semantic → semantic}/jsonld/tests/shared.test.ts +0 -0
  403. /package/src/{share/semantic → semantic}/jsonld/tests/video.test.ts +0 -0
  404. /package/src/{share/semantic → semantic}/jsonld/tests/webpage.test.ts +0 -0
  405. /package/src/{share/semantic → semantic}/jsonld/tests/website.test.ts +0 -0
  406. /package/src/{share/semantic → semantic}/jsonld/video.ts +0 -0
  407. /package/src/{share/semantic → semantic}/llms-policy.ts +0 -0
  408. /package/src/{share/semantic → semantic}/markdown-hygiene.ts +0 -0
  409. /package/src/{share/semantic → semantic}/output-projection.ts +0 -0
  410. /package/src/{share/semantic → semantic}/page-markdown.ts +0 -0
  411. /package/src/{share/semantic → semantic}/price-marker-resolver.ts +0 -0
  412. /package/src/{share/semantic → semantic}/robots.ts +0 -0
  413. /package/src/{share/semantic → semantic}/tests/ai.test.ts +0 -0
  414. /package/src/{share/semantic → semantic}/tests/block-extraction.test.ts +0 -0
  415. /package/src/{share/semantic → semantic}/tests/breadcrumbs.test.ts +0 -0
  416. /package/src/{share/semantic → semantic}/tests/build-page.test.ts +0 -0
  417. /package/src/{share/semantic → semantic}/tests/feed.test.ts +0 -0
  418. /package/src/{share/semantic → semantic}/tests/helpers.ts +0 -0
  419. /package/src/{share/semantic → semantic}/tests/ids.test.ts +0 -0
  420. /package/src/{share/semantic → semantic}/tests/image-sitemap.test.ts +0 -0
  421. /package/src/{share/semantic → semantic}/tests/jsonld.test.ts +0 -0
  422. /package/src/{share/semantic → semantic}/tests/llms-policy.test.ts +0 -0
  423. /package/src/{share/semantic → semantic}/tests/markdown-hygiene.test.ts +0 -0
  424. /package/src/{share/semantic → semantic}/tests/markdown-page.test.ts +0 -0
  425. /package/src/{share/semantic → semantic}/tests/organization-profile.test.ts +0 -0
  426. /package/src/{share/semantic → semantic}/tests/output-projection.test.ts +0 -0
  427. /package/src/{share/semantic → semantic}/tests/page-markdown.test.ts +0 -0
  428. /package/src/{share/semantic → semantic}/tests/page-utils.test.ts +0 -0
  429. /package/src/{share/semantic → semantic}/tests/robots.test.ts +0 -0
  430. /package/src/{share/semantic → semantic}/tests/update-stamp.test.ts +0 -0
  431. /package/src/{share/semantic → semantic}/update-stamp.ts +0 -0
  432. /package/src/{share/slug → slug}/heading-slugger.ts +0 -0
  433. /package/src/{share/slug → slug}/index.ts +0 -0
  434. /package/src/{share/slug → slug}/slug-id.ts +0 -0
  435. /package/src/{share/slug → slug}/strategies.ts +0 -0
  436. /package/src/{share/slug → slug}/tests/slug.test.ts +0 -0
  437. /package/src/{share → text}/tests/text-normalize.pbt.test.ts +0 -0
  438. /package/src/{share → text}/text-position.ts +0 -0
@@ -0,0 +1,131 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { mkdtemp, rm, mkdir, writeFile } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { tmpdir } from "node:os";
5
+ import {
6
+ walkFiles,
7
+ readTextFile,
8
+ readTextFiles,
9
+ readBinaryFiles,
10
+ } from "../walk-files.ts";
11
+
12
+ describe("walkFiles", () => {
13
+ let root: string;
14
+
15
+ beforeEach(async () => {
16
+ root = await mkdtemp(join(tmpdir(), "walk-files-"));
17
+ });
18
+
19
+ afterEach(async () => {
20
+ await rm(root, { recursive: true, force: true });
21
+ });
22
+
23
+ it("returns relative paths with forward slashes, recursively by default", async () => {
24
+ await mkdir(join(root, "a", "b"), { recursive: true });
25
+ await writeFile(join(root, "top.ts"), "");
26
+ await writeFile(join(root, "a", "mid.ts"), "");
27
+ await writeFile(join(root, "a", "b", "deep.ts"), "");
28
+
29
+ const files = await walkFiles(root);
30
+
31
+ expect(files.sort()).toEqual(["a/b/deep.ts", "a/mid.ts", "top.ts"]);
32
+ });
33
+
34
+ it("returns only top-level files when recursive is false", async () => {
35
+ await mkdir(join(root, "sub"), { recursive: true });
36
+ await writeFile(join(root, "top.ts"), "");
37
+ await writeFile(join(root, "sub", "nested.ts"), "");
38
+
39
+ const files = await walkFiles(root, { recursive: false });
40
+
41
+ expect(files).toEqual(["top.ts"]);
42
+ });
43
+
44
+ it("applies the filter to relative paths", async () => {
45
+ await mkdir(join(root, "sub"), { recursive: true });
46
+ await writeFile(join(root, "keep.ts"), "");
47
+ await writeFile(join(root, "skip.js"), "");
48
+ await writeFile(join(root, "sub", "keep.ts"), "");
49
+
50
+ const files = await walkFiles(root, { filter: (rel) => rel.endsWith(".ts") });
51
+
52
+ expect(files.sort()).toEqual(["keep.ts", "sub/keep.ts"]);
53
+ });
54
+
55
+ it("returns an empty array for a missing directory", async () => {
56
+ expect(await walkFiles(join(root, "nope"))).toEqual([]);
57
+ });
58
+
59
+ it("skips non-file entries", async () => {
60
+ await mkdir(join(root, "dir-only"), { recursive: true });
61
+ await writeFile(join(root, "file.ts"), "");
62
+
63
+ const files = await walkFiles(root);
64
+
65
+ expect(files).toEqual(["file.ts"]);
66
+ });
67
+ });
68
+
69
+ describe("readTextFile", () => {
70
+ let root: string;
71
+
72
+ beforeEach(async () => {
73
+ root = await mkdtemp(join(tmpdir(), "walk-read-"));
74
+ });
75
+
76
+ afterEach(async () => {
77
+ await rm(root, { recursive: true, force: true });
78
+ });
79
+
80
+ it("reads utf-8 content", async () => {
81
+ await writeFile(join(root, "a.txt"), "hello ünïcode");
82
+
83
+ expect(await readTextFile(join(root, "a.txt"))).toBe("hello ünïcode");
84
+ });
85
+
86
+ it("returns null for a missing file", async () => {
87
+ expect(await readTextFile(join(root, "missing.txt"))).toBeNull();
88
+ });
89
+ });
90
+
91
+ describe("readTextFiles / readBinaryFiles", () => {
92
+ let root: string;
93
+
94
+ beforeEach(async () => {
95
+ root = await mkdtemp(join(tmpdir(), "walk-reads-"));
96
+ });
97
+
98
+ afterEach(async () => {
99
+ await rm(root, { recursive: true, force: true });
100
+ });
101
+
102
+ it("reads multiple files keyed by relative path", async () => {
103
+ await mkdir(join(root, "sub"), { recursive: true });
104
+ await writeFile(join(root, "a.ts"), "aaa");
105
+ await writeFile(join(root, "sub", "b.ts"), "bbb");
106
+
107
+ const contents = await readTextFiles(root, ["a.ts", "sub/b.ts"]);
108
+
109
+ expect(contents.get("a.ts")).toBe("aaa");
110
+ expect(contents.get("sub/b.ts")).toBe("bbb");
111
+ expect(contents.size).toBe(2);
112
+ });
113
+
114
+ it("omits unreadable entries", async () => {
115
+ await writeFile(join(root, "a.ts"), "aaa");
116
+
117
+ const contents = await readTextFiles(root, ["a.ts", "missing.ts"]);
118
+
119
+ expect(contents.size).toBe(1);
120
+ expect(contents.has("missing.ts")).toBe(false);
121
+ });
122
+
123
+ it("reads binary content without utf-8 corruption", async () => {
124
+ const bytes = Buffer.from([0x00, 0xff, 0xfe, 0x42]);
125
+ await writeFile(join(root, "bin.dat"), bytes);
126
+
127
+ const contents = await readBinaryFiles(root, ["bin.dat"]);
128
+
129
+ expect(contents.get("bin.dat")).toEqual(bytes);
130
+ });
131
+ });
@@ -0,0 +1,114 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>walkFiles — the single file-discovery and file-reading seam for stack plugins
4
+ (RFC-1100). Returns workspace-relative paths with forward slashes and reads file
5
+ contents in bulk, so validators never import node:fs directly.</purpose>
6
+
7
+ <non-goals>
8
+ <item>Does not write files — writes flow through writeFileIfChanged / WorkspaceIO.</item>
9
+ <item>Does not apply implicit ignore rules (no dotfile or prefix skipping) — callers scope by directory and filter.</item>
10
+ <item>Does not run in the browser — server-only (Node fs/promises).</item>
11
+ </non-goals>
12
+ </MODULE_CONTRACT>
13
+ <CHANGE_SUMMARY>
14
+ <item>RFC-1100: initial shared walker — walkFiles plus readTextFile/readTextFiles/readBinaryFiles companions; replaces per-validator private readdir walkers in stack plugins.</item>
15
+ <item>RFC-1100: step 1 — shared tool/fs/check seams (walkFiles, runTool, defineStackChecks)</item>
16
+ </CHANGE_SUMMARY>
17
+ */
18
+
19
+ // Server-only. Do not import from browser/client scripts.
20
+
21
+ import { readdir, readFile } from "node:fs/promises";
22
+ import { join } from "node:path";
23
+
24
+ export interface WalkFilesOptions {
25
+ /** Recurse into subdirectories. Default true. */
26
+ recursive?: boolean;
27
+ /** Return true to include a file by its directory-relative path (forward slashes). */
28
+ filter?: (relPath: string) => boolean;
29
+ }
30
+
31
+ /**
32
+ * Lists files under `dir` as relative paths with forward slashes.
33
+ * Missing or unreadable directories yield an empty array.
34
+ */
35
+ export async function walkFiles(
36
+ dir: string,
37
+ options: WalkFilesOptions = {},
38
+ ): Promise<string[]> {
39
+ const { recursive = true, filter } = options;
40
+ const results: string[] = [];
41
+
42
+ async function walk(current: string, relPrefix: string): Promise<void> {
43
+ let entries;
44
+ try {
45
+ entries = await readdir(current, { withFileTypes: true });
46
+ } catch {
47
+ return;
48
+ }
49
+ for (const entry of entries) {
50
+ const relPath = relPrefix ? `${relPrefix}/${entry.name}` : entry.name;
51
+ if (entry.isDirectory()) {
52
+ if (recursive) {
53
+ await walk(join(current, entry.name), relPath);
54
+ }
55
+ continue;
56
+ }
57
+ if (!entry.isFile()) continue;
58
+ if (filter && !filter(relPath)) continue;
59
+ results.push(relPath);
60
+ }
61
+ }
62
+
63
+ await walk(dir, "");
64
+ return results;
65
+ }
66
+
67
+ /**
68
+ * Reads a single file as utf-8. Returns null when the file is missing or unreadable.
69
+ */
70
+ export async function readTextFile(path: string): Promise<string | null> {
71
+ try {
72
+ return await readFile(path, "utf-8");
73
+ } catch {
74
+ return null;
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Reads multiple files under `dir` as utf-8, keyed by their walkFiles-relative path.
80
+ * Unreadable entries are omitted from the result.
81
+ */
82
+ export async function readTextFiles(
83
+ dir: string,
84
+ relPaths: string[],
85
+ ): Promise<Map<string, string>> {
86
+ const contents = new Map<string, string>();
87
+ for (const relPath of relPaths) {
88
+ const content = await readTextFile(join(dir, relPath));
89
+ if (content !== null) {
90
+ contents.set(relPath, content);
91
+ }
92
+ }
93
+ return contents;
94
+ }
95
+
96
+ /**
97
+ * Reads multiple files under `dir` as raw buffers, keyed by their walkFiles-relative
98
+ * path. Use for byte-accurate work (hashing, gzip measurement) where utf-8 decoding
99
+ * would corrupt binary content. Unreadable entries are omitted from the result.
100
+ */
101
+ export async function readBinaryFiles(
102
+ dir: string,
103
+ relPaths: string[],
104
+ ): Promise<Map<string, Buffer>> {
105
+ const contents = new Map<string, Buffer>();
106
+ for (const relPath of relPaths) {
107
+ try {
108
+ contents.set(relPath, await readFile(join(dir, relPath)));
109
+ } catch {
110
+ // Skip unreadable files — same tolerance as the walkers this replaces.
111
+ }
112
+ }
113
+ return contents;
114
+ }
@@ -12,11 +12,14 @@
12
12
  </non-goals>
13
13
  </MODULE_CONTRACT>
14
14
  <CHANGE_SUMMARY>
15
- <item>RFC-0192: Blueprint type + entry assembly (no block baking yet).</item>
16
15
  <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
16
  <item>RFC-0496: add BlueprintServiceConfig + ServicePublicationGate for website-service depth-1 service dossier configuration; add BlueprintLinkingParent for cross-surface parent linking.</item>
18
17
  <item>RFC-0497: add BlueprintIntersectionConfig + IntersectionGate + IntersectionSimilarity for website-local depth-5 intersection gate configuration.</item>
19
18
  <item>RFC-0500: add BlueprintHubConfig for depth-0 editorial knowledge hub configuration; add BlueprintStatusGate for record status filtering.</item>
19
+ <item>RFC-1106: step 5 — merge blueprint triplet
20
+
21
+ surface/blueprint.ts now holds the blueprintSchema (sole declaration), all ~30 contract type names derived via z.infer, parseBlueprint, and the pure helpers. Deleted satellites blueprint-types.ts + blueprint-schema.ts, their package.json export entries, and the zero-consumer site shims (domain/surface/blueprint{,-types,-schema}.ts + 2 load-verification tests). All barrel consumers unchanged.</item>
22
+ <history>RFC-0192</history>
20
23
  </CHANGE_SUMMARY>
21
24
  */
22
25
 
@@ -38,71 +41,344 @@ import type {
38
41
  VirtualRouteEntry,
39
42
  } from "./types.ts";
40
43
 
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
- };
44
+ import { z } from "zod";
45
+
46
+ // ---------------------------------------------------------------------------
47
+ // Blueprint schema — RFC-1106: the sole declaration of the Blueprint contract.
48
+ // All Blueprint types below derive from blueprintSchema via z.infer; the former
49
+ // blueprint-types.ts / blueprint-schema.ts satellites are merged here.
50
+ // ---------------------------------------------------------------------------
51
+
52
+ const localizedString = z.record(z.string(), z.string());
53
+
54
+ const intRecord = z.record(z.string(), z.number().int());
55
+
56
+ // RFC-0490: pillar-hub configuration for depth-0 hub pages.
57
+ const pillarCtaSchema = z.object({
58
+ label: localizedString,
59
+ target: z.string().min(1),
60
+ });
61
+
62
+ const pillarHeroSchema = z.object({
63
+ eyebrow: localizedString,
64
+ heading: localizedString,
65
+ lead: localizedString,
66
+ primaryCta: pillarCtaSchema,
67
+ secondaryCta: pillarCtaSchema,
68
+ });
69
+
70
+ const pillarAdaptationDimensionSchema = z.object({
71
+ heading: localizedString,
72
+ body: localizedString,
73
+ });
74
+
75
+ const pillarAdaptationSchema = z.object({
76
+ heading: localizedString,
77
+ dimensions: z.array(pillarAdaptationDimensionSchema).min(1),
78
+ });
79
+
80
+ const pillarProductPriceSchema = z.object({
81
+ heading: localizedString,
82
+ body: localizedString,
83
+ priceRef: z.string().min(1).optional(),
84
+ });
85
+
86
+ const pillarFinalCtaSchema = z.object({
87
+ heading: localizedString,
88
+ body: localizedString,
89
+ primaryCta: pillarCtaSchema,
90
+ secondaryCta: pillarCtaSchema,
91
+ });
92
+
93
+ const pillarSchema = z.object({
94
+ hero: pillarHeroSchema,
95
+ adaptation: pillarAdaptationSchema,
96
+ productPrice: pillarProductPriceSchema,
97
+ finalCta: pillarFinalCtaSchema,
98
+ catalogHeading: localizedString.optional(),
99
+ });
100
+
101
+ // RFC-0492: dossier configuration for depth-1 industry pages.
102
+ const industryPublicationGateSchema = z.object({
103
+ minServiceCategories: z.number().int().min(0),
104
+ minCustomerJourneys: z.number().int().min(0),
105
+ minTrustSignals: z.number().int().min(0),
106
+ minArchitectureEntries: z.number().int().min(0),
107
+ minModuleMappings: z.number().int().min(0),
108
+ minUniqueFaq: z.number().int().min(0),
109
+ });
110
+
111
+ const dossierSchema = z.object({
112
+ gate: industryPublicationGateSchema,
113
+ claimRestrictions: z.array(z.string().min(1)),
114
+ doorwayMaxFlaggedShare: z.number().min(0).max(1),
115
+ duplicateMaxSimilarity: z.number().min(0).max(1),
116
+ mode: z.enum(["warn", "fail"]),
117
+ });
118
+
119
+ // RFC-0496: service configuration for depth-1 service dossier pages.
120
+ const servicePublicationGateSchema = z.object({
121
+ minServiceVariants: z.number().int().min(0),
122
+ minCustomerQuestions: z.number().int().min(0),
123
+ minPriceModels: z.number().int().min(0),
124
+ minFaq: z.number().int().min(0),
125
+ minPageStructure: z.number().int().min(0),
126
+ });
127
+
128
+ const serviceSchema = z.object({
129
+ gate: servicePublicationGateSchema,
130
+ claimRestrictions: z.array(z.string().min(1)),
131
+ mode: z.enum(["warn", "fail"]),
132
+ });
133
+
134
+ const intersectionGateSchema = z.object({
135
+ minLocalServiceQuestions: z.number().int().min(0),
136
+ minScenarios: z.number().int().min(0),
137
+ minLocalEvidence: z.number().int().min(0),
138
+ minUniqueContentBlocks: z.number().int().min(0),
139
+ minUniqueFaq: z.number().int().min(0),
140
+ minSources: z.number().int().min(0),
141
+ });
142
+
143
+ const intersectionSimilaritySchema = z.object({
144
+ similarityToIndustryPage: z.number().min(0).max(1),
145
+ similarityToCityPage: z.number().min(0).max(1),
146
+ similarityToServicePage: z.number().min(0).max(1),
147
+ similarityToOtherIntersections: z.number().min(0).max(1),
148
+ });
149
+
150
+ const intersectionSchema = z.object({
151
+ gate: intersectionGateSchema,
152
+ similarity: intersectionSimilaritySchema,
153
+ substanceIndependenceThreshold: z.number().min(0).max(1),
154
+ mode: z.enum(["warn", "fail"]),
155
+ });
156
+
157
+ // RFC-0500: hub configuration for depth-0 editorial knowledge hubs (ratgeber).
158
+ const hubSchema = z.object({
159
+ cardFields: z.array(z.string().min(1)).min(1),
160
+ reservedSlugs: z.array(z.string().min(1)),
161
+ });
162
+
163
+ // RFC-0500: status gate — only records with allowed statuses are emitted as surface entries.
164
+ const statusGateSchema = z.object({
165
+ allowedStatuses: z.array(z.string().min(1)),
166
+ excludedStatuses: z.array(z.string().min(1)),
167
+ });
168
+
169
+ // RFC-0496: cross-surface parent linking.
170
+ const linkingParentSchema = z.object({
171
+ surface: z.string().min(1),
172
+ depth: z.number().int().min(0),
173
+ joinField: z.string().min(1),
174
+ });
175
+
176
+ // RFC-0325: static article metadata for a level with no per-record binding (depth-0 hubs).
177
+ const blueprintLevelArticleSchema = z.object({
178
+ publishedAt: z.string().min(1),
179
+ updatedAt: z.string().min(1).optional(),
180
+ author: z.string().min(1).optional(),
181
+ tags: z.array(z.string().min(1)).optional(),
182
+ });
183
+
184
+ const evidencePolicySchema = z.object({
185
+ approvedNarrative: z.enum(["required", "optional"]).optional(),
186
+ requiredRecordFields: z.array(z.string().min(1)).optional(),
187
+ preferredEvidenceSources: z.array(z.string().min(1)).optional(),
188
+ minTupleSpecificFacts: z.number().int().min(0).optional(),
189
+ minWerkEvidence: z.number().int().min(0).optional(),
190
+ existenceSource: z.enum(["records", "works"]).optional(),
191
+ freshness: z.enum(["valid-and-current", "valid"]).optional(),
192
+ duplicate: z
193
+ .object({
194
+ method: z.enum(["shingle", "simhash"]).optional(),
195
+ maxSimilarityWithinCluster: z.number().min(0).max(1).optional(),
196
+ })
197
+ .optional(),
198
+ leadImage: z.enum(["required", "warning", "optional"]).optional(),
199
+ mode: z.enum(["error", "warning"]).optional(),
200
+ });
201
+
202
+ const demandPolicySchema = z.object({
203
+ minVolume: z.number().min(0).optional(),
204
+ allowIntents: z
205
+ .array(z.enum(["informational", "commercial", "transactional", "navigational"]))
206
+ .optional(),
207
+ missing: z.enum(["noindex", "do-not-emit"]).optional(),
208
+ staleAfterDays: z.number().int().min(0).optional(),
209
+ });
210
+
211
+ const depthRolePolicySchema = z.object({
212
+ indexability: z.enum(["index", "navigation-noindex", "evidence-gated"]),
213
+ canonicalTarget: z.union([z.literal("tradeHub"), z.number().int().min(0)]).optional(),
214
+ follow: z.boolean().optional(),
215
+ includeInSitemap: z.boolean().optional(),
216
+ geo: z.enum(["full", "twin-only", "off"]).optional(),
217
+ localEvidence: z
218
+ .object({
219
+ minVerifiedFacts: z.number().int().min(0).optional(),
220
+ minCitySpecificQa: z.number().int().min(0).optional(),
221
+ minUniqueTokenShare: z.number().min(0).max(1).optional(),
222
+ maxBodySimilarityWithinBranch: z.number().min(0).max(1).optional(),
223
+ })
224
+ .optional(),
225
+ });
226
+
227
+ export const blueprintSchema = z.object({
228
+ id: z.string().min(1),
229
+ entitlement: z.string().min(1),
230
+ dataset: z.object({ collection: z.string().min(1), status: z.string().optional() }),
231
+ axes: z
232
+ .array(
233
+ z.object({
234
+ id: z.string().min(1),
235
+ universe: z.union([
236
+ z.object({ collection: z.string().min(1), field: z.string().min(1) }),
237
+ z.object({ provider: z.string().min(1) }),
238
+ ]),
239
+ match: z.object({ recordField: z.string().min(1) }),
240
+ }),
241
+ )
242
+ .min(1),
243
+ levels: z
244
+ .array(
245
+ z.object({
246
+ depth: z.number().int().min(0),
247
+ slug: localizedString,
248
+ redirectToPageId: z.string().min(1).optional(),
249
+ constellation: z.string().min(1),
250
+ geo: z.enum(["full", "twin-only", "off"]).optional(),
251
+ titleTemplate: localizedString.optional(),
252
+ descriptionTemplate: localizedString.optional(),
253
+ intro: localizedString.optional(),
254
+ semanticType: z.string().min(1).optional(),
255
+ article: blueprintLevelArticleSchema.optional(),
256
+ pillar: pillarSchema.optional(),
257
+ dossier: dossierSchema.optional(),
258
+ service: serviceSchema.optional(),
259
+ intersection: intersectionSchema.optional(),
260
+ hub: hubSchema.optional(),
261
+ }),
262
+ )
263
+ .min(1),
264
+ policy: z.object({
265
+ minRecordsPerDepth: intRecord,
266
+ noindexBelowPerDepth: intRecord.optional(),
267
+ redirectPolicy: z.enum(["nearest-ancestor", "root"]).optional(),
268
+ trailingSlash: z.boolean().optional(),
269
+ maxStubDepth: z.number().int().optional(),
270
+ substanceMin: z.number().min(0).max(100).optional(),
271
+ substanceMinPerDepth: intRecord.optional(),
272
+ evidencePerDepth: z.record(z.string(), evidencePolicySchema).optional(),
273
+ demandPerDepth: z.record(z.string(), demandPolicySchema).optional(),
274
+ depthRoles: z.record(z.string(), depthRolePolicySchema).optional(),
275
+ sitemapBudget: z.number().int().min(0).optional(),
276
+ maxThinShare: z.number().min(0).max(1).optional(),
277
+ regionalGateDepths: z.array(z.number().int().min(0)).optional(),
278
+ bake: z.enum(["inline", "lazy"]).optional(),
279
+ statusGate: statusGateSchema.optional(),
280
+ }),
281
+ linking: z
282
+ .object({
283
+ children: z.object({ limit: z.number().int() }).optional(),
284
+ siblings: z.object({ limit: z.number().int() }).optional(),
285
+ teasers: z
286
+ .object({
287
+ relevance: z.array(z.object({ sharedAxis: z.string(), weight: z.number() })).optional(),
288
+ })
289
+ .optional(),
290
+ parent: linkingParentSchema.optional(),
291
+ })
292
+ .optional(),
293
+ rotation: z.object({ variantsByTupleHash: z.boolean() }).optional(),
294
+ projection: z
295
+ .object({
296
+ title: localizedString.optional(),
297
+ description: z.union([localizedString, z.object({ ref: z.string() })]).optional(),
298
+ })
299
+ .optional(),
300
+ freshness: z
301
+ .object({
302
+ slaDaysPerDepth: intRecord,
303
+ field: z.string().min(1),
304
+ mode: z.enum(["any", "all", "median"]).optional(),
305
+ })
306
+ .optional(),
307
+ enrichedFields: z
308
+ .array(
309
+ z.object({
310
+ field: z.string().min(1),
311
+ promptId: z.string().min(1),
312
+ scopeDepth: z.number().int(),
313
+ maxTokens: z.number().int(),
314
+ // RFC-0207: output shape + generation granularity (both default to the original behavior).
315
+ kind: z.enum(["field", "narrative"]).optional(),
316
+ scope: z.enum(["tuple", "record"]).optional(),
317
+ axis: z.string().min(1).optional(),
318
+ }),
319
+ )
320
+ .optional(),
321
+ });
322
+
323
+ // ---------------------------------------------------------------------------
324
+ // Derived contract types — every name the deleted blueprint-types.ts exported,
325
+ // now inferred from the schema above.
326
+ // ---------------------------------------------------------------------------
327
+
328
+ /** A localized string map: lang → value. */
329
+ export type LocalizedString = z.infer<typeof localizedString>;
330
+
331
+ export type Blueprint = z.infer<typeof blueprintSchema>;
332
+ export type BlueprintAxis = Blueprint["axes"][number];
333
+ export type BlueprintLevel = Blueprint["levels"][number];
334
+ export type BlueprintPolicy = Blueprint["policy"];
335
+ export type BlueprintLinking = NonNullable<Blueprint["linking"]>;
336
+ export type BlueprintProjection = NonNullable<Blueprint["projection"]>;
337
+ export type EnrichedFieldSpec = NonNullable<Blueprint["enrichedFields"]>[number];
338
+
339
+ export type GeoDepth = NonNullable<BlueprintLevel["geo"]>;
340
+ export type BlueprintLevelArticle = NonNullable<BlueprintLevel["article"]>;
341
+ export type BlueprintPillar = NonNullable<BlueprintLevel["pillar"]>;
342
+ export type BlueprintPillarHero = BlueprintPillar["hero"];
343
+ export type BlueprintPillarAdaptation = BlueprintPillar["adaptation"];
344
+ export type BlueprintPillarAdaptationDimension = BlueprintPillarAdaptation["dimensions"][number];
345
+ export type BlueprintPillarProductPrice = BlueprintPillar["productPrice"];
346
+ export type BlueprintPillarFinalCta = BlueprintPillar["finalCta"];
347
+ export type BlueprintDossier = NonNullable<BlueprintLevel["dossier"]>;
348
+ export type IndustryPublicationGate = BlueprintDossier["gate"];
349
+ export type BlueprintServiceConfig = NonNullable<BlueprintLevel["service"]>;
350
+ export type ServicePublicationGate = BlueprintServiceConfig["gate"];
351
+ export type BlueprintIntersectionConfig = NonNullable<BlueprintLevel["intersection"]>;
352
+ export type IntersectionGate = BlueprintIntersectionConfig["gate"];
353
+ export type IntersectionSimilarity = BlueprintIntersectionConfig["similarity"];
354
+ export type BlueprintHubConfig = NonNullable<BlueprintLevel["hub"]>;
355
+
356
+ export type BlueprintStatusGate = NonNullable<BlueprintPolicy["statusGate"]>;
357
+ export type BlueprintLinkingParent = NonNullable<BlueprintLinking["parent"]>;
358
+ export type BlueprintEvidenceDepthPolicy = NonNullable<BlueprintPolicy["evidencePerDepth"]>[string];
359
+ export type BlueprintDemandDepthPolicy = NonNullable<BlueprintPolicy["demandPerDepth"]>[string];
360
+ export type BlueprintDepthRolePolicy = NonNullable<BlueprintPolicy["depthRoles"]>[string];
361
+ export type BlueprintDuplicatePolicy = NonNullable<BlueprintEvidenceDepthPolicy["duplicate"]>;
362
+
363
+ export interface ParseBlueprintResult {
364
+ ok: boolean;
365
+ blueprint?: Blueprint;
366
+ errors: string[];
367
+ }
368
+
369
+ /** Validate an unknown value (parsed YAML) into a typed Blueprint. */
370
+ export function parseBlueprint(value: unknown): ParseBlueprintResult {
371
+ const result = blueprintSchema.safeParse(value);
372
+ if (result.success) {
373
+ return { ok: true, blueprint: result.data, errors: [] };
374
+ }
375
+ return {
376
+ ok: false,
377
+ errors: result.error.issues.map(
378
+ (issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`,
379
+ ),
380
+ };
381
+ }
106
382
 
107
383
  const DEFAULT_SEGMENT_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*$/;
108
384
 
@@ -13,7 +13,12 @@
13
13
  </non-goals>
14
14
  </MODULE_CONTRACT>
15
15
  <CHANGE_SUMMARY>
16
- <item>Architecture review 2026-07-10: initial implementation of composeIndexDecision and pure gate functions.</item>
16
+ <item>RFC-1097: step 6 — compass.migrate codemod run
17
+
18
+ Mechanical v1 to v2 header migration across the workspace: 942 files rewritten — CHANGE_SUMMARY windows collapsed into history, forbidden v1 blocks stripped, KEY_DECISIONS seeded from @ai-invariant comments (5 files) or TODO placeholders (103 files), blocks reordered to canonical order.</item>
19
+ <item>RFC-1097: sweep — werkstatt-engine clean
20
+
21
+ Sweep batch 4: 73 Compass headers on headerless engine files (certification, component-runtime, isolation, evolution, testing), real KEY_DECISIONS on 75 files (kernel, cache, dht, swim, gitmesh, runtime), ~80 purpose expansions (CONTRACT-02/PURPOSE-02), non-goals on 13 CONTRACT-03 files, CS-07 history literal fix repo-wide (253 files). Policy: .template.ts/.template.astro excludedPaths. werkstatt-engine now 0 diagnostics.</item>
17
22
  </CHANGE_SUMMARY>
18
23
  */
19
24