@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
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/*
|
|
2
2
|
<MODULE_CONTRACT>
|
|
3
3
|
<purpose>RFC-0176: verify the inbound/queue runtime — authenticateInbound, IntegrationEventSchema,
|
|
4
|
-
routeEventToReady (self-enabling
|
|
4
|
+
routeEventToReady (self-enabling Lagebild route), and consumeIntegrationBatch dedup via a KV-backed
|
|
5
5
|
seen-set. fetch + KV are stubbed so the full producer→consumer flow is exercised without Cloudflare.</purpose>
|
|
6
6
|
<responsibilities>
|
|
7
|
-
<item>Assert a valid event routes once to the
|
|
7
|
+
<item>Assert a valid event routes once to the lagebild gogol-adapter destination.</item>
|
|
8
8
|
<item>Assert a queue redelivery is deduped (no double-write) via the KV seen-set.</item>
|
|
9
9
|
<item>Assert inbound auth + event-shape validation are fail-closed.</item>
|
|
10
10
|
</responsibilities>
|
|
@@ -14,6 +14,7 @@ seen-set. fetch + KV are stubbed so the full producer→consumer flow is exercis
|
|
|
14
14
|
</MODULE_CONTRACT>
|
|
15
15
|
<CHANGE_SUMMARY>
|
|
16
16
|
<item>RFC-0176: initial queue/inbound runtime test.</item>
|
|
17
|
+
<item>Lagebild replaced Pipedrive as sole CRM destination — test updated accordingly.</item>
|
|
17
18
|
</CHANGE_SUMMARY>
|
|
18
19
|
*/
|
|
19
20
|
|
|
@@ -30,8 +31,10 @@ import {
|
|
|
30
31
|
} from "../index.ts";
|
|
31
32
|
|
|
32
33
|
const SECRETS: IntegrationSecrets = {
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
LAGEBILD_API_URL: "https://lagebild-api.example.workers.dev",
|
|
35
|
+
LAGEBILD_API_KEY: "lbk_test_key_0001",
|
|
36
|
+
LAGEBILD_TENANT_ID: "ten_warpgogol000001",
|
|
37
|
+
LAGEBILD_SOURCE_SYSTEM_ID: "site_warpgogol_com",
|
|
35
38
|
};
|
|
36
39
|
|
|
37
40
|
const EVENT: IntegrationEvent = {
|
|
@@ -63,13 +66,18 @@ const realFetch = globalThis.fetch;
|
|
|
63
66
|
|
|
64
67
|
beforeEach(() => {
|
|
65
68
|
fetchCalls = [];
|
|
66
|
-
// Stub
|
|
69
|
+
// Stub Lagebild ingress endpoint — returns accepted with a submission id.
|
|
67
70
|
globalThis.fetch = (async (url: string | URL | Request) => {
|
|
68
71
|
fetchCalls.push(String(url));
|
|
69
72
|
return {
|
|
70
73
|
ok: true,
|
|
71
74
|
status: 200,
|
|
72
|
-
json: async () => ({
|
|
75
|
+
json: async () => ({
|
|
76
|
+
submission_id: "sub_test123",
|
|
77
|
+
accepted: true,
|
|
78
|
+
is_replay: false,
|
|
79
|
+
correlation_id: null,
|
|
80
|
+
}),
|
|
73
81
|
} as unknown as Response;
|
|
74
82
|
}) as typeof fetch;
|
|
75
83
|
});
|
|
@@ -78,17 +86,17 @@ afterEach(() => {
|
|
|
78
86
|
globalThis.fetch = realFetch;
|
|
79
87
|
});
|
|
80
88
|
|
|
81
|
-
test("routeEventToReady routes a lead to the
|
|
89
|
+
test("routeEventToReady routes a lead to the lagebild gogol-adapter destination", async () => {
|
|
82
90
|
const result = await routeEventToReady(EVENT, SECRETS);
|
|
83
|
-
expect(result.routed).toEqual(["crm:
|
|
91
|
+
expect(result.routed).toEqual(["crm:lagebild"]);
|
|
84
92
|
expect(result.failed.length).toBe(0);
|
|
85
|
-
//
|
|
86
|
-
expect(fetchCalls.length).toBe(
|
|
93
|
+
// lagebild adapter performs a single POST to /v1/ingress.
|
|
94
|
+
expect(fetchCalls.length).toBe(1);
|
|
87
95
|
});
|
|
88
96
|
|
|
89
97
|
test("routeEventToReady skips when destination secrets are absent", async () => {
|
|
90
98
|
const result = await routeEventToReady(EVENT, {});
|
|
91
|
-
expect(result.skipped).toEqual(["crm:
|
|
99
|
+
expect(result.skipped).toEqual(["crm:lagebild"]);
|
|
92
100
|
expect(result.routed.length).toBe(0);
|
|
93
101
|
expect(fetchCalls.length).toBe(0);
|
|
94
102
|
});
|
|
@@ -98,13 +106,13 @@ test("consumeIntegrationBatch dedups a queue redelivery via KV (no double-write)
|
|
|
98
106
|
const dedup = kvDedup(kv);
|
|
99
107
|
|
|
100
108
|
const first = await consumeIntegrationBatch([EVENT], SECRETS, dedup);
|
|
101
|
-
expect(first[0].routed).toEqual(["crm:
|
|
109
|
+
expect(first[0].routed).toEqual(["crm:lagebild"]);
|
|
102
110
|
const afterFirst = fetchCalls.length;
|
|
103
|
-
expect(afterFirst).toBe(
|
|
111
|
+
expect(afterFirst).toBe(1);
|
|
104
112
|
|
|
105
113
|
// Redeliver the SAME eventId — must be skipped by dedup, no new fetches.
|
|
106
114
|
const second = await consumeIntegrationBatch([EVENT], SECRETS, dedup);
|
|
107
|
-
expect(second[0].skipped).toEqual(["crm:
|
|
115
|
+
expect(second[0].skipped).toEqual(["crm:lagebild"]);
|
|
108
116
|
expect(fetchCalls.length).toBe(afterFirst);
|
|
109
117
|
expect(kv.size()).toBe(1);
|
|
110
118
|
});
|
|
@@ -3,6 +3,14 @@ import { defineConfig } from "vitest/config";
|
|
|
3
3
|
export default defineConfig({
|
|
4
4
|
test: {
|
|
5
5
|
environment: "node",
|
|
6
|
+
testTimeout: 30_000,
|
|
6
7
|
include: ["src/**/*.test.ts"],
|
|
8
|
+
coverage: {
|
|
9
|
+
provider: "v8",
|
|
10
|
+
reporter: ["json", "json-summary", "text-summary", "html"],
|
|
11
|
+
reportsDirectory: "../../.coverage/integration",
|
|
12
|
+
include: ["src/integration/**/*.ts"],
|
|
13
|
+
exclude: ["src/integration/**/*.test.ts", "src/integration/**/*.d.ts"],
|
|
14
|
+
},
|
|
7
15
|
},
|
|
8
16
|
});
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>
|
|
4
|
+
Desired-state composition types for RFC-1038. Defines the declarative target
|
|
5
|
+
(DesiredState), the runtime actual state (ActualState, replacing KernelRegistry),
|
|
6
|
+
component/command/pipeline declarations, and the module export shape that
|
|
7
|
+
replaces KernelModule.register().
|
|
8
|
+
</purpose>
|
|
9
|
+
<non-goals>
|
|
10
|
+
<item>Does not implement reconciliation logic — see reconciler.ts.</item>
|
|
11
|
+
<item>Does not implement overlay resolution — see overlay.ts.</item>
|
|
12
|
+
<item>Does not define Zod schemas — see component/schemas.ts.</item>
|
|
13
|
+
</non-goals>
|
|
14
|
+
</MODULE_CONTRACT>
|
|
15
|
+
<CHANGE_SUMMARY>
|
|
16
|
+
<item>RFC-1038: initial implementation — desired-state composition types replacing ComponentManifestV1, KernelModule, KernelRegistry.</item>
|
|
17
|
+
</CHANGE_SUMMARY>
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import type { Sha256Digest } from "../fingerprint/primitives.ts";
|
|
21
|
+
import type { ComponentScope, ScopeContext, ComponentDeclaration } from "../component/contracts.ts";
|
|
22
|
+
import type {
|
|
23
|
+
KernelFlagSpec,
|
|
24
|
+
GeneratedArtifactSpec,
|
|
25
|
+
KernelPipelineStep,
|
|
26
|
+
KernelCommandMetadata,
|
|
27
|
+
KernelCommandInput,
|
|
28
|
+
KernelRuntimeContext,
|
|
29
|
+
KernelCommandResult,
|
|
30
|
+
ModuleFiberState,
|
|
31
|
+
} from "./types.ts";
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Unified component type — replaces ComponentManifestV1.
|
|
35
|
+
* Re-exported from contracts.ts for convenience.
|
|
36
|
+
*/
|
|
37
|
+
export type { ComponentDeclaration };
|
|
38
|
+
|
|
39
|
+
export interface DesiredState {
|
|
40
|
+
/** Stable component declarations keyed by componentId. Map for O(1) lookup. */
|
|
41
|
+
components: Map<string, ComponentDeclaration>;
|
|
42
|
+
/** Capability contracts that must be satisfied. */
|
|
43
|
+
requiredCapabilities: string[];
|
|
44
|
+
/** Available artifacts for resolution. */
|
|
45
|
+
availableArtifacts: ReadonlyMap<string, Sha256Digest>;
|
|
46
|
+
/** Admitted grants for resolution. */
|
|
47
|
+
admittedGrants: ReadonlyArray<{ scope: string; resource: string }>;
|
|
48
|
+
/** Profile ID for resolution. */
|
|
49
|
+
profileId: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface ReconciliationDelta {
|
|
53
|
+
/** Components to activate (present in desired, absent in actual). */
|
|
54
|
+
toActivate: ComponentDeclaration[];
|
|
55
|
+
/** Components to deactivate (absent in desired, present in actual). */
|
|
56
|
+
toDeactivate: string[];
|
|
57
|
+
/** Components to reconfigure (present in both, but config changed). */
|
|
58
|
+
toReconfigure: Array<{
|
|
59
|
+
id: string;
|
|
60
|
+
oldConfig: Record<string, unknown>;
|
|
61
|
+
newConfig: Record<string, unknown>;
|
|
62
|
+
}>;
|
|
63
|
+
/** Components unchanged (present in both, config identical). */
|
|
64
|
+
unchanged: string[];
|
|
65
|
+
/** Missing dependencies — required capabilities with no provider. */
|
|
66
|
+
missingDependencies: Array<{ capability: string; requiredBy: string }>;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface ReconciliationResult {
|
|
70
|
+
delta: ReconciliationDelta;
|
|
71
|
+
applied: boolean;
|
|
72
|
+
/** Components that failed to activate. */
|
|
73
|
+
failures: Array<{ id: string; reason: string }>;
|
|
74
|
+
/** Time taken to reconcile, in milliseconds. */
|
|
75
|
+
durationMs: number;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Command declaration — replaces KernelCommandDefinition for registration.
|
|
80
|
+
* Carries ALL metadata fields from KernelCommandDefinition plus the execute function.
|
|
81
|
+
* Type safety is preserved: execute receives typed KernelCommandInput and KernelRuntimeContext.
|
|
82
|
+
*/
|
|
83
|
+
export interface CommandDeclaration extends KernelCommandMetadata {
|
|
84
|
+
/** Command name — e.g. "sternsystem.validate". */
|
|
85
|
+
name: string;
|
|
86
|
+
/** RFC-0260: declared flag schema. */
|
|
87
|
+
flags?: Record<string, KernelFlagSpec>;
|
|
88
|
+
/** RFC-0266: workspace-root-relative path globs this command reads. */
|
|
89
|
+
reads?: string[];
|
|
90
|
+
/** RFC-0266: workspace-root-relative path globs this command writes. */
|
|
91
|
+
writes?: string[];
|
|
92
|
+
/** RFC-0637: paths relative to module src/ for cache hashing. */
|
|
93
|
+
modulePaths?: string[];
|
|
94
|
+
/** RFC-0687: command names whose outputs this validator checks. */
|
|
95
|
+
validatesOutputs?: string[];
|
|
96
|
+
/** RFC-0960: repo-relative path to the implementing source file. */
|
|
97
|
+
modulePath?: string;
|
|
98
|
+
/** RFC-0960: declared generated artifacts. */
|
|
99
|
+
generates?: GeneratedArtifactSpec[];
|
|
100
|
+
/** RFC-0963: the single contract this validator enforces. */
|
|
101
|
+
contract?: string;
|
|
102
|
+
/** RFC-0963: the rule IDs this validator enforces. */
|
|
103
|
+
rules?: string[];
|
|
104
|
+
/** The execute function — typed, same signature as KernelCommandDefinition.execute. */
|
|
105
|
+
execute: (
|
|
106
|
+
input: KernelCommandInput,
|
|
107
|
+
context: KernelRuntimeContext,
|
|
108
|
+
) => Promise<void | KernelCommandResult> | void | KernelCommandResult;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Pipeline declaration — replaces registerPipeline() calls.
|
|
113
|
+
* Carries the pipeline name and steps with all KernelPipelineStep fields.
|
|
114
|
+
*/
|
|
115
|
+
export interface PipelineDeclaration {
|
|
116
|
+
/** Pipeline name — e.g. "packages.check". */
|
|
117
|
+
name: string;
|
|
118
|
+
/** Pipeline steps with command references, args, timeouts, and dependsOn (RFC-0686). */
|
|
119
|
+
steps: KernelPipelineStep[];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Module export — replaces KernelModule.
|
|
124
|
+
* Each *.module.ts file exports this object instead of calling register().
|
|
125
|
+
* The reconciler reads declarations, commands, and pipelines from this export.
|
|
126
|
+
*/
|
|
127
|
+
export interface ModuleExport {
|
|
128
|
+
/** Module name — e.g. "sternsystem". */
|
|
129
|
+
name: string;
|
|
130
|
+
/** Module version. */
|
|
131
|
+
version: string;
|
|
132
|
+
/** Component declarations for desired-state composition. */
|
|
133
|
+
declarations: ComponentDeclaration[];
|
|
134
|
+
/**
|
|
135
|
+
* Command declarations — replaces registerCommand() calls.
|
|
136
|
+
* execute functions may lazy-load implementations via `await import()`
|
|
137
|
+
* inside the execute body, preserving the current lazy-loading pattern.
|
|
138
|
+
*/
|
|
139
|
+
commands: CommandDeclaration[];
|
|
140
|
+
/** Pipeline declarations — replaces registerPipeline() calls. */
|
|
141
|
+
pipelines: PipelineDeclaration[];
|
|
142
|
+
/**
|
|
143
|
+
* Optional conditional declaration builder.
|
|
144
|
+
* Replaces conditional registration logic in register() bodies.
|
|
145
|
+
* Receives the runtime context (env vars, profile, etc.) and returns
|
|
146
|
+
* additional or modified declarations/commands/pipelines.
|
|
147
|
+
* This runs at startup before reconciliation, not at registration time.
|
|
148
|
+
*/
|
|
149
|
+
conditionalBuilder?: (context: ModuleBuildContext) => {
|
|
150
|
+
declarations?: ComponentDeclaration[];
|
|
151
|
+
commands?: CommandDeclaration[];
|
|
152
|
+
pipelines?: PipelineDeclaration[];
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Build context passed to conditionalBuilder.
|
|
158
|
+
* Provides environment and profile information for conditional declarations.
|
|
159
|
+
*/
|
|
160
|
+
export interface ModuleBuildContext {
|
|
161
|
+
/** Environment variables (process.env snapshot). */
|
|
162
|
+
env: Record<string, string | undefined>;
|
|
163
|
+
/** Profile ID from kernel config. */
|
|
164
|
+
profileId: string;
|
|
165
|
+
/** Whether this is a long-running process (dev server, watch mode). */
|
|
166
|
+
longRunning: boolean;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Actual state — replaces KernelRegistry entirely.
|
|
171
|
+
* The desired state is the declarative target; the actual state is what's
|
|
172
|
+
* currently running. The reconciler updates actual state to match desired state.
|
|
173
|
+
* Command execution reads from actual state — no separate registry needed.
|
|
174
|
+
*
|
|
175
|
+
* Commands and pipelines are always available — they're the module's interface,
|
|
176
|
+
* not dynamically activated. They're populated once at startup from ModuleExport[]
|
|
177
|
+
* and never change. The reconciler only manages components (capabilities and effects).
|
|
178
|
+
* A command may check component state at execution time if it depends on a capability.
|
|
179
|
+
*/
|
|
180
|
+
export interface ActualState {
|
|
181
|
+
/** Active components with their runtime fiber state, keyed by componentId. */
|
|
182
|
+
components: ReadonlyMap<string, { declaration: ComponentDeclaration; state: ModuleFiberState }>;
|
|
183
|
+
/**
|
|
184
|
+
* All declared commands from all ModuleExport[], keyed by command name.
|
|
185
|
+
* Populated once at startup, never changes.
|
|
186
|
+
*/
|
|
187
|
+
commands: ReadonlyMap<string, CommandDeclaration>;
|
|
188
|
+
/**
|
|
189
|
+
* All declared pipelines from all ModuleExport[], keyed by pipeline name.
|
|
190
|
+
* Populated once at startup, never changes.
|
|
191
|
+
*/
|
|
192
|
+
pipelines: ReadonlyMap<string, KernelPipelineStep[]>;
|
|
193
|
+
/**
|
|
194
|
+
* Map from command name to module name — used for command manifest generation.
|
|
195
|
+
* Populated once at startup alongside commands.
|
|
196
|
+
*/
|
|
197
|
+
commandModules?: ReadonlyMap<string, string>;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Mutable version of ActualState — used by the reconciler for component mutations.
|
|
202
|
+
* Commands and pipelines are still readonly (populated once at startup).
|
|
203
|
+
*/
|
|
204
|
+
export interface MutableActualState {
|
|
205
|
+
components: Map<string, { declaration: ComponentDeclaration; state: ModuleFiberState }>;
|
|
206
|
+
commands: ReadonlyMap<string, CommandDeclaration>;
|
|
207
|
+
pipelines: ReadonlyMap<string, KernelPipelineStep[]>;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Overlay — layered patch on the base desired state.
|
|
212
|
+
* Allows scope-specific modifications without rewriting the base.
|
|
213
|
+
*/
|
|
214
|
+
export interface DesiredStateOverlay {
|
|
215
|
+
/** Overlay ID — stable and unique within the scope. */
|
|
216
|
+
id: string;
|
|
217
|
+
/** Scope this overlay applies to (RFC-1036). */
|
|
218
|
+
scope: ComponentScope;
|
|
219
|
+
/** Scope context (e.g., missionId for per-mission overlays). */
|
|
220
|
+
context: ScopeContext;
|
|
221
|
+
/** Components to add or replace in the base desired state. */
|
|
222
|
+
addOrReplace: Map<string, ComponentDeclaration>;
|
|
223
|
+
/** Component IDs to remove from the base desired state. */
|
|
224
|
+
remove: string[];
|
|
225
|
+
/** Priority — higher priority overlays override lower ones. */
|
|
226
|
+
priority: number;
|
|
227
|
+
}
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>
|
|
4
|
+
Sole runtime and type owner of DiagnosticSeverity, DiagnosticEvidence, and
|
|
5
|
+
Diagnostic strict Zod schemas (RFC-0852). Types are inferred from schemas.
|
|
6
|
+
kernel/types.ts re-exports these types; the site plugin imports the schemas.
|
|
7
|
+
</purpose>
|
|
8
|
+
<non-goals>
|
|
9
|
+
<item>Do not define canonical JSON bytes or limits; RFC-0849 owns them.</item>
|
|
10
|
+
<item>Do not define EvidenceEnvelopeV1, certification identities, or dossier admission; RFC-0853 owns those.</item>
|
|
11
|
+
<item>Do not add command status vocabularies or suppression systems.</item>
|
|
12
|
+
</non-goals>
|
|
13
|
+
</MODULE_CONTRACT>
|
|
14
|
+
<CHANGE_SUMMARY>
|
|
15
|
+
<item>RFC-0852: Move canonical Diagnostic ownership from site plugin into the engine.</item>
|
|
16
|
+
<item>RFC-1027: Add structured remediation hints — remediationRefSchema and remediation field on Diagnostic.</item>
|
|
17
|
+
</CHANGE_SUMMARY>
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { z } from "zod";
|
|
21
|
+
import {
|
|
22
|
+
isCanonicalJsonObjectV1,
|
|
23
|
+
canonicalJsonBytesV1,
|
|
24
|
+
type CanonicalJsonObjectV1,
|
|
25
|
+
} from "../fingerprint/canonical-json.ts";
|
|
26
|
+
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Limits (RFC-0852 §Bounds)
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
export const DIAGNOSTIC_LIMITS = {
|
|
32
|
+
ruleIdChars: 128,
|
|
33
|
+
messageBytes: 4 * 1024,
|
|
34
|
+
fixHintBytes: 8 * 1024,
|
|
35
|
+
pathBytes: 1024,
|
|
36
|
+
urlBytes: 4 * 1024,
|
|
37
|
+
snippetBytes: 16 * 1024,
|
|
38
|
+
evidenceItems: 32,
|
|
39
|
+
dataBytes: 64 * 1024,
|
|
40
|
+
diagnosticBytes: 128 * 1024,
|
|
41
|
+
diagnosticsPerResult: 1000,
|
|
42
|
+
remediationActionBytes: 512,
|
|
43
|
+
remediationTargetFiles: 8,
|
|
44
|
+
} as const;
|
|
45
|
+
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// Helpers
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
function utf8ByteLength(value: string): number {
|
|
51
|
+
return Buffer.byteLength(value, "utf8");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// Diagnostic rule ID — [A-Z0-9][A-Z0-9._-]* , max 128 ASCII chars
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
|
|
58
|
+
const diagnosticRuleIdPattern = /^[A-Z0-9][A-Z0-9._-]*$/;
|
|
59
|
+
|
|
60
|
+
export const diagnosticRuleIdSchema = z
|
|
61
|
+
.string()
|
|
62
|
+
.max(DIAGNOSTIC_LIMITS.ruleIdChars)
|
|
63
|
+
.regex(
|
|
64
|
+
diagnosticRuleIdPattern,
|
|
65
|
+
"CERT-DIAGNOSTIC-SCHEMA-01: ruleId must match [A-Z0-9][A-Z0-9._-]*",
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// Safe workspace-relative POSIX path
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
const unsafePathPatterns = [
|
|
73
|
+
/[/\\]\.\.([/\\]|$)/, // .. component
|
|
74
|
+
/[/\\]\.([/\\]|$)/, // . component (but allow leading . for dotfiles? No — RFC says reject empty/.)
|
|
75
|
+
/^\//, // absolute path
|
|
76
|
+
/^[/\\]/, // leading separator
|
|
77
|
+
/\\/, // backslash
|
|
78
|
+
/\0/, // NUL
|
|
79
|
+
/^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//, // URI scheme
|
|
80
|
+
/^~([/\\]|$)/, // home expansion
|
|
81
|
+
/^[a-zA-Z]:[\\/]/, // Windows drive letter
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
function isSafeWorkspaceRelativePath(value: string): boolean {
|
|
85
|
+
if (value.length === 0) return false;
|
|
86
|
+
if (utf8ByteLength(value) > DIAGNOSTIC_LIMITS.pathBytes) return false;
|
|
87
|
+
for (const pattern of unsafePathPatterns) {
|
|
88
|
+
if (pattern.test(value)) return false;
|
|
89
|
+
}
|
|
90
|
+
// Reject empty components from split
|
|
91
|
+
const segments = value.split("/");
|
|
92
|
+
for (const seg of segments) {
|
|
93
|
+
if (seg.length === 0) return false; // empty component (e.g. "a//b")
|
|
94
|
+
if (seg === "." || seg === "..") return false;
|
|
95
|
+
}
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export const safeWorkspaceRelativePathSchema = z.string().refine(isSafeWorkspaceRelativePath, {
|
|
100
|
+
message:
|
|
101
|
+
"CERT-DIAGNOSTIC-LOCATOR-01: path must be a workspace-relative POSIX path without absolute paths, backslashes, empty/./.. components, NUL, URI schemes, or home expansion",
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
// Safe diagnostic URL — absolute http/https, no userinfo, no credentials
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
|
|
108
|
+
function isSafeDiagnosticUrl(value: string): boolean {
|
|
109
|
+
if (utf8ByteLength(value) > DIAGNOSTIC_LIMITS.urlBytes) return false;
|
|
110
|
+
if (/\0/.test(value)) return false;
|
|
111
|
+
if (/[\x00-\x1f\x7f]/.test(value)) return false; // control characters
|
|
112
|
+
|
|
113
|
+
let parsed: URL;
|
|
114
|
+
try {
|
|
115
|
+
parsed = new URL(value);
|
|
116
|
+
} catch {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return false;
|
|
121
|
+
|
|
122
|
+
// Reject userinfo (credentials in authority)
|
|
123
|
+
if (parsed.username || parsed.password) return false;
|
|
124
|
+
|
|
125
|
+
// Reject credential-bearing query parameters (best-effort high-confidence)
|
|
126
|
+
const query = parsed.searchParams;
|
|
127
|
+
const credentialKeys = [
|
|
128
|
+
"token",
|
|
129
|
+
"access_token",
|
|
130
|
+
"secret",
|
|
131
|
+
"api_key",
|
|
132
|
+
"apikey",
|
|
133
|
+
"key",
|
|
134
|
+
"password",
|
|
135
|
+
"passwd",
|
|
136
|
+
"pwd",
|
|
137
|
+
"authorization",
|
|
138
|
+
"auth",
|
|
139
|
+
"signature",
|
|
140
|
+
"sig",
|
|
141
|
+
];
|
|
142
|
+
for (const key of credentialKeys) {
|
|
143
|
+
if (query.has(key)) return false;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export const safeDiagnosticUrlSchema = z.string().refine(isSafeDiagnosticUrl, {
|
|
150
|
+
message:
|
|
151
|
+
"CERT-DIAGNOSTIC-LOCATOR-01: URL must be an absolute http/https URL with no userinfo, control characters, or credential-bearing query parameters",
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
// Redacted diagnostic text — no known secrets/PII/absolute paths
|
|
156
|
+
// ---------------------------------------------------------------------------
|
|
157
|
+
|
|
158
|
+
const secretPatterns = [
|
|
159
|
+
/sk-[A-Za-z0-9_-]{20,}/, // OpenAI-style API key
|
|
160
|
+
/eyJ[A-Za-z0-9_-]{20,}\.[A-Za-z0-9_-]+/, // JWT
|
|
161
|
+
/-----BEGIN (?:RSA |EC |OPENSSH |)PRIVATE KEY-----/, // private key
|
|
162
|
+
/Bearer\s+[A-Za-z0-9_-]{20,}/, // bearer token
|
|
163
|
+
/Authorization:\s*Bearer\s+[A-Za-z0-9_-]{20,}/i, // auth header
|
|
164
|
+
/(?:mongodb|postgres|postgresql|mysql|redis):\/\/[^\s@"']+:[^\s@"']+@/, // connection string
|
|
165
|
+
/(?:aws_access_key_id|aws_secret_access_key)\s*=\s*[A-Za-z0-9/+=]{16,}/, // AWS creds
|
|
166
|
+
];
|
|
167
|
+
|
|
168
|
+
const absolutePathPatterns = [
|
|
169
|
+
/^(?:\/|[A-Za-z]:[\\/]|~[\\/])/, // absolute or home path
|
|
170
|
+
];
|
|
171
|
+
|
|
172
|
+
const piiPatterns = [
|
|
173
|
+
/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/, // email
|
|
174
|
+
/\b\d{3}[-.]?\d{3}[-.]?\d{4}\b/, // phone (US-like)
|
|
175
|
+
];
|
|
176
|
+
|
|
177
|
+
function isRedactedDiagnosticText(value: string, maxBytes: number): boolean {
|
|
178
|
+
if (utf8ByteLength(value) > maxBytes) return false;
|
|
179
|
+
if (value.trim().length === 0) return false;
|
|
180
|
+
|
|
181
|
+
for (const pattern of secretPatterns) {
|
|
182
|
+
if (pattern.test(value)) return false;
|
|
183
|
+
}
|
|
184
|
+
for (const pattern of absolutePathPatterns) {
|
|
185
|
+
if (pattern.test(value)) return false;
|
|
186
|
+
}
|
|
187
|
+
for (const pattern of piiPatterns) {
|
|
188
|
+
if (pattern.test(value)) return false;
|
|
189
|
+
}
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function redactedDiagnosticTextSchema(maxBytes: number) {
|
|
194
|
+
return z.string().refine((val) => isRedactedDiagnosticText(val, maxBytes), {
|
|
195
|
+
message: `CERT-DIAGNOSTIC-REDACTION-01: text must not contain known secrets, PII, or absolute paths and must be within ${maxBytes} UTF-8 bytes`,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ---------------------------------------------------------------------------
|
|
200
|
+
// Canonical JSON object V1 schema for Diagnostic.data
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
// RFC-0852: data must be a runtime-branded CanonicalJsonObjectV1 at parse time.
|
|
203
|
+
// The TypeScript type is Record<string, unknown> for structural compatibility
|
|
204
|
+
// with existing producers; the Zod custom check enforces canonical validation
|
|
205
|
+
// before persistence. z.custom is used instead of z.record because Zod 4's
|
|
206
|
+
// z.record structural validation rejects branded frozen objects created by
|
|
207
|
+
// snapshotCanonicalJsonObjectV1.
|
|
208
|
+
|
|
209
|
+
const canonicalJsonObjectV1Schema = z
|
|
210
|
+
.custom<Record<string, unknown>>(
|
|
211
|
+
(val): val is CanonicalJsonObjectV1 => isCanonicalJsonObjectV1(val),
|
|
212
|
+
{
|
|
213
|
+
message: "CERT-DIAGNOSTIC-SCHEMA-01: data must be a runtime-branded CanonicalJsonObjectV1",
|
|
214
|
+
},
|
|
215
|
+
)
|
|
216
|
+
.refine(
|
|
217
|
+
(val) => {
|
|
218
|
+
if (!isCanonicalJsonObjectV1(val)) return false;
|
|
219
|
+
const bytes = canonicalJsonBytesV1(val);
|
|
220
|
+
return bytes.length <= DIAGNOSTIC_LIMITS.dataBytes;
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
message: `CERT-DIAGNOSTIC-LIMIT-01: canonical data bytes must not exceed ${DIAGNOSTIC_LIMITS.dataBytes} bytes`,
|
|
224
|
+
},
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
// ---------------------------------------------------------------------------
|
|
228
|
+
// Severity
|
|
229
|
+
// ---------------------------------------------------------------------------
|
|
230
|
+
|
|
231
|
+
export const diagnosticSeveritySchema = z.enum(["error", "warning", "info"]);
|
|
232
|
+
export type DiagnosticSeverity = z.infer<typeof diagnosticSeveritySchema>;
|
|
233
|
+
|
|
234
|
+
// ---------------------------------------------------------------------------
|
|
235
|
+
// Evidence
|
|
236
|
+
// ---------------------------------------------------------------------------
|
|
237
|
+
|
|
238
|
+
export const diagnosticEvidenceSchema = z
|
|
239
|
+
.object({
|
|
240
|
+
kind: z.enum(["rule", "rendered", "source", "config", "cache", "runtime"]),
|
|
241
|
+
ruleFile: safeWorkspaceRelativePathSchema.optional(),
|
|
242
|
+
ruleId: diagnosticRuleIdSchema.optional(),
|
|
243
|
+
file: safeWorkspaceRelativePathSchema.optional(),
|
|
244
|
+
url: safeDiagnosticUrlSchema.optional(),
|
|
245
|
+
snippet: redactedDiagnosticTextSchema(DIAGNOSTIC_LIMITS.snippetBytes).optional(),
|
|
246
|
+
})
|
|
247
|
+
.strict();
|
|
248
|
+
|
|
249
|
+
export type DiagnosticEvidence = z.infer<typeof diagnosticEvidenceSchema>;
|
|
250
|
+
|
|
251
|
+
// ---------------------------------------------------------------------------
|
|
252
|
+
// Remediation reference (RFC-1027)
|
|
253
|
+
// ---------------------------------------------------------------------------
|
|
254
|
+
|
|
255
|
+
export const remediationRefSchema = z
|
|
256
|
+
.object({
|
|
257
|
+
ruleId: diagnosticRuleIdSchema,
|
|
258
|
+
action: redactedDiagnosticTextSchema(DIAGNOSTIC_LIMITS.remediationActionBytes),
|
|
259
|
+
template: redactedDiagnosticTextSchema(DIAGNOSTIC_LIMITS.fixHintBytes).optional(),
|
|
260
|
+
docRef: safeWorkspaceRelativePathSchema.optional(),
|
|
261
|
+
targetFiles: z
|
|
262
|
+
.array(safeWorkspaceRelativePathSchema)
|
|
263
|
+
.max(DIAGNOSTIC_LIMITS.remediationTargetFiles)
|
|
264
|
+
.optional(),
|
|
265
|
+
})
|
|
266
|
+
.strict();
|
|
267
|
+
|
|
268
|
+
export type RemediationRef = z.infer<typeof remediationRefSchema>;
|
|
269
|
+
|
|
270
|
+
// ---------------------------------------------------------------------------
|
|
271
|
+
// Diagnostic
|
|
272
|
+
// ---------------------------------------------------------------------------
|
|
273
|
+
|
|
274
|
+
export const diagnosticSchema = z
|
|
275
|
+
.object({
|
|
276
|
+
ruleId: diagnosticRuleIdSchema,
|
|
277
|
+
severity: diagnosticSeveritySchema,
|
|
278
|
+
message: redactedDiagnosticTextSchema(DIAGNOSTIC_LIMITS.messageBytes),
|
|
279
|
+
file: safeWorkspaceRelativePathSchema.optional(),
|
|
280
|
+
line: z.number().int().positive().optional(),
|
|
281
|
+
column: z.number().int().positive().optional(),
|
|
282
|
+
fixHint: redactedDiagnosticTextSchema(DIAGNOSTIC_LIMITS.fixHintBytes).optional(),
|
|
283
|
+
remediation: remediationRefSchema.optional(),
|
|
284
|
+
evidence: z.array(diagnosticEvidenceSchema).max(DIAGNOSTIC_LIMITS.evidenceItems).optional(),
|
|
285
|
+
data: canonicalJsonObjectV1Schema.optional(),
|
|
286
|
+
})
|
|
287
|
+
.strict();
|
|
288
|
+
|
|
289
|
+
export type Diagnostic = z.infer<typeof diagnosticSchema>;
|