@warpgogol/werkstatt-shared 0.14.0 → 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.
- package/README.md +31 -13
- package/README.uk.md +25 -15
- package/package.json +519 -762
- package/src/{share/agent → agent}/ard-catalog.ts +6 -1
- package/src/{share/agent → agent}/dns-aid.test.ts +2 -2
- package/src/{share/agent → agent}/manifest.ts +15 -1
- package/src/{share/agent → agent}/search.ts +6 -1
- package/src/{share → agent}/tests/api-catalog.test.ts +2 -2
- package/src/{share → agent}/tests/ard-catalog.test.ts +2 -2
- package/src/{share → agent}/tests/capability.test.ts +1 -1
- package/src/{share → agent}/tests/fleet-catalog.test.ts +1 -1
- package/src/{share → agent}/tests/knowledge.test.ts +2 -2
- package/src/{share → agent}/tests/manifest.test.ts +1 -1
- package/src/{share → agent}/tests/mcp-card.test.ts +2 -2
- package/src/agent/tests/omit-empty.test.ts +33 -0
- package/src/{share → agent}/tests/openapi.test.ts +2 -2
- package/src/{share → agent}/tests/proof.test.ts +1 -1
- package/src/{share → attribution}/material-credits.ts +4 -4
- package/src/{share → checks}/check-hints.ts +6 -1
- package/src/checks/index.ts +4 -1
- package/src/checks/lib/astro-site-url.ts +6 -1
- package/src/checks/lib/i18n.ts +14 -0
- package/src/checks/result-helpers.ts +22 -5
- package/src/checks/tests/remediation-auto-populate.test.ts +83 -0
- package/src/{share → client-scripts}/counter-utils.ts +6 -2
- package/src/{share/scripts → client-scripts}/external-link-qr.ts +11 -16
- package/src/{share/scripts → client-scripts}/external-links.ts +12 -1
- package/src/{share/scripts → client-scripts}/gsap-counter.ts +8 -3
- package/src/client-scripts/index.ts +35 -0
- package/src/{share/scripts → client-scripts}/inline-number-animation.ts +1 -1
- package/src/{share/scripts → client-scripts}/lenis.ts +6 -1
- package/src/{share/scripts → client-scripts}/lordicon.ts +6 -1
- package/src/{share/scripts → client-scripts}/orchestrator.ts +10 -1
- package/src/{share/scripts → client-scripts}/scheduler.ts +6 -1
- package/src/client-scripts/scroll-spy.ts +106 -0
- package/src/client-scripts/tests/external-link-qr.test.ts +8 -0
- package/src/client-scripts/tests/external-links.test.ts +25 -0
- package/src/client-scripts/tests/gsap-counter.test.ts +8 -0
- package/src/client-scripts/tests/gsap-mountain-journey.test.ts +8 -0
- package/src/client-scripts/tests/gsap-parallax.test.ts +8 -0
- package/src/client-scripts/tests/gsap-reveal.test.ts +8 -0
- package/src/client-scripts/tests/gsap-stagger.test.ts +8 -0
- package/src/client-scripts/tests/inline-number-animation.test.ts +8 -0
- package/src/client-scripts/tests/lenis.test.ts +8 -0
- package/src/client-scripts/tests/live-photos.test.ts +8 -0
- package/src/client-scripts/tests/lordicon.test.ts +8 -0
- package/src/client-scripts/tests/orchestrator.test.ts +47 -0
- package/src/client-scripts/tests/scheduler.test.ts +23 -0
- package/src/client-scripts/tests/scroll-spy.test.ts +204 -0
- package/src/{share/scripts → client-scripts/tests}/video-player.test.ts +51 -31
- package/src/component/contracts.ts +206 -0
- package/src/component/index.ts +11 -0
- package/src/{share → content}/content-reference.ts +3 -3
- package/src/{share/content → content}/entity-id.ts +6 -3
- package/src/content/index.ts +3 -0
- package/src/{share/content → content}/merge.ts +6 -1
- package/src/content/system-manifest.test.ts +107 -0
- package/src/content/system-manifest.ts +12 -94
- package/src/{share → content}/tests/resolve-field-path.test.ts +1 -1
- package/src/{share → content}/tests/substitute-deep.test.ts +1 -1
- package/src/content-discipline/index.ts +19 -0
- package/src/{share/content-discipline → content-discipline}/parsers.ts +2 -2
- package/src/{share/env.d.ts → env.d.ts} +6 -3
- package/src/fingerprint/canonical-json.ts +731 -0
- package/src/fingerprint/index.ts +12 -0
- package/src/fingerprint/primitives.ts +72 -0
- package/src/{share/i18n → i18n}/localization.ts +6 -2
- package/src/integration/adapters.ts +10 -71
- package/src/integration/dispatch.ts +1 -1
- package/src/integration/funnel.ts +6 -1
- package/src/integration/index.ts +101 -4
- package/src/integration/lagebild-destination-adapter.ts +108 -0
- package/src/integration/lagebild-ingress.ts +7 -12
- package/src/integration/orchestration.ts +11 -10
- package/src/integration/tests/deliver-event.test.ts +1 -1
- package/src/integration/tests/dispatch.test.ts +4 -4
- package/src/integration/tests/hub-runtime.test.ts +22 -14
- package/src/integration/vitest.config.ts +8 -0
- package/src/kernel/desired-state.ts +227 -0
- package/src/kernel/diagnostic.ts +289 -0
- package/src/kernel/fs-atomic.ts +131 -0
- package/src/kernel/index.ts +15 -0
- package/src/kernel/tests/fs-atomic.test.ts +150 -0
- package/src/kernel/tests/workspace-io.test.ts +187 -0
- package/src/kernel/types.ts +459 -0
- package/src/kernel/workspace-io.ts +248 -0
- package/src/{share → knowledge}/tests/claim.test.ts +1 -1
- package/src/{share → knowledge}/tests/derivation.test.ts +1 -1
- package/src/{share → knowledge}/tests/freshness.test.ts +1 -1
- package/src/{share → knowledge}/tests/ledger.test.ts +1 -1
- package/src/{share → knowledge}/tests/plan.test.ts +1 -1
- package/src/{share → knowledge}/tests/source.test.ts +1 -1
- package/src/legal/index.ts +15 -0
- package/src/{share/middleware → middleware}/access-protection.ts +8 -8
- package/src/{share → node}/dev-props-validator.ts +6 -1
- package/src/{share → node}/import-scan.ts +23 -3
- package/src/{share → node}/semantic/derived-prices-loader.ts +4 -2
- package/src/{share → node}/semantic/markdown-twin-provenance.ts +1 -1
- package/src/node/tests/derived-prices-loader.test.ts +59 -0
- package/src/node/tests/markdown-twin-provenance.test.ts +152 -0
- package/src/observability/env-resolver.ts +6 -1
- package/src/observability/index.ts +6 -1
- package/src/observability/otlp-converter.ts +6 -1
- package/src/observability/otlp-transport.ts +6 -1
- package/src/observability/pusher.ts +6 -1
- package/src/observability/redact.ts +6 -1
- package/src/observability/typed-refs.ts +6 -2
- package/src/observability/vitest.config.ts +1 -0
- package/src/{share → offers}/formula-eval.ts +3 -3
- package/src/{share → offers}/tests/formula-eval.test.ts +2 -2
- package/src/onboarding/index.ts +1 -0
- package/src/{share → onboarding}/tests/onboarding-yaml.test.ts +1 -1
- package/src/ontology/archetype-registry.ts +6 -1
- package/src/ontology/archetypes/index.json +33 -1
- package/src/ontology/archetypes/index.yaml +27 -1
- package/src/ontology/archetypes/sections/entity-grid.yaml +46 -0
- package/src/ontology/archetypes/sections/exit-diagram.yaml +43 -0
- package/src/ontology/biome-token-projection.ts +6 -1
- package/src/ontology/cosmic/index.ts +6 -1
- package/src/ontology/cosmic/moon-catalog.ts +6 -1
- package/src/ontology/cosmic/planet-catalog.ts +6 -1
- package/src/ontology/cosmic/star-catalog.ts +6 -1
- package/src/ontology/enums.ts +6 -1
- package/src/ontology/external-surfaces/index.ts +1 -1
- package/src/ontology/index.ts +6 -2
- package/src/ontology/manifest.ts +26 -4
- package/src/ontology/operations/artifact-store.ts +45 -0
- package/src/ontology/operations/dht.ts +98 -0
- package/src/ontology/operations/handoff.ts +92 -0
- package/src/ontology/operations/index.ts +187 -1
- package/src/ontology/operations/leitstand.ts +99 -0
- package/src/ontology/operations/materialization.ts +90 -0
- package/src/ontology/operations/mission.ts +111 -0
- package/src/ontology/operations/naming-policy.ts +132 -0
- package/src/ontology/operations/notausgang.ts +64 -0
- package/src/ontology/operations/release.ts +121 -0
- package/src/ontology/operations/sternsystem.ts +192 -0
- package/src/ontology/operations/werkstatt.ts +48 -0
- package/src/ontology/schemas/biome.ts +7 -2
- package/src/ontology/schemas/capability.ts +1 -1
- package/src/ontology/schemas/constellation.ts +6 -1
- package/src/ontology/schemas/index.ts +6 -2
- package/src/ontology/schemas/manifest-resolver.ts +6 -1
- package/src/ontology/schemas/page-entry.ts +9 -5
- package/src/ontology/schemas/system/growth.ts +6 -1
- package/src/ontology/schemas/system/manifest.ts +40 -1
- package/src/ontology/schemas/system/page-output.ts +7 -6
- package/src/ontology/schemas/system/tests/growth.test.ts +22 -0
- package/src/ontology/schemas/system/tests/integrations.test.ts +12 -0
- package/src/ontology/schemas/system/tests/manifest.test.ts +22 -0
- package/src/ontology/schemas/system/tests/page-output.test.ts +13 -0
- package/src/ontology/schemas/system/tests/release.test.ts +22 -0
- package/src/ontology/schemas/system/tests/text.test.ts +18 -0
- package/src/ontology/schemas/system/tests/verification.test.ts +12 -0
- package/src/ontology/schemas/system/text.ts +15 -0
- package/src/ontology/schemas/system.ts +6 -2
- package/src/ontology/schemas/tests/biome.test.ts +19 -0
- package/src/ontology/schemas/tests/capability.test.ts +22 -0
- package/src/ontology/schemas/tests/constellation.test.ts +22 -0
- package/src/ontology/schemas/tests/dns-records.test.ts +13 -0
- package/src/ontology/schemas/tests/manifest-resolver.test.ts +13 -0
- package/src/ontology/schemas/tests/page-entry.test.ts +22 -0
- package/src/ontology/schemas/tests/section-archetype.test.ts +12 -0
- package/src/ontology/schemas/tests/site-family.test.ts +18 -0
- package/src/ontology/schemas/tests/system.test.ts +20 -0
- package/src/ontology/shared-section-props/body-fragments.ts +2 -0
- package/src/ontology/tests/sternsystem-owner.test.ts +1 -1
- package/src/ontology/vitest.config.ts +1 -0
- package/src/{share → page}/page.ts +13 -9
- package/src/{share → page}/tests/dev-props-validator.test.ts +1 -1
- package/src/{share → page}/tests/hero-section-numbering-parity.test.ts +1 -1
- package/src/passport/index.ts +6 -1
- package/src/passport/key-rotate.ts +10 -2
- package/src/passport/schema.ts +6 -1
- package/src/passport/sign.ts +8 -3
- package/src/passport/vitest.config.ts +1 -0
- package/src/pbt/index.test.ts +95 -0
- package/src/pbt/index.ts +251 -0
- package/src/plugin/plugin-contract.ts +1 -1
- package/src/{share → policy}/entitlement.ts +24 -4
- package/src/{share → policy}/feature-policy.ts +8 -3
- package/src/{share → policy}/visibility.ts +7 -2
- package/src/redirects/redirects.ts +117 -0
- package/src/{share → redirects/tests}/redirects.test.ts +1 -1
- package/src/remediation/remediation-catalog.ts +316 -0
- package/src/{share/routes → routes}/template-filter.ts +1 -1
- package/src/{share → runtime}/runtime-context.ts +7 -2
- package/src/{share → runtime}/shared-context.ts +1 -1
- package/src/{share/schemas → schemas}/claims.ts +2 -2
- package/src/{share/schemas → schemas}/effects.ts +6 -1
- package/src/{share/schemas → schemas}/features.ts +1 -1
- package/src/{share/schemas → schemas}/index.ts +3 -3
- package/src/{share/schemas → schemas}/navigation.ts +6 -1
- package/src/{share/schemas → schemas}/page-base.ts +6 -2
- package/src/{share/schemas → schemas}/person.ts +1 -1
- package/src/{share/schemas → schemas}/standard-list-item.ts +1 -1
- package/src/schemas/tests/claim-records.test.ts +52 -0
- package/src/schemas/tests/claims.test.ts +23 -0
- package/src/schemas/tests/effects.test.ts +116 -0
- package/src/schemas/tests/features.test.ts +61 -0
- package/src/schemas/tests/horizontal-align.test.ts +16 -0
- package/src/schemas/tests/icon-color.test.ts +16 -0
- package/src/schemas/tests/live-photo.test.ts +40 -0
- package/src/schemas/tests/material-credit.test.ts +51 -0
- package/src/schemas/tests/media.test.ts +26 -0
- package/src/schemas/tests/navigation.test.ts +58 -0
- package/src/schemas/tests/page-base.test.ts +19 -0
- package/src/schemas/tests/participant.test.ts +26 -0
- package/src/schemas/tests/person.test.ts +12 -0
- package/src/schemas/tests/print.test.ts +30 -0
- package/src/schemas/tests/section-background.test.ts +31 -0
- package/src/schemas/tests/section-body.test.ts +16 -0
- package/src/schemas/tests/section-cards.test.ts +17 -0
- package/src/schemas/tests/section-cta.test.ts +41 -0
- package/src/schemas/tests/section-header.test.ts +31 -0
- package/src/schemas/tests/section-image.test.ts +24 -0
- package/src/schemas/tests/section-motion.test.ts +29 -0
- package/src/schemas/tests/section-shell.test.ts +42 -0
- package/src/schemas/tests/section-stats.test.ts +17 -0
- package/src/schemas/tests/site-background.test.ts +33 -0
- package/src/schemas/tests/standard-list-item.test.ts +16 -0
- package/src/{share → sections}/rfc0042-utils.ts +1 -1
- package/src/{share/semantic → semantic}/block-extractors/index.ts +20 -1
- package/src/{share/semantic → semantic}/business-projection.ts +95 -1
- package/src/semantic/canonical-uri.ts +54 -0
- package/src/{share/semantic → semantic}/extract.ts +100 -1
- package/src/semantic/fact-extraction.test.ts +47 -0
- package/src/semantic/fact-extraction.ts +46 -0
- package/src/semantic/freshness.ts +67 -0
- package/src/{share/semantic → semantic}/ids.ts +6 -1
- package/src/{share/semantic → semantic}/index.ts +9 -2
- package/src/{share/semantic → semantic}/jsonld/breadcrumb.ts +6 -2
- package/src/{share/semantic → semantic}/jsonld/context.ts +6 -2
- package/src/{share/semantic → semantic}/jsonld/faq.ts +6 -2
- package/src/{share/semantic → semantic}/jsonld/initiative.ts +6 -1
- package/src/{share/semantic → semantic}/jsonld/organization.ts +6 -1
- package/src/{share/semantic → semantic}/jsonld/person.ts +6 -2
- package/src/{share/semantic → semantic}/jsonld/service.ts +6 -2
- package/src/semantic/jsonld/shared.ts +36 -0
- package/src/semantic/jsonld/tests/article.test.ts +89 -0
- package/src/semantic/jsonld/tests/breadcrumb.test.ts +62 -0
- package/src/semantic/jsonld/tests/collection-list.test.ts +39 -0
- package/src/semantic/jsonld/tests/faq.test.ts +60 -0
- package/src/semantic/jsonld/tests/initiative.test.ts +56 -0
- package/src/semantic/jsonld/tests/organization.test.ts +123 -0
- package/src/semantic/jsonld/tests/person.test.ts +89 -0
- package/src/semantic/jsonld/tests/service.test.ts +65 -0
- package/src/semantic/jsonld/tests/shared.test.ts +41 -0
- package/src/semantic/jsonld/tests/video.test.ts +84 -0
- package/src/semantic/jsonld/tests/webpage.test.ts +93 -0
- package/src/semantic/jsonld/tests/website.test.ts +27 -0
- package/src/semantic/jsonld/types.ts +24 -0
- package/src/{share/semantic → semantic}/jsonld/webpage.ts +6 -1
- package/src/semantic/jsonld/website.ts +32 -0
- package/src/{share/semantic → semantic}/jsonld.ts +6 -1
- package/src/{share/semantic → semantic}/llms.ts +41 -3
- package/src/{share/semantic → semantic}/models.ts +27 -38
- package/src/{share/semantic → semantic}/organization-profile.ts +3 -0
- package/src/{share/semantic → semantic}/page-builders/markdown-page.ts +6 -3
- package/src/{share/semantic → semantic}/page-utils.ts +6 -3
- package/src/semantic/tests/ai.test.ts +55 -0
- package/src/semantic/tests/block-extraction.test.ts +34 -0
- package/src/{share/tests/breadcrumbs.test.ts → semantic/tests/breadcrumbs-0229.test.ts} +1 -1
- package/src/semantic/tests/breadcrumbs.test.ts +127 -0
- package/src/{share → semantic}/tests/build-page-price-markers.test.ts +2 -2
- package/src/semantic/tests/build-page.test.ts +122 -0
- package/src/semantic/tests/business-projection.test.ts +367 -0
- package/src/semantic/tests/canonical-uri.test.ts +56 -0
- package/src/semantic/tests/extract.test.ts +209 -0
- package/src/semantic/tests/feed.test.ts +113 -0
- package/src/semantic/tests/freshness.pbt.test.ts +108 -0
- package/src/semantic/tests/helpers.ts +32 -0
- package/src/semantic/tests/ids.test.ts +118 -0
- package/src/{share/tests/image-sitemap.test.ts → semantic/tests/image-sitemap-0150.test.ts} +1 -1
- package/src/semantic/tests/image-sitemap.test.ts +109 -0
- package/src/{share → semantic}/tests/jsonld-service.test.ts +2 -2
- package/src/{share → semantic}/tests/jsonld-video.test.ts +3 -3
- package/src/{share → semantic}/tests/jsonld-webpage.test.ts +3 -3
- package/src/semantic/tests/jsonld.test.ts +61 -0
- package/src/{share → semantic}/tests/llms-0789.test.ts +2 -2
- package/src/semantic/tests/llms-policy.test.ts +60 -0
- package/src/semantic/tests/llms.test.ts +164 -0
- package/src/semantic/tests/markdown-hygiene.test.ts +72 -0
- package/src/semantic/tests/markdown-page.test.ts +97 -0
- package/src/{share → semantic}/tests/organization-jsonld.test.ts +3 -3
- package/src/semantic/tests/organization-profile.test.ts +107 -0
- package/src/{share/tests/output-projection.test.ts → semantic/tests/output-projection-0143.test.ts} +1 -1
- package/src/semantic/tests/output-projection.test.ts +77 -0
- package/src/semantic/tests/page-markdown.test.ts +98 -0
- package/src/semantic/tests/page-utils.test.ts +88 -0
- package/src/{share/tests/price-marker-resolver.test.ts → semantic/tests/price-marker-resolver-0767.test.ts} +2 -2
- package/src/semantic/tests/price-marker-resolver.test.ts +90 -0
- package/src/semantic/tests/project-claims.pbt.test.ts +60 -0
- package/src/semantic/tests/robots.test.ts +70 -0
- package/src/{share/semantic → semantic}/tests/split-sentences.test.ts +1 -1
- package/src/{share → semantic}/tests/twin-path.test.ts +1 -1
- package/src/semantic/tests/update-stamp.test.ts +102 -0
- package/src/signing/index.ts +13 -0
- package/src/signing/key.ts +139 -0
- package/src/signing/sign.ts +66 -0
- package/src/signing/types.ts +29 -0
- package/src/{share/slug → slug}/slug-url.ts +4 -1
- package/src/stack/run-tool.ts +108 -0
- package/src/stack/stack-checks.ts +124 -0
- package/src/stack/tests/run-tool.test.ts +138 -0
- package/src/stack/tests/stack-checks.test.ts +141 -0
- package/src/stack/tests/walk-files.test.ts +131 -0
- package/src/stack/walk-files.ts +114 -0
- package/src/surface/blueprint.ts +342 -66
- package/src/surface/decision-composer.ts +6 -1
- package/src/surface/geo.ts +6 -1
- package/src/surface/index.ts +11 -7
- package/src/surface/types.ts +2 -2
- package/src/surface/vitest.config.ts +1 -0
- package/src/tests/signing-core.test.ts +129 -0
- package/src/{share → text}/css-value-normalize.ts +6 -1
- package/src/text/string-utils.ts +24 -0
- package/src/{share → text}/tests/text-normalize.test.ts +5 -0
- package/src/{share → text}/text-normalize.ts +4 -3
- package/src/{share → text}/wrap-inline-numbers.ts +1 -1
- package/src/types/axiom-study.d.ts +36 -0
- package/src/types/hls-js-light.d.ts +21 -0
- package/src/types/qrcode-browser.d.ts +23 -0
- package/src/typography/fix.pbt.test.ts +208 -0
- package/src/typography/fix.ts +148 -0
- package/src/typography/index.ts +54 -0
- package/src/typography/locale-defaults.ts +97 -0
- package/src/typography/rules-tier1.test.ts +459 -0
- package/src/typography/rules-tier1.ts +925 -0
- package/src/typography/rules-tier2-locale.pbt.test.ts +190 -0
- package/src/typography/rules-tier2-locale.test.ts +286 -0
- package/src/typography/rules-tier2-locale.ts +399 -0
- package/src/typography/rules-tier2-structure.test.ts +330 -0
- package/src/typography/rules-tier2-structure.ts +378 -0
- package/src/typography/rules-tier3-advisory.test.ts +290 -0
- package/src/typography/rules-tier3-advisory.ts +239 -0
- package/src/typography/text-surface.test.ts +244 -0
- package/src/typography/text-surface.ts +448 -0
- package/src/index.ts +0 -14
- package/src/integration/port-barrel.ts +0 -105
- package/src/share/content/index.ts +0 -16
- package/src/share/content-discipline/index.ts +0 -14
- package/src/share/index.ts +0 -86
- package/src/share/legal/index.ts +0 -1
- package/src/share/redirects.ts +0 -54
- package/src/share/scripts/index.ts +0 -26
- package/src/share/semantic/jsonld/shared.ts +0 -31
- package/src/share/semantic/jsonld/types.ts +0 -18
- package/src/share/semantic/jsonld/website.ts +0 -27
- package/src/share/string-utils.ts +0 -19
- package/src/share/types/axiom-study.d.ts +0 -22
- package/src/share/types/hls-js-light.d.ts +0 -16
- package/src/share/types/qrcode-browser.d.ts +0 -18
- package/src/share/utility-registry.yaml +0 -36
- package/src/share/vitest.config.ts +0 -8
- package/src/surface/blueprint-schema.ts +0 -314
- package/src/surface/blueprint-types.ts +0 -256
- /package/src/{share/agent → agent}/api-catalog.ts +0 -0
- /package/src/{share/agent → agent}/capability.ts +0 -0
- /package/src/{share/agent → agent}/dns-aid.ts +0 -0
- /package/src/{share/agent → agent}/fleet-catalog.ts +0 -0
- /package/src/{share/agent → agent}/index.ts +0 -0
- /package/src/{share/agent → agent}/knowledge.ts +0 -0
- /package/src/{share/agent → agent}/mcp-card.ts +0 -0
- /package/src/{share/agent → agent}/omit-empty.ts +0 -0
- /package/src/{share/agent → agent}/openapi.ts +0 -0
- /package/src/{share/agent → agent}/proof.ts +0 -0
- /package/src/{share/agent → agent}/search.test.ts +0 -0
- /package/src/{share → attribution}/attribution-display.ts +0 -0
- /package/src/{share/scripts → client-scripts}/gsap-mountain-journey.ts +0 -0
- /package/src/{share/scripts → client-scripts}/gsap-parallax.ts +0 -0
- /package/src/{share/scripts → client-scripts}/gsap-reveal.ts +0 -0
- /package/src/{share/scripts → client-scripts}/gsap-stagger.ts +0 -0
- /package/src/{share/scripts → client-scripts}/live-photos.ts +0 -0
- /package/src/{share/scripts → client-scripts}/video-player.ts +0 -0
- /package/src/{share/content → content}/resolve-field-path.ts +0 -0
- /package/src/{share/content → content}/substitute-deep.ts +0 -0
- /package/src/{share → content}/tests/content-ref-index.test.ts +0 -0
- /package/src/{share/content-discipline → content-discipline}/types.ts +0 -0
- /package/src/{share → image-provider}/image-provider.ts +0 -0
- /package/src/{share/knowledge → knowledge}/claim.ts +0 -0
- /package/src/{share/knowledge → knowledge}/derivation.ts +0 -0
- /package/src/{share/knowledge → knowledge}/freshness.ts +0 -0
- /package/src/{share/knowledge → knowledge}/index.ts +0 -0
- /package/src/{share/knowledge → knowledge}/ledger.ts +0 -0
- /package/src/{share/knowledge → knowledge}/plan.ts +0 -0
- /package/src/{share/knowledge → knowledge}/source.ts +0 -0
- /package/src/{share/legal → legal}/translation-policy.ts +0 -0
- /package/src/{share/middleware → middleware}/language-redirect.ts +0 -0
- /package/src/{share/middleware → middleware}/tests/access-protection.test.ts +0 -0
- /package/src/{share → node}/fs/index.ts +0 -0
- /package/src/{share/tests/markdown-twin-provenance.test.ts → node/tests/markdown-twin-provenance-0613.test.ts} +0 -0
- /package/src/{share → offers}/offer-capacity.ts +0 -0
- /package/src/{share/onboarding-yaml/index.ts → onboarding/yaml.ts} +0 -0
- /package/src/{share → ontology}/tests/ontology-role-by-cosmic-name.test.ts +0 -0
- /package/src/{share/routes → routes}/tests/template-filter.test.ts +0 -0
- /package/src/{share/schemas → schemas}/claim-records.ts +0 -0
- /package/src/{share/schemas → schemas}/horizontal-align.ts +0 -0
- /package/src/{share/schemas → schemas}/icon-color.ts +0 -0
- /package/src/{share/schemas → schemas}/live-photo.ts +0 -0
- /package/src/{share/schemas → schemas}/material-credit.ts +0 -0
- /package/src/{share/schemas → schemas}/media.ts +0 -0
- /package/src/{share/schemas → schemas}/participant.ts +0 -0
- /package/src/{share/schemas → schemas}/print.ts +0 -0
- /package/src/{share/schemas → schemas}/section-background.ts +0 -0
- /package/src/{share/schemas → schemas}/section-body.ts +0 -0
- /package/src/{share/schemas → schemas}/section-cards.ts +0 -0
- /package/src/{share/schemas → schemas}/section-cta.ts +0 -0
- /package/src/{share/schemas → schemas}/section-header.ts +0 -0
- /package/src/{share/schemas → schemas}/section-image.ts +0 -0
- /package/src/{share/schemas → schemas}/section-motion.ts +0 -0
- /package/src/{share/schemas → schemas}/section-shell.ts +0 -0
- /package/src/{share/schemas → schemas}/section-stats.ts +0 -0
- /package/src/{share/schemas → schemas}/site-background.ts +0 -0
- /package/src/{share/semantic → semantic}/ai.ts +0 -0
- /package/src/{share/semantic → semantic}/block-extraction.ts +0 -0
- /package/src/{share/semantic → semantic}/breadcrumbs.ts +0 -0
- /package/src/{share/semantic → semantic}/build-page.ts +0 -0
- /package/src/{share/semantic → semantic}/feed.ts +0 -0
- /package/src/{share/semantic → semantic}/image-sitemap.ts +0 -0
- /package/src/{share/semantic → semantic}/jsonld/article.ts +0 -0
- /package/src/{share/semantic → semantic}/jsonld/collection-list.ts +0 -0
- /package/src/{share/semantic → semantic}/jsonld/video.ts +0 -0
- /package/src/{share/semantic → semantic}/llms-policy.ts +0 -0
- /package/src/{share/semantic → semantic}/markdown-hygiene.ts +0 -0
- /package/src/{share/semantic → semantic}/output-projection.ts +0 -0
- /package/src/{share/semantic → semantic}/page-markdown.ts +0 -0
- /package/src/{share/semantic → semantic}/price-marker-resolver.ts +0 -0
- /package/src/{share/semantic → semantic}/robots.ts +0 -0
- /package/src/{share/semantic → semantic}/update-stamp.ts +0 -0
- /package/src/{share/slug → slug}/heading-slugger.ts +0 -0
- /package/src/{share/slug → slug}/index.ts +0 -0
- /package/src/{share/slug → slug}/slug-id.ts +0 -0
- /package/src/{share/slug → slug}/strategies.ts +0 -0
- /package/src/{share/slug → slug}/tests/slug.test.ts +0 -0
- /package/src/{share → text}/tests/text-normalize.pbt.test.ts +0 -0
- /package/src/{share → text}/text-position.ts +0 -0
|
@@ -59,7 +59,7 @@ export function need<T>(fieldName: string, value: T | undefined | null): T | str
|
|
|
59
59
|
* const props = cast<TeamSectionContent>(pageOverride);
|
|
60
60
|
* ```
|
|
61
61
|
*/
|
|
62
|
-
export function cast<T extends
|
|
62
|
+
export function cast<T extends object>(pageOverride: Record<string, unknown>): T {
|
|
63
63
|
return pageOverride as unknown as T;
|
|
64
64
|
}
|
|
65
65
|
|
|
@@ -501,10 +501,27 @@ for (const blockType of PASSPORT_NOOP_TYPES) {
|
|
|
501
501
|
});
|
|
502
502
|
}
|
|
503
503
|
|
|
504
|
+
// ---------------------------------------------------------------------------
|
|
505
|
+
// entity-grid (RFC-1062) — extracts heading and body items with descriptions.
|
|
504
506
|
// ---------------------------------------------------------------------------
|
|
505
507
|
// Site-specific block types that have no semantic text to extract but must be
|
|
506
508
|
// registered so page.blocks.extract.validate does not fail.
|
|
507
|
-
|
|
509
|
+
BLOCK_EXTRACTORS.register<Record<string, unknown>>({
|
|
510
|
+
blockType: "entity-grid",
|
|
511
|
+
extract(props) {
|
|
512
|
+
const heading = safeString(safeGet(props, "header.heading"));
|
|
513
|
+
const lead = safeString(safeGet(props, "header.subheading"));
|
|
514
|
+
const items = safeArray(safeGet(props, "body.items"), (item) => {
|
|
515
|
+
const number = safeString(safeGet(item, "number"));
|
|
516
|
+
const title = safeString(safeGet(item, "title"));
|
|
517
|
+
const description = safeString(safeGet(item, "description"));
|
|
518
|
+
if (!title) return undefined;
|
|
519
|
+
return { title: number ? `${number}. ${title}` : title, description };
|
|
520
|
+
});
|
|
521
|
+
return { heading, lead, items };
|
|
522
|
+
},
|
|
523
|
+
});
|
|
524
|
+
|
|
508
525
|
const SITE_NOOP_TYPES = [
|
|
509
526
|
"nachweis-list",
|
|
510
527
|
"nachweis-detail",
|
|
@@ -514,6 +531,8 @@ const SITE_NOOP_TYPES = [
|
|
|
514
531
|
"mountain-journey",
|
|
515
532
|
"dynamic-status-block",
|
|
516
533
|
"service-metadata-block",
|
|
534
|
+
"toc",
|
|
535
|
+
"exit-diagram",
|
|
517
536
|
] as const;
|
|
518
537
|
|
|
519
538
|
for (const blockType of SITE_NOOP_TYPES) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*
|
|
2
2
|
<MODULE_CONTRACT>
|
|
3
|
-
<purpose>RFC-0148: pure projectors that map canonical business-schema data into the semantic model, plus the projection visibility boundary. Framework-agnostic and side-effect-free, so the disk llms path and the Astro JSON-LD path project every business file identically. Lives in @warpgogol/werkstatt-shared/
|
|
3
|
+
<purpose>RFC-0148: pure projectors that map canonical business-schema data into the semantic model, plus the projection visibility boundary. Framework-agnostic and side-effect-free, so the disk llms path and the Astro JSON-LD path project every business file identically. Lives in @warpgogol/werkstatt-shared/semantic (not @warpgogol/werkstatt-site/pbp) because @warpgogol/werkstatt-site/pbp depends on @warpgogol/site-kernel-content — placing the projectors here keeps the node disk loader cycle-free.</purpose>
|
|
4
4
|
<non-goals>
|
|
5
5
|
<item>Do not read files — pure mapping over already-loaded data.</item>
|
|
6
6
|
<item>Do not project privacy-sensitive domains (external-services, compliance).</item>
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
<item>RFC-0148: initial projection registry — offer + location projectors and the visibility boundary.</item>
|
|
11
11
|
<item>RFC-0287: added projectWeb for the Agent Surface knowledge tier.</item>
|
|
12
12
|
<item>RFC-0373: added projectServices for business service catalog projection.</item>
|
|
13
|
+
<item>RFC-1076: add projectClaims projector and SemanticClaimProvenance / SemanticEvidenceRef types.</item>
|
|
13
14
|
</CHANGE_SUMMARY>
|
|
14
15
|
*/
|
|
15
16
|
|
|
@@ -21,6 +22,38 @@ import type {
|
|
|
21
22
|
SemanticWeb,
|
|
22
23
|
} from "./models.ts";
|
|
23
24
|
|
|
25
|
+
export interface SemanticClaimProvenance {
|
|
26
|
+
/** Stable claim ID from PbpClaim.id. */
|
|
27
|
+
id: string;
|
|
28
|
+
/** Claim class: factual, risk, benefit, etc. */
|
|
29
|
+
claimClass: string;
|
|
30
|
+
/** Claim kind: risk, benefit, comparison, fact, limitation, recommendation. */
|
|
31
|
+
claimKind: string;
|
|
32
|
+
/** The claim statement text. */
|
|
33
|
+
statement: string;
|
|
34
|
+
/** ISO 639-1 language tag of the statement (RFC-0706). */
|
|
35
|
+
statementLang?: string;
|
|
36
|
+
/** Verification level N0–N3 (ADR-0028). */
|
|
37
|
+
verificationLevel?: string;
|
|
38
|
+
/** Confidence: high, medium, low. */
|
|
39
|
+
confidence?: string;
|
|
40
|
+
/** Evidence references — resolved from PbpClaim.evidenceRefs. */
|
|
41
|
+
evidence: SemanticEvidenceRef[];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface SemanticEvidenceRef {
|
|
45
|
+
/** EvidenceSource entity ID. */
|
|
46
|
+
id: string;
|
|
47
|
+
/** Evidence kind: verified-record, third-party-registry, certificate, etc. */
|
|
48
|
+
kind: string;
|
|
49
|
+
/** Human-readable label for the evidence source. */
|
|
50
|
+
label: string;
|
|
51
|
+
/** SHA-256 integrity hash of the canonical evidence artifact, if available. */
|
|
52
|
+
sha256?: string;
|
|
53
|
+
/** Canonical URI of the evidence source (RFC-1075), if available. */
|
|
54
|
+
canonicalUri?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
24
57
|
/**
|
|
25
58
|
* RFC-0148 privacy boundary. `public` projects to AI (llms) + JSON-LD; `pageMeta`
|
|
26
59
|
* is build-time only (e.g. legal-page dates → sitemap lastmod); `none` is never
|
|
@@ -253,6 +286,67 @@ export function projectServices(
|
|
|
253
286
|
return services;
|
|
254
287
|
}
|
|
255
288
|
|
|
289
|
+
/**
|
|
290
|
+
* RFC-1076: project PBP claims with their evidence references into the semantic model.
|
|
291
|
+
* Only claims with status "published" are projected. The sha256 is read from the
|
|
292
|
+
* canonical item (items[key] where canonical === true), falling back to the first
|
|
293
|
+
* item. Localization is handled by the semantic loader (per-language loading with
|
|
294
|
+
* default-language fallback), not by this projector.
|
|
295
|
+
*/
|
|
296
|
+
export function projectClaims(
|
|
297
|
+
claims: ReadonlyArray<Record<string, unknown>> | undefined,
|
|
298
|
+
evidenceSources: Record<string, Record<string, unknown>> | undefined,
|
|
299
|
+
): SemanticClaimProvenance[] {
|
|
300
|
+
if (!claims?.length) return [];
|
|
301
|
+
const result: SemanticClaimProvenance[] = [];
|
|
302
|
+
for (const claim of claims) {
|
|
303
|
+
const id = typeof claim["id"] === "string" ? claim["id"] : "";
|
|
304
|
+
if (!id) continue;
|
|
305
|
+
const status = typeof claim["status"] === "string" ? claim["status"] : "";
|
|
306
|
+
if (status !== "published") continue;
|
|
307
|
+
const evidenceRefs = (claim["evidenceRefs"] ?? {}) as Record<string, { ref?: string }>;
|
|
308
|
+
const evidence: SemanticEvidenceRef[] = [];
|
|
309
|
+
for (const ref of Object.values(evidenceRefs)) {
|
|
310
|
+
const sourceId = ref?.ref;
|
|
311
|
+
if (!sourceId) continue;
|
|
312
|
+
const source = evidenceSources?.[sourceId];
|
|
313
|
+
if (!source) continue;
|
|
314
|
+
const items = (source["items"] ?? {}) as Record<
|
|
315
|
+
string,
|
|
316
|
+
{ sha256?: string; canonical?: boolean }
|
|
317
|
+
>;
|
|
318
|
+
const itemValues = Object.values(items);
|
|
319
|
+
const canonicalItem = itemValues.find((it) => it?.canonical === true) ?? itemValues[0];
|
|
320
|
+
evidence.push({
|
|
321
|
+
id: sourceId,
|
|
322
|
+
kind: typeof source["kind"] === "string" ? source["kind"] : "",
|
|
323
|
+
label: typeof source["name"] === "string" ? source["name"] : sourceId,
|
|
324
|
+
...(typeof canonicalItem?.["sha256"] === "string"
|
|
325
|
+
? { sha256: canonicalItem["sha256"] }
|
|
326
|
+
: {}),
|
|
327
|
+
...(typeof source["canonicalUri"] === "string"
|
|
328
|
+
? { canonicalUri: source["canonicalUri"] }
|
|
329
|
+
: {}),
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
result.push({
|
|
333
|
+
id,
|
|
334
|
+
claimClass: typeof claim["claimClass"] === "string" ? claim["claimClass"] : "",
|
|
335
|
+
claimKind: typeof claim["claimKind"] === "string" ? claim["claimKind"] : "",
|
|
336
|
+
statement: typeof claim["statement"] === "string" ? claim["statement"] : "",
|
|
337
|
+
...(typeof claim["statementLang"] === "string"
|
|
338
|
+
? { statementLang: claim["statementLang"] }
|
|
339
|
+
: {}),
|
|
340
|
+
...(typeof claim["verificationLevel"] === "string"
|
|
341
|
+
? { verificationLevel: claim["verificationLevel"] }
|
|
342
|
+
: {}),
|
|
343
|
+
...(typeof claim["confidence"] === "string" ? { confidence: claim["confidence"] } : {}),
|
|
344
|
+
evidence,
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
return result;
|
|
348
|
+
}
|
|
349
|
+
|
|
256
350
|
/**
|
|
257
351
|
* RFC-0287: project the business web/domain identity record (business/{lang}/web.md
|
|
258
352
|
* — primaryUrl, statusUrl, domains.{primary,german}). A thin, faithful passthrough of
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>RFC-1075: derive persistent canonical URIs for PBP entity envelopes from site origin and entity identity. Used for Linked Data @id fields in JSON-LD and llms-full.txt projections.</purpose>
|
|
4
|
+
<non-goals>
|
|
5
|
+
<item>Does not validate that the entity ID is well-formed — callers are responsible for providing valid IDs.</item>
|
|
6
|
+
<item>Does not perform URL normalization beyond trailing-slash removal on the site origin.</item>
|
|
7
|
+
</non-goals>
|
|
8
|
+
</MODULE_CONTRACT>
|
|
9
|
+
<CHANGE_SUMMARY>
|
|
10
|
+
<item>RFC-1075: initial — deriveCanonicalUri pure function for persistent entity @id URIs.</item>
|
|
11
|
+
</CHANGE_SUMMARY>
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Entity types supported by the PBP canonical URI scheme.
|
|
16
|
+
*
|
|
17
|
+
* The URI path pattern is `/.well-known/entity/{type}/{id}` for typed entities
|
|
18
|
+
* (e.g. offerings) and `/.well-known/entity/business` for the single business entity.
|
|
19
|
+
*/
|
|
20
|
+
export type CanonicalEntityType = "business" | "offering";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* RFC-1075: derive a persistent canonical URI for a PBP entity.
|
|
24
|
+
*
|
|
25
|
+
* The URI follows the pattern:
|
|
26
|
+
* - Business: `{siteOrigin}/.well-known/entity/business`
|
|
27
|
+
* - Offering: `{siteOrigin}/.well-known/entity/offering/{entityId}`
|
|
28
|
+
*
|
|
29
|
+
* The `siteOrigin` is stripped of trailing slashes to produce a clean base.
|
|
30
|
+
* When `siteOrigin` is absent or empty, the function returns `undefined` —
|
|
31
|
+
* callers should skip emitting `@id` in that case.
|
|
32
|
+
*
|
|
33
|
+
* @param siteOrigin - The site origin URL (e.g. `https://example.com`)
|
|
34
|
+
* @param type - The entity type (`"business"` or `"offering"`)
|
|
35
|
+
* @param entityId - The entity ID (required for `"offering"`, ignored for `"business"`)
|
|
36
|
+
* @returns The canonical URI string, or `undefined` when `siteOrigin` is absent
|
|
37
|
+
*/
|
|
38
|
+
export function deriveCanonicalUri(
|
|
39
|
+
siteOrigin: string | undefined,
|
|
40
|
+
type: CanonicalEntityType,
|
|
41
|
+
entityId?: string,
|
|
42
|
+
): string | undefined {
|
|
43
|
+
if (!siteOrigin) return undefined;
|
|
44
|
+
|
|
45
|
+
const base = siteOrigin.replace(/\/+$/, "");
|
|
46
|
+
|
|
47
|
+
if (type === "business") {
|
|
48
|
+
return `${base}/.well-known/entity/business`;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (!entityId) return undefined;
|
|
52
|
+
|
|
53
|
+
return `${base}/.well-known/entity/offering/${entityId}`;
|
|
54
|
+
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
</MODULE_CONTRACT>
|
|
8
8
|
<CHANGE_SUMMARY>
|
|
9
9
|
<item>RFC-0133: backfilled MODULE_MAP and CHANGE_SUMMARY markers for compass.validate compliance.</item>
|
|
10
|
-
<item>RFC-0915: removed custom slugify() — replaced by slugId from @warpgogol/werkstatt-shared/
|
|
10
|
+
<item>RFC-0915: removed custom slugify() — replaced by slugId from @warpgogol/werkstatt-shared/slug.</item>
|
|
11
11
|
</CHANGE_SUMMARY>
|
|
12
12
|
*/
|
|
13
13
|
|
|
@@ -160,6 +160,105 @@ export function splitSentences(text: string, locale: string = "en"): string[] {
|
|
|
160
160
|
return sentences.filter(Boolean);
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
+
export type MarkdownList = {
|
|
164
|
+
marker: "-" | "*" | "+" | "digit";
|
|
165
|
+
items: string[];
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const LIST_MARKER_PATTERNS: Array<{ marker: MarkdownList["marker"]; regex: RegExp }> = [
|
|
169
|
+
{ marker: "-", regex: /^-\s+/ },
|
|
170
|
+
{ marker: "*", regex: /^\*\s+/ },
|
|
171
|
+
{ marker: "+", regex: /^\+\s+/ },
|
|
172
|
+
{ marker: "digit", regex: /^\d+\.\s+/ },
|
|
173
|
+
];
|
|
174
|
+
|
|
175
|
+
function matchListMarker(
|
|
176
|
+
line: string,
|
|
177
|
+
): { marker: MarkdownList["marker"]; text: string } | undefined {
|
|
178
|
+
for (const { marker, regex } of LIST_MARKER_PATTERNS) {
|
|
179
|
+
const match = line.match(regex);
|
|
180
|
+
if (match) {
|
|
181
|
+
return { marker, text: line.slice(match[0].length).trim() };
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return undefined;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function isTopLevelListLine(
|
|
188
|
+
line: string,
|
|
189
|
+
): { marker: MarkdownList["marker"]; text: string } | undefined {
|
|
190
|
+
// Top-level: no leading whitespace before the marker
|
|
191
|
+
if (/^\s/.test(line)) return undefined;
|
|
192
|
+
return matchListMarker(line);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function isIndentedListLine(line: string): boolean {
|
|
196
|
+
// Indented list line: starts with whitespace + list marker
|
|
197
|
+
if (!/^\s/.test(line)) return false;
|
|
198
|
+
const trimmed = line.trimStart();
|
|
199
|
+
return LIST_MARKER_PATTERNS.some(({ regex }) => regex.test(trimmed));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export function extractLists(markdown: string): MarkdownList[] {
|
|
203
|
+
const normalized = markdown.trim();
|
|
204
|
+
if (!normalized) return [];
|
|
205
|
+
|
|
206
|
+
const lines = normalized.split("\n");
|
|
207
|
+
const lists: MarkdownList[] = [];
|
|
208
|
+
let currentList: MarkdownList | null = null;
|
|
209
|
+
let inCodeFence = false;
|
|
210
|
+
|
|
211
|
+
for (const line of lines) {
|
|
212
|
+
// Track fenced code blocks
|
|
213
|
+
if (line.trimStart().startsWith("```")) {
|
|
214
|
+
inCodeFence = !inCodeFence;
|
|
215
|
+
if (currentList) {
|
|
216
|
+
lists.push(currentList);
|
|
217
|
+
currentList = null;
|
|
218
|
+
}
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (inCodeFence) {
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const topMatch = isTopLevelListLine(line);
|
|
227
|
+
|
|
228
|
+
if (topMatch) {
|
|
229
|
+
// Continue current list if same marker type
|
|
230
|
+
if (currentList && currentList.marker === topMatch.marker) {
|
|
231
|
+
currentList.items.push(topMatch.text);
|
|
232
|
+
} else {
|
|
233
|
+
// Different marker or first list — flush previous, start new
|
|
234
|
+
if (currentList) {
|
|
235
|
+
lists.push(currentList);
|
|
236
|
+
}
|
|
237
|
+
currentList = { marker: topMatch.marker, items: [topMatch.text] };
|
|
238
|
+
}
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Indented list line — part of parent item, not a new item
|
|
243
|
+
if (isIndentedListLine(line)) {
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Non-list line (blank, prose, heading, etc.) — terminate current list
|
|
248
|
+
if (currentList) {
|
|
249
|
+
lists.push(currentList);
|
|
250
|
+
currentList = null;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Flush trailing list
|
|
255
|
+
if (currentList) {
|
|
256
|
+
lists.push(currentList);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return lists;
|
|
260
|
+
}
|
|
261
|
+
|
|
163
262
|
export function extractListFacts(markdown: string): string[] {
|
|
164
263
|
return markdown
|
|
165
264
|
.split("\n")
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { describe, test, expect } from "vitest";
|
|
2
|
+
import { normalizeFactValue, type CanonicalFact } from "./fact-extraction.ts";
|
|
3
|
+
|
|
4
|
+
describe("fact-extraction: normalizeFactValue", () => {
|
|
5
|
+
test("normalizes email to lowercase", () => {
|
|
6
|
+
expect(normalizeFactValue("email", "Info@Test.COM")).toBe("info@test.com");
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
test("normalizes phone by stripping tel: prefix and separators", () => {
|
|
10
|
+
expect(normalizeFactValue("phone", "tel:+49 30 123-4567")).toBe("+49301234567");
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test("normalizes phone by stripping spaces, hyphens, and parentheses", () => {
|
|
14
|
+
expect(normalizeFactValue("phone", "+49 (30) 123-4567")).toBe("+49301234567");
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test("trims whitespace for other types", () => {
|
|
18
|
+
expect(normalizeFactValue("price", " 2900 ")).toBe("2900");
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test("trims whitespace for name", () => {
|
|
22
|
+
expect(normalizeFactValue("name", " Test Business ")).toBe("Test Business");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("handles empty string", () => {
|
|
26
|
+
expect(normalizeFactValue("email", "")).toBe("");
|
|
27
|
+
expect(normalizeFactValue("phone", "")).toBe("");
|
|
28
|
+
expect(normalizeFactValue("price", "")).toBe("");
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
describe("fact-extraction: CanonicalFact interface", () => {
|
|
33
|
+
test("CanonicalFact can be constructed with all fields", () => {
|
|
34
|
+
const fact: CanonicalFact = {
|
|
35
|
+
type: "price",
|
|
36
|
+
entityId: "offering-1",
|
|
37
|
+
entityType: "offering",
|
|
38
|
+
value: "2900",
|
|
39
|
+
surface: "canonical",
|
|
40
|
+
source: "pbp",
|
|
41
|
+
};
|
|
42
|
+
expect(fact.type).toBe("price");
|
|
43
|
+
expect(fact.entityId).toBe("offering-1");
|
|
44
|
+
expect(fact.value).toBe("2900");
|
|
45
|
+
expect(fact.surface).toBe("canonical");
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>RFC-1077: Canonical fact interface and normalization utility for cross-surface fact parity validation. Shared between werkstatt-shared (contract) and werkstatt-site (extraction logic).</purpose>
|
|
4
|
+
<non-goals>
|
|
5
|
+
<item>Do not import from werkstatt-site — this package must not depend on the site plugin.</item>
|
|
6
|
+
<item>Do not implement fact extraction — that lives in werkstatt-site where PbpResolvedGraph is available.</item>
|
|
7
|
+
</non-goals>
|
|
8
|
+
</MODULE_CONTRACT>
|
|
9
|
+
<CHANGE_SUMMARY>
|
|
10
|
+
<item>RFC-1077: initial implementation — CanonicalFact interface and normalizeFactValue.</item>
|
|
11
|
+
</CHANGE_SUMMARY>
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** RFC-1077: A canonical fact extracted from the PBP resolved graph or a rendered surface. */
|
|
15
|
+
export interface CanonicalFact {
|
|
16
|
+
/** Fact type: price, address, email, foundingYear, representative, phone, name. */
|
|
17
|
+
type: string;
|
|
18
|
+
/** Entity ID the fact belongs to (e.g. offering ID, business ID, place ID). */
|
|
19
|
+
entityId: string;
|
|
20
|
+
/** Entity type: business, offering, place, contactPoint. */
|
|
21
|
+
entityType: string;
|
|
22
|
+
/** The canonical value as a string (normalized for comparison). */
|
|
23
|
+
value: string;
|
|
24
|
+
/** The surface where this fact was found: html, llms-full, jsonld, canonical. */
|
|
25
|
+
surface: string;
|
|
26
|
+
/** Source file path or URL where the fact was found. */
|
|
27
|
+
source: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** RFC-1077: Normalize a fact value for comparison across surfaces. */
|
|
31
|
+
export function normalizeFactValue(type: string, value: string): string {
|
|
32
|
+
const trimmed = value.trim();
|
|
33
|
+
if (type === "email") return trimmed.toLowerCase();
|
|
34
|
+
if (type === "phone") return trimmed.replace(/^tel:/, "").replace(/[\s\-()]/g, "");
|
|
35
|
+
if (type === "price") {
|
|
36
|
+
let stripped = trimmed.replace(/\s*(EUR|USD|GBP|CHF|UAH|€|\$|£|₴)\s*$/i, "");
|
|
37
|
+
// Handle German thousands separator: "2.000" → "2000", "1.040" → "1040"
|
|
38
|
+
stripped = stripped.replace(/(\d)\.(\d{3})(?!\d)/g, "$1$2");
|
|
39
|
+
// Handle space thousands separator: "2 000" → "2000"
|
|
40
|
+
stripped = stripped.replace(/(\d)\s(\d{3})(?!\d)/g, "$1$2");
|
|
41
|
+
const num = parseFloat(stripped);
|
|
42
|
+
if (!isNaN(num)) return String(num);
|
|
43
|
+
return stripped;
|
|
44
|
+
}
|
|
45
|
+
return trimmed;
|
|
46
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>
|
|
4
|
+
RFC-1078: Pure freshness calculation functions for semantic.freshness.validate.
|
|
5
|
+
Provides calculateAgeDays, isAssessmentStale, isItemStale, and the FreshnessViolation
|
|
6
|
+
interface. All functions are pure and deterministic for a fixed reference date.
|
|
7
|
+
</purpose>
|
|
8
|
+
<non-goals>
|
|
9
|
+
<item>Does not compile PBP profiles — that is the validator's job in werkstatt-site.</item>
|
|
10
|
+
<item>Does not emit diagnostics — the validator collects violations and emits them.</item>
|
|
11
|
+
</non-goals>
|
|
12
|
+
</MODULE_CONTRACT>
|
|
13
|
+
<CHANGE_SUMMARY>
|
|
14
|
+
<item>RFC-1078: initial — calculateAgeDays, isAssessmentStale, isItemStale, FreshnessViolation, DEFAULT_FRESHNESS_WINDOW_DAYS.</item>
|
|
15
|
+
</CHANGE_SUMMARY>
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** RFC-1078: Default freshness window for evidence items without a declared maxAgeDays. */
|
|
19
|
+
export const DEFAULT_FRESHNESS_WINDOW_DAYS = 180;
|
|
20
|
+
|
|
21
|
+
/** RFC-1078: A freshness violation detected by semantic.freshness.validate. */
|
|
22
|
+
export interface FreshnessViolation {
|
|
23
|
+
rule: string;
|
|
24
|
+
entityType: string;
|
|
25
|
+
entityId: string;
|
|
26
|
+
/** The field that is stale: assessment.observedAt, items[].retrievedAt, etc. */
|
|
27
|
+
field: string;
|
|
28
|
+
/** The observed timestamp. */
|
|
29
|
+
observedAt: string;
|
|
30
|
+
/** The maximum age in days. */
|
|
31
|
+
maxAgeDays: number;
|
|
32
|
+
/** The actual age in days at validation time. */
|
|
33
|
+
actualAgeDays: number;
|
|
34
|
+
message: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* RFC-1078: Calculate age in days from an ISO timestamp to a reference date.
|
|
39
|
+
* Pure and deterministic for a fixed reference date.
|
|
40
|
+
* Returns Number.MAX_SAFE_INTEGER for invalid date strings.
|
|
41
|
+
*/
|
|
42
|
+
export function calculateAgeDays(observedAt: string, referenceDate: Date = new Date()): number {
|
|
43
|
+
const observed = new Date(observedAt);
|
|
44
|
+
if (isNaN(observed.getTime())) return Number.MAX_SAFE_INTEGER;
|
|
45
|
+
const diffMs = referenceDate.getTime() - observed.getTime();
|
|
46
|
+
return Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** RFC-1078: Check if a technical assessment is stale. Pure. */
|
|
50
|
+
export function isAssessmentStale(
|
|
51
|
+
assessment: { observedAt: string; freshness: { maxAgeDays: number } },
|
|
52
|
+
referenceDate: Date = new Date(),
|
|
53
|
+
): boolean {
|
|
54
|
+
const ageDays = calculateAgeDays(assessment.observedAt, referenceDate);
|
|
55
|
+
return ageDays > assessment.freshness.maxAgeDays;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** RFC-1078: Check if an evidence item is stale. Pure. Returns false if retrievedAt is missing. */
|
|
59
|
+
export function isItemStale(
|
|
60
|
+
item: { retrievedAt?: string },
|
|
61
|
+
maxAgeDays: number,
|
|
62
|
+
referenceDate: Date = new Date(),
|
|
63
|
+
): boolean {
|
|
64
|
+
if (!item.retrievedAt) return false;
|
|
65
|
+
const ageDays = calculateAgeDays(item.retrievedAt, referenceDate);
|
|
66
|
+
return ageDays > maxAgeDays;
|
|
67
|
+
}
|
|
@@ -7,8 +7,13 @@
|
|
|
7
7
|
</non-goals>
|
|
8
8
|
</MODULE_CONTRACT>
|
|
9
9
|
<CHANGE_SUMMARY>
|
|
10
|
-
<item>Moved from app semantic/ids to packages/share/src/semantic/ids.ts — framework-agnostic, reusable across all apps.</item>
|
|
11
10
|
<item>RFC-0910: add canonicalRootUrl — unprefixed root URL for entity identity (Organization.url, WebSite.url).</item>
|
|
11
|
+
<item>RFC-1097: step 6 — compass.migrate codemod run
|
|
12
|
+
|
|
13
|
+
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>
|
|
14
|
+
<item>RFC-1097: sweep — werkstatt-engine clean
|
|
15
|
+
|
|
16
|
+
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>
|
|
12
17
|
</CHANGE_SUMMARY>
|
|
13
18
|
*/
|
|
14
19
|
|
|
@@ -6,7 +6,12 @@
|
|
|
6
6
|
</non-goals>
|
|
7
7
|
</MODULE_CONTRACT>
|
|
8
8
|
<CHANGE_SUMMARY>
|
|
9
|
-
<item>
|
|
9
|
+
<item>RFC-1097: step 6 — compass.migrate codemod run
|
|
10
|
+
|
|
11
|
+
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>
|
|
12
|
+
<item>RFC-1097: sweep — werkstatt-engine clean
|
|
13
|
+
|
|
14
|
+
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>
|
|
10
15
|
</CHANGE_SUMMARY>
|
|
11
16
|
*/
|
|
12
17
|
|
|
@@ -32,5 +37,7 @@ export * from "./build-page.ts";
|
|
|
32
37
|
export * from "./block-extraction.ts";
|
|
33
38
|
export * from "./block-extractors/index.ts";
|
|
34
39
|
export * from "./update-stamp.ts";
|
|
35
|
-
export * from "./markdown-twin-provenance.ts";
|
|
36
40
|
export * from "./price-marker-resolver.ts";
|
|
41
|
+
export * from "./canonical-uri.ts";
|
|
42
|
+
export * from "./fact-extraction.ts";
|
|
43
|
+
export * from "./freshness.ts";
|
|
@@ -6,8 +6,12 @@
|
|
|
6
6
|
</non-goals>
|
|
7
7
|
</MODULE_CONTRACT>
|
|
8
8
|
<CHANGE_SUMMARY>
|
|
9
|
-
<item>
|
|
10
|
-
|
|
9
|
+
<item>RFC-1097: step 6 — compass.migrate codemod run
|
|
10
|
+
|
|
11
|
+
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>
|
|
12
|
+
<item>RFC-1097: sweep — werkstatt-engine clean
|
|
13
|
+
|
|
14
|
+
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>
|
|
11
15
|
</CHANGE_SUMMARY>
|
|
12
16
|
*/
|
|
13
17
|
|
|
@@ -7,8 +7,12 @@
|
|
|
7
7
|
</non-goals>
|
|
8
8
|
</MODULE_CONTRACT>
|
|
9
9
|
<CHANGE_SUMMARY>
|
|
10
|
-
<item>
|
|
11
|
-
|
|
10
|
+
<item>RFC-1097: step 6 — compass.migrate codemod run
|
|
11
|
+
|
|
12
|
+
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>
|
|
13
|
+
<item>RFC-1097: sweep — werkstatt-engine clean
|
|
14
|
+
|
|
15
|
+
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>
|
|
12
16
|
</CHANGE_SUMMARY>
|
|
13
17
|
*/
|
|
14
18
|
|
|
@@ -6,8 +6,12 @@
|
|
|
6
6
|
</non-goals>
|
|
7
7
|
</MODULE_CONTRACT>
|
|
8
8
|
<CHANGE_SUMMARY>
|
|
9
|
-
<item>
|
|
10
|
-
|
|
9
|
+
<item>RFC-1097: step 6 — compass.migrate codemod run
|
|
10
|
+
|
|
11
|
+
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>
|
|
12
|
+
<item>RFC-1097: sweep — werkstatt-engine clean
|
|
13
|
+
|
|
14
|
+
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>
|
|
11
15
|
</CHANGE_SUMMARY>
|
|
12
16
|
*/
|
|
13
17
|
|
|
@@ -6,7 +6,12 @@
|
|
|
6
6
|
</non-goals>
|
|
7
7
|
</MODULE_CONTRACT>
|
|
8
8
|
<CHANGE_SUMMARY>
|
|
9
|
-
<item>
|
|
9
|
+
<item>RFC-1097: step 6 — compass.migrate codemod run
|
|
10
|
+
|
|
11
|
+
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>
|
|
12
|
+
<item>RFC-1097: sweep — werkstatt-engine clean
|
|
13
|
+
|
|
14
|
+
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>
|
|
10
15
|
</CHANGE_SUMMARY>
|
|
11
16
|
*/
|
|
12
17
|
|
|
@@ -7,7 +7,12 @@
|
|
|
7
7
|
</non-goals>
|
|
8
8
|
</MODULE_CONTRACT>
|
|
9
9
|
<CHANGE_SUMMARY>
|
|
10
|
-
<item>
|
|
10
|
+
<item>RFC-1097: step 6 — compass.migrate codemod run
|
|
11
|
+
|
|
12
|
+
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>
|
|
13
|
+
<item>RFC-1097: sweep — werkstatt-engine clean
|
|
14
|
+
|
|
15
|
+
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>
|
|
11
16
|
</CHANGE_SUMMARY>
|
|
12
17
|
*/
|
|
13
18
|
|
|
@@ -6,9 +6,13 @@
|
|
|
6
6
|
</non-goals>
|
|
7
7
|
</MODULE_CONTRACT>
|
|
8
8
|
<CHANGE_SUMMARY>
|
|
9
|
-
<item>Added Person JSON-LD generation for organization members.</item>
|
|
10
|
-
<item>Moved from app semantic/jsonld/person to packages/share.</item>
|
|
11
9
|
<item>RFC-0512: emit address, knowsAbout, affiliation when present on SemanticPerson.</item>
|
|
10
|
+
<item>RFC-1097: step 6 — compass.migrate codemod run
|
|
11
|
+
|
|
12
|
+
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>
|
|
13
|
+
<item>RFC-1097: sweep — werkstatt-engine clean
|
|
14
|
+
|
|
15
|
+
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>
|
|
12
16
|
</CHANGE_SUMMARY>
|
|
13
17
|
*/
|
|
14
18
|
|
|
@@ -6,9 +6,13 @@
|
|
|
6
6
|
</non-goals>
|
|
7
7
|
</MODULE_CONTRACT>
|
|
8
8
|
<CHANGE_SUMMARY>
|
|
9
|
-
<item>Added Service JSON-LD generation.</item>
|
|
10
|
-
<item>Moved from app semantic/jsonld/service to packages/share.</item>
|
|
11
9
|
<item>RFC-0498: extend buildServiceNodes to gate Service emission by per-depth policy for all surface depths (website-local depth-1, website-service depth-1, website-local depth-5).</item>
|
|
10
|
+
<item>RFC-1097: step 6 — compass.migrate codemod run
|
|
11
|
+
|
|
12
|
+
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>
|
|
13
|
+
<item>RFC-1097: sweep — werkstatt-engine clean
|
|
14
|
+
|
|
15
|
+
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>
|
|
12
16
|
</CHANGE_SUMMARY>
|
|
13
17
|
*/
|
|
14
18
|
|