@warpgogol/werkstatt-shared 0.13.0 → 0.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/README.md +26 -16
  2. package/README.uk.md +24 -14
  3. package/package.json +27 -69
  4. package/src/checks/result-helpers.ts +21 -4
  5. package/src/checks/tests/remediation-auto-populate.test.ts +83 -0
  6. package/src/integration/funnel.ts +78 -1
  7. package/src/integration/index.ts +19 -2
  8. package/src/integration/lagebild-ingress.ts +169 -0
  9. package/src/integration/orchestration.ts +7 -13
  10. package/src/integration/port-barrel.ts +9 -28
  11. package/src/integration/tests/funnel-bridge.test.ts +7 -7
  12. package/src/integration/tests/lagebild-ingress.test.ts +118 -0
  13. package/src/integration/vitest.config.ts +7 -0
  14. package/src/observability/typed-refs.ts +1 -1
  15. package/src/ontology/analytics/matomo-fleet.registry.yaml +1 -1
  16. package/src/ontology/archetypes/index.json +12 -9
  17. package/src/ontology/archetypes/index.yaml +26 -10
  18. package/src/ontology/blueprints/website-local.yaml +11 -11
  19. package/src/ontology/blueprints/website-service.yaml +20 -20
  20. package/src/ontology/capabilities/lead.submit.yaml +2 -2
  21. package/src/ontology/enums.ts +2 -2
  22. package/src/ontology/external-surfaces/jsonld-types.yaml +14 -14
  23. package/src/ontology/external-surfaces/url-schema.yaml +1 -1
  24. package/src/ontology/index.ts +2 -0
  25. package/src/ontology/manifest.ts +19 -0
  26. package/src/ontology/schemas/index.ts +7 -2
  27. package/src/ontology/schemas/system/integrations.ts +1 -1
  28. package/src/ontology/schemas/system/manifest.ts +38 -1
  29. package/src/ontology/schemas/system/tests/growth.test.ts +22 -0
  30. package/src/ontology/schemas/system/tests/integrations.test.ts +12 -0
  31. package/src/ontology/schemas/system/tests/manifest.test.ts +22 -0
  32. package/src/ontology/schemas/system/tests/page-output.test.ts +13 -0
  33. package/src/ontology/schemas/system/tests/release.test.ts +22 -0
  34. package/src/ontology/schemas/system/tests/text.test.ts +18 -0
  35. package/src/ontology/schemas/system/tests/verification.test.ts +12 -0
  36. package/src/ontology/schemas/system.ts +7 -2
  37. package/src/ontology/schemas/tests/biome.test.ts +19 -0
  38. package/src/ontology/schemas/tests/capability.test.ts +22 -0
  39. package/src/ontology/schemas/tests/constellation.test.ts +22 -0
  40. package/src/ontology/schemas/tests/dns-records.test.ts +13 -0
  41. package/src/ontology/schemas/tests/manifest-resolver.test.ts +13 -0
  42. package/src/ontology/schemas/tests/page-entry.test.ts +22 -0
  43. package/src/ontology/schemas/tests/section-archetype.test.ts +12 -0
  44. package/src/ontology/schemas/tests/site-family.test.ts +18 -0
  45. package/src/ontology/schemas/tests/system.test.ts +20 -0
  46. package/src/ontology/shared-section-props/common.ts +11 -0
  47. package/src/ontology/shared-section-props/visual-header.ts +1 -1
  48. package/src/share/agent/api-catalog.ts +5 -0
  49. package/src/share/agent/ard-catalog.ts +14 -0
  50. package/src/share/agent/index.ts +2 -0
  51. package/src/share/agent/manifest.ts +25 -2
  52. package/src/share/agent/mcp-card.ts +4 -0
  53. package/src/share/agent/openapi.ts +78 -0
  54. package/src/share/agent/search.test.ts +188 -0
  55. package/src/share/agent/search.ts +164 -0
  56. package/src/share/agent/tests/api-catalog.test.ts +8 -0
  57. package/src/share/agent/tests/ard-catalog.test.ts +8 -0
  58. package/src/share/agent/tests/capability.test.ts +14 -0
  59. package/src/share/agent/tests/fleet-catalog.test.ts +15 -0
  60. package/src/share/agent/tests/knowledge.test.ts +20 -0
  61. package/src/share/agent/tests/manifest.test.ts +9 -0
  62. package/src/share/agent/tests/mcp-card.test.ts +8 -0
  63. package/src/share/agent/tests/omit-empty.test.ts +33 -0
  64. package/src/share/agent/tests/openapi.test.ts +8 -0
  65. package/src/share/agent/tests/proof.test.ts +15 -0
  66. package/src/share/env.d.ts +0 -4
  67. package/src/share/knowledge/tests/claim.test.ts +11 -0
  68. package/src/share/knowledge/tests/derivation.test.ts +30 -0
  69. package/src/share/knowledge/tests/freshness.test.ts +18 -0
  70. package/src/share/knowledge/tests/ledger.test.ts +35 -0
  71. package/src/share/knowledge/tests/plan.test.ts +19 -0
  72. package/src/share/knowledge/tests/source.test.ts +19 -0
  73. package/src/share/remediation/remediation-catalog.ts +196 -0
  74. package/src/share/schemas/effects.ts +16 -0
  75. package/src/share/schemas/media.ts +4 -0
  76. package/src/share/schemas/section-shell.ts +2 -1
  77. package/src/share/schemas/tests/claim-records.test.ts +52 -0
  78. package/src/share/schemas/tests/claims.test.ts +23 -0
  79. package/src/share/schemas/tests/effects.test.ts +116 -0
  80. package/src/share/schemas/tests/features.test.ts +61 -0
  81. package/src/share/schemas/tests/horizontal-align.test.ts +16 -0
  82. package/src/share/schemas/tests/icon-color.test.ts +16 -0
  83. package/src/share/schemas/tests/live-photo.test.ts +40 -0
  84. package/src/share/schemas/tests/material-credit.test.ts +51 -0
  85. package/src/share/schemas/tests/media.test.ts +26 -0
  86. package/src/share/schemas/tests/navigation.test.ts +58 -0
  87. package/src/share/schemas/tests/page-base.test.ts +19 -0
  88. package/src/share/schemas/tests/participant.test.ts +26 -0
  89. package/src/share/schemas/tests/person.test.ts +12 -0
  90. package/src/share/schemas/tests/print.test.ts +30 -0
  91. package/src/share/schemas/tests/section-background.test.ts +31 -0
  92. package/src/share/schemas/tests/section-body.test.ts +16 -0
  93. package/src/share/schemas/tests/section-cards.test.ts +17 -0
  94. package/src/share/schemas/tests/section-cta.test.ts +41 -0
  95. package/src/share/schemas/tests/section-header.test.ts +31 -0
  96. package/src/share/schemas/tests/section-image.test.ts +24 -0
  97. package/src/share/schemas/tests/section-motion.test.ts +29 -0
  98. package/src/share/schemas/tests/section-shell.test.ts +42 -0
  99. package/src/share/schemas/tests/section-stats.test.ts +17 -0
  100. package/src/share/schemas/tests/site-background.test.ts +33 -0
  101. package/src/share/schemas/tests/standard-list-item.test.ts +16 -0
  102. package/src/share/scripts/external-link-qr.ts +9 -1
  103. package/src/share/scripts/gsap-counter.ts +2 -0
  104. package/src/share/scripts/inline-number-animation.ts +2 -0
  105. package/src/share/scripts/live-photos.ts +2 -0
  106. package/src/share/scripts/tests/external-link-qr.test.ts +8 -0
  107. package/src/share/scripts/tests/external-links.test.ts +25 -0
  108. package/src/share/scripts/tests/gsap-counter.test.ts +8 -0
  109. package/src/share/scripts/tests/gsap-mountain-journey.test.ts +8 -0
  110. package/src/share/scripts/tests/gsap-parallax.test.ts +8 -0
  111. package/src/share/scripts/tests/gsap-reveal.test.ts +8 -0
  112. package/src/share/scripts/tests/gsap-stagger.test.ts +8 -0
  113. package/src/share/scripts/tests/inline-number-animation.test.ts +8 -0
  114. package/src/share/scripts/tests/lenis.test.ts +8 -0
  115. package/src/share/scripts/tests/live-photos.test.ts +8 -0
  116. package/src/share/scripts/tests/lordicon.test.ts +8 -0
  117. package/src/share/scripts/tests/orchestrator.test.ts +8 -0
  118. package/src/share/scripts/tests/scheduler.test.ts +23 -0
  119. package/src/share/scripts/video-player.test.ts +210 -0
  120. package/src/share/scripts/video-player.ts +73 -13
  121. package/src/share/semantic/extract.ts +25 -1
  122. package/src/share/semantic/jsonld/tests/article.test.ts +89 -0
  123. package/src/share/semantic/jsonld/tests/breadcrumb.test.ts +62 -0
  124. package/src/share/semantic/jsonld/tests/collection-list.test.ts +39 -0
  125. package/src/share/semantic/jsonld/tests/faq.test.ts +60 -0
  126. package/src/share/semantic/jsonld/tests/initiative.test.ts +56 -0
  127. package/src/share/semantic/jsonld/tests/organization.test.ts +123 -0
  128. package/src/share/semantic/jsonld/tests/person.test.ts +89 -0
  129. package/src/share/semantic/jsonld/tests/service.test.ts +65 -0
  130. package/src/share/semantic/jsonld/tests/shared.test.ts +41 -0
  131. package/src/share/semantic/jsonld/tests/video.test.ts +84 -0
  132. package/src/share/semantic/jsonld/tests/webpage.test.ts +93 -0
  133. package/src/share/semantic/jsonld/tests/website.test.ts +27 -0
  134. package/src/share/semantic/jsonld/types.ts +1 -0
  135. package/src/share/semantic/models.ts +1 -0
  136. package/src/share/semantic/tests/ai.test.ts +55 -0
  137. package/src/share/semantic/tests/block-extraction.test.ts +34 -0
  138. package/src/share/semantic/tests/breadcrumbs.test.ts +127 -0
  139. package/src/share/semantic/tests/build-page.test.ts +122 -0
  140. package/src/share/semantic/tests/business-projection.test.ts +188 -0
  141. package/src/share/semantic/tests/derived-prices-loader.test.ts +46 -0
  142. package/src/share/semantic/tests/extract.test.ts +126 -0
  143. package/src/share/semantic/tests/feed.test.ts +113 -0
  144. package/src/share/semantic/tests/helpers.ts +32 -0
  145. package/src/share/semantic/tests/ids.test.ts +118 -0
  146. package/src/share/semantic/tests/image-sitemap.test.ts +109 -0
  147. package/src/share/semantic/tests/jsonld.test.ts +61 -0
  148. package/src/share/semantic/tests/llms-policy.test.ts +60 -0
  149. package/src/share/semantic/tests/llms.test.ts +118 -0
  150. package/src/share/semantic/tests/markdown-hygiene.test.ts +72 -0
  151. package/src/share/semantic/tests/markdown-page.test.ts +97 -0
  152. package/src/share/semantic/tests/markdown-twin-provenance.test.ts +152 -0
  153. package/src/share/semantic/tests/organization-profile.test.ts +107 -0
  154. package/src/share/semantic/tests/output-projection.test.ts +77 -0
  155. package/src/share/semantic/tests/page-markdown.test.ts +98 -0
  156. package/src/share/semantic/tests/page-utils.test.ts +88 -0
  157. package/src/share/semantic/tests/price-marker-resolver.test.ts +88 -0
  158. package/src/share/semantic/tests/robots.test.ts +70 -0
  159. package/src/share/semantic/tests/split-sentences.test.ts +57 -0
  160. package/src/share/semantic/tests/update-stamp.test.ts +102 -0
  161. package/src/share/tests/manifest.test.ts +51 -0
  162. package/src/share/tests/openapi.test.ts +30 -0
  163. package/src/share/types/qrcode-browser.d.ts +18 -0
  164. package/src/share/utility-registry.yaml +16 -2
  165. package/src/integration/crm-buffer.ts +0 -491
  166. package/src/integration-adapter-supabase-crm/adapter.ts +0 -437
  167. package/src/integration-adapter-supabase-crm/client.ts +0 -605
  168. package/src/integration-adapter-supabase-crm/index.ts +0 -28
  169. package/src/integration-adapter-supabase-crm/pipedrive-sync-target.ts +0 -482
  170. package/src/integration-adapter-supabase-crm/supabase-rest.ts +0 -89
  171. package/src/integration-adapter-supabase-crm/tenant-registry.ts +0 -334
  172. package/src/integration-adapter-supabase-crm/tests/change-balance.pbt.test.ts +0 -83
  173. package/src/integration-adapter-supabase-crm/tests/funnel-persistence.test.ts +0 -409
  174. package/src/integration-adapter-supabase-crm/tests/lifecycle-sync.test.ts +0 -288
  175. package/src/integration-adapter-supabase-crm/tests/stage-map.test.ts +0 -80
  176. package/src/integration-adapter-supabase-crm/vitest.config.ts +0 -8
  177. package/src/integration-adapter-supabase-crm/worker.ts +0 -223
  178. package/src/ontology/archetypes/components/currency-selector.yaml +0 -19
@@ -0,0 +1,20 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { AGENT_KNOWLEDGE_DOMAINS, isAgentKnowledgeDomain } from "../knowledge.ts";
3
+
4
+ describe("AGENT_KNOWLEDGE_DOMAINS", () => {
5
+ it("is a non-empty array", () => {
6
+ expect(Array.isArray(AGENT_KNOWLEDGE_DOMAINS)).toBe(true);
7
+ expect(AGENT_KNOWLEDGE_DOMAINS.length).toBeGreaterThan(0);
8
+ });
9
+ });
10
+
11
+ describe("isAgentKnowledgeDomain", () => {
12
+ it("returns true for valid domain", () => {
13
+ const firstDomain = AGENT_KNOWLEDGE_DOMAINS[0];
14
+ expect(isAgentKnowledgeDomain(firstDomain)).toBe(true);
15
+ });
16
+
17
+ it("returns false for invalid domain", () => {
18
+ expect(isAgentKnowledgeDomain("invalid-domain")).toBe(false);
19
+ });
20
+ });
@@ -0,0 +1,9 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { AGENT_SURFACE_VERSION } from "../manifest.ts";
3
+
4
+ describe("AGENT_SURFACE_VERSION", () => {
5
+ it("is a version string", () => {
6
+ expect(typeof AGENT_SURFACE_VERSION).toBe("string");
7
+ expect(AGENT_SURFACE_VERSION).toMatch(/\d+\.\d+\.\d+/);
8
+ });
9
+ });
@@ -0,0 +1,8 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { buildMcpServerCard } from "../mcp-card.ts";
3
+
4
+ describe("buildMcpServerCard", () => {
5
+ it("is a function", () => {
6
+ expect(typeof buildMcpServerCard).toBe("function");
7
+ });
8
+ });
@@ -0,0 +1,33 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { omitEmptyKnowledgeValues } from "../omit-empty.ts";
3
+
4
+ describe("omitEmptyKnowledgeValues", () => {
5
+ it("is a function", () => {
6
+ expect(typeof omitEmptyKnowledgeValues).toBe("function");
7
+ });
8
+
9
+ it("removes empty strings, null, undefined, empty arrays, and empty objects", () => {
10
+ const input = { a: "value", b: "", c: null, d: undefined, e: [], f: {} };
11
+ const result = omitEmptyKnowledgeValues(input);
12
+ expect(result).not.toHaveProperty("b");
13
+ expect(result).not.toHaveProperty("c");
14
+ expect(result).not.toHaveProperty("d");
15
+ expect(result).not.toHaveProperty("e");
16
+ expect(result).not.toHaveProperty("f");
17
+ expect(result).toHaveProperty("a", "value");
18
+ });
19
+
20
+ it("preserves false and 0 (schema-allowed falsy values)", () => {
21
+ const input = { enabled: false, count: 0 };
22
+ const result = omitEmptyKnowledgeValues(input);
23
+ expect(result).toHaveProperty("enabled", false);
24
+ expect(result).toHaveProperty("count", 0);
25
+ });
26
+
27
+ it("preserves non-empty arrays and objects", () => {
28
+ const input = { items: [1, 2], nested: { x: 1 } };
29
+ const result = omitEmptyKnowledgeValues(input);
30
+ expect(result).toHaveProperty("items", [1, 2]);
31
+ expect(result).toHaveProperty("nested", { x: 1 });
32
+ });
33
+ });
@@ -0,0 +1,8 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { formatAgentOpenApi } from "../openapi.ts";
3
+
4
+ describe("formatAgentOpenApi", () => {
5
+ it("is a function", () => {
6
+ expect(typeof formatAgentOpenApi).toBe("function");
7
+ });
8
+ });
@@ -0,0 +1,15 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { AGENT_PROOF_DOMAIN, buildAgentSigningPayload } from "../proof.ts";
3
+
4
+ describe("AGENT_PROOF_DOMAIN", () => {
5
+ it("is a string constant", () => {
6
+ expect(typeof AGENT_PROOF_DOMAIN).toBe("string");
7
+ expect(AGENT_PROOF_DOMAIN.length).toBeGreaterThan(0);
8
+ });
9
+ });
10
+
11
+ describe("buildAgentSigningPayload", () => {
12
+ it("is a function", () => {
13
+ expect(typeof buildAgentSigningPayload).toBe("function");
14
+ });
15
+ });
@@ -48,10 +48,6 @@ declare module "astro:env/server" {
48
48
  export const UPSTASH_QSTASH_NEXT_SIGNING_KEY: string | undefined;
49
49
  export const UPSTASH_REDIS_REST_URL: string | undefined;
50
50
  export const UPSTASH_REDIS_REST_TOKEN: string | undefined;
51
- // Lagebild MVP: Supabase CRM buffer (self-enabling — adapter skips when absent).
52
- export const SUPABASE_BUFFER_URL: string | undefined;
53
- export const SUPABASE_BUFFER_SERVICE_KEY: string | undefined;
54
- export const SUPABASE_BUFFER_TENANT_ID: string | undefined;
55
51
  // RFC-0191: Stripe billing — the webhook signing secret (stripe-webhook route) and the
56
52
  // server API key (billing client). Per-tenant; self-enabling — handlers fail-closed when absent.
57
53
  export const STRIPE_WEBHOOK_SECRET: string | undefined;
@@ -0,0 +1,11 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { CLAIM_PROVENANCE_KINDS } from "../claim.ts";
3
+
4
+ describe("CLAIM_PROVENANCE_KINDS", () => {
5
+ it("contains expected provenance kinds", () => {
6
+ expect(CLAIM_PROVENANCE_KINDS).toContain("external");
7
+ expect(CLAIM_PROVENANCE_KINDS).toContain("derived");
8
+ expect(CLAIM_PROVENANCE_KINDS).toContain("asserted");
9
+ expect(CLAIM_PROVENANCE_KINDS).toContain("generated");
10
+ });
11
+ });
@@ -0,0 +1,30 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { normalizeForHash, hashSourceValue, derivedState } from "../derivation.ts";
3
+
4
+ describe("normalizeForHash", () => {
5
+ it("is a function", () => {
6
+ expect(typeof normalizeForHash).toBe("function");
7
+ });
8
+
9
+ it("normalizes whitespace", () => {
10
+ const result = normalizeForHash(" hello world ");
11
+ expect(typeof result).toBe("string");
12
+ });
13
+ });
14
+
15
+ describe("hashSourceValue", () => {
16
+ it("is a function", () => {
17
+ expect(typeof hashSourceValue).toBe("function");
18
+ });
19
+
20
+ it("returns a string hash", () => {
21
+ const result = hashSourceValue("test");
22
+ expect(typeof result).toBe("string");
23
+ });
24
+ });
25
+
26
+ describe("derivedState", () => {
27
+ it("is a function", () => {
28
+ expect(typeof derivedState).toBe("function");
29
+ });
30
+ });
@@ -0,0 +1,18 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { addDuration } from "../freshness.ts";
3
+
4
+ describe("addDuration", () => {
5
+ it("is a function", () => {
6
+ expect(typeof addDuration).toBe("function");
7
+ });
8
+
9
+ it("adds months to a date", () => {
10
+ const result = addDuration("2026-01-01", "P3M");
11
+ expect(result).not.toBeNull();
12
+ });
13
+
14
+ it("returns null for invalid duration", () => {
15
+ const result = addDuration("2026-01-01", "invalid");
16
+ expect(result).toBeNull();
17
+ });
18
+ });
@@ -0,0 +1,35 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import type { ClaimEvent, ClaimLineage } from "../ledger.ts";
3
+
4
+ describe("ledger types", () => {
5
+ it("ClaimEvent is a valid type", () => {
6
+ const event: ClaimEvent = {
7
+ id: "evt-1",
8
+ ts: "2026-01-01T00:00:00Z",
9
+ subject: "test",
10
+ provenance: "asserted",
11
+ asOf: "2026-01-01",
12
+ actor: "agent",
13
+ event: "asserted" as ClaimEvent["event"],
14
+ };
15
+ expect(event).toBeDefined();
16
+ });
17
+
18
+ it("ClaimLineage is a valid type", () => {
19
+ const event: ClaimEvent = {
20
+ id: "evt-1",
21
+ ts: "2026-01-01T00:00:00Z",
22
+ subject: "test",
23
+ provenance: "asserted",
24
+ asOf: "2026-01-01",
25
+ actor: "agent",
26
+ event: "asserted" as ClaimEvent["event"],
27
+ };
28
+ const lineage: ClaimLineage = {
29
+ subject: "test",
30
+ current: event,
31
+ history: [event],
32
+ };
33
+ expect(lineage).toBeDefined();
34
+ });
35
+ });
@@ -0,0 +1,19 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { stableTaskId } from "../plan.ts";
3
+
4
+ describe("stableTaskId", () => {
5
+ it("is a function", () => {
6
+ expect(typeof stableTaskId).toBe("function");
7
+ });
8
+
9
+ it("returns a string id", () => {
10
+ const result = stableTaskId("subject-1", "review-due");
11
+ expect(typeof result).toBe("string");
12
+ });
13
+
14
+ it("is deterministic for same inputs", () => {
15
+ const a = stableTaskId("subject-1", "review-due");
16
+ const b = stableTaskId("subject-1", "review-due");
17
+ expect(a).toBe(b);
18
+ });
19
+ });
@@ -0,0 +1,19 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { SOURCE_KINDS, sourceToleranceSchema } from "../source.ts";
3
+
4
+ describe("SOURCE_KINDS", () => {
5
+ it("contains expected source kinds", () => {
6
+ expect(SOURCE_KINDS).toContain("http-json");
7
+ expect(SOURCE_KINDS).toContain("manual");
8
+ });
9
+ });
10
+
11
+ describe("sourceToleranceSchema", () => {
12
+ it("is defined", () => {
13
+ expect(sourceToleranceSchema).toBeDefined();
14
+ });
15
+
16
+ it("rejects null", () => {
17
+ expect(() => sourceToleranceSchema.parse(null)).toThrow();
18
+ });
19
+ });
@@ -0,0 +1,196 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>
4
+ Canonical remediation catalog mapping ruleId to structured remediation patterns.
5
+ Consumed by diagnosticsResult() for auto-population and by remediation.hint.validate
6
+ for coverage checking (RFC-1027).
7
+ </purpose>
8
+ <non-goals>
9
+ <item>Does not own the Diagnostic schema — that lives in werkstatt-engine schemas.</item>
10
+ <item>Does not aggregate remediation hints into KernelExecutionReport — that is the engine's job.</item>
11
+ </non-goals>
12
+ </MODULE_CONTRACT>
13
+ <CHANGE_SUMMARY>
14
+ <item>RFC-1027: Create REMEDIATION_CATALOG with 30+ patterns for the most common ruleIds.</item>
15
+ </CHANGE_SUMMARY>
16
+ */
17
+
18
+ export interface RemediationPattern {
19
+ ruleId: string;
20
+ action: string;
21
+ template?: string;
22
+ docRef?: string;
23
+ targetFiles?: string[];
24
+ }
25
+
26
+ const REMEDIATION_ENTRIES: RemediationPattern[] = [
27
+ {
28
+ ruleId: "SEO-RUNTIME.CANONICAL-MISMATCH",
29
+ action: "Ensure the canonical URL in the rendered HTML matches the production domain without language prefix for the default locale.",
30
+ docRef: "docs/authoring/site-composition.md",
31
+ targetFiles: ["src/layouts/**/*.astro"],
32
+ },
33
+ {
34
+ ruleId: "WORKSPACE.SURFACE.VALIDATE",
35
+ action: "Fix surface validation errors by checking the surface block declarations against the schema.",
36
+ docRef: "docs/authoring/site-composition.md",
37
+ },
38
+ {
39
+ ruleId: "TEST.SIGNAL.POLICY.VALIDATE",
40
+ action: "Align test signal declarations with the policy schema — check signal name, severity, and evidence path.",
41
+ docRef: "docs/agents/domain.md",
42
+ },
43
+ {
44
+ ruleId: "PUBLIC.ICONS.VALIDATE",
45
+ action: "Replace invalid icon references with valid SurfaceLabels entries or remove the icon field.",
46
+ docRef: "docs/authoring/site-composition.md",
47
+ },
48
+ {
49
+ ruleId: "PARITY-SECTION-COUNT",
50
+ action: "Add or remove sections so the locale overlay matches the base locale section count.",
51
+ docRef: "docs/authoring/preventive-measures-parity-and-templates.md",
52
+ },
53
+ {
54
+ ruleId: "GEN-FILES-01",
55
+ action: "Regenerate generated files by running the owning kernel command, then commit the updated output.",
56
+ docRef: "docs/authoring/generated-files-and-templates.md",
57
+ },
58
+ {
59
+ ruleId: "DEPS-GEN-01",
60
+ action: "Run pnpm exec werkstatt run deps.peer.check to regenerate the peer dependency manifest.",
61
+ docRef: "docs/authoring/generated-files-and-templates.md",
62
+ },
63
+ {
64
+ ruleId: "AGC-01",
65
+ action: "Fix the agent gate configuration — ensure the gate metadata matches the declared gate catalog.",
66
+ docRef: "docs/agents/domain.md",
67
+ },
68
+ {
69
+ ruleId: "WORKPIECE-IMPORTS-01",
70
+ action: "Resolve the broken import in the workpiece — check the module path and ensure the package is installed.",
71
+ },
72
+ {
73
+ ruleId: "SNAP-01",
74
+ action: "Regenerate the behavior snapshot by running pnpm exec werkstatt run behavior.snapshot.generate.",
75
+ },
76
+ {
77
+ ruleId: "CREG-04",
78
+ action: "Fix the content regression — review the content diff and update the review.yaml before closing the mission.",
79
+ docRef: "docs/authoring/site-composition.md",
80
+ },
81
+ {
82
+ ruleId: "CREG-03",
83
+ action: "Fix the content regression — ensure all locale overlays are consistent with the base content.",
84
+ docRef: "docs/authoring/preventive-measures-parity-and-templates.md",
85
+ },
86
+ {
87
+ ruleId: "CREG-01",
88
+ action: "Fix the content regression — the base content was changed without a review.yaml. Run content.regression.review.generate.",
89
+ docRef: "docs/authoring/site-composition.md",
90
+ },
91
+ {
92
+ ruleId: "BRK-04",
93
+ action: "Fix the bordbuch entry — ensure the hash chain is intact and the entry is properly signed.",
94
+ },
95
+ {
96
+ ruleId: "PROPS-01",
97
+ action: "Fix the content props schema violation — check the frontmatter against the schema declaration.",
98
+ },
99
+ {
100
+ ruleId: "MAINTENANCE.DEBT.BASELINE.VALIDATE",
101
+ action: "Regenerate the maintenance debt baseline by running pnpm exec werkstatt run maintenance.debt.baseline.generate.",
102
+ },
103
+ {
104
+ ruleId: "HDR-04",
105
+ action: "Fix the header configuration — ensure the header block matches the surface schema.",
106
+ docRef: "docs/authoring/site-composition.md",
107
+ },
108
+ {
109
+ ruleId: "HDR-02",
110
+ action: "Fix the header navigation — ensure all nav items have valid href and label.",
111
+ docRef: "docs/authoring/site-composition.md",
112
+ },
113
+ {
114
+ ruleId: "HDR-01",
115
+ action: "Fix the header structure — ensure the header block is declared in the surface composition.",
116
+ docRef: "docs/authoring/site-composition.md",
117
+ },
118
+ {
119
+ ruleId: "GEN-EDIT-01",
120
+ action: "Do not hand-edit generated files. Modify the source template and regenerate.",
121
+ docRef: "docs/authoring/generated-files-and-templates.md",
122
+ },
123
+ {
124
+ ruleId: "DEPS-PEER-01",
125
+ action: "Add the missing peer dependency to the package.json or remove the import that requires it.",
126
+ },
127
+ {
128
+ ruleId: "CW-EVID-01",
129
+ action: "Fix the changelog evidence — ensure the evidence file exists and is referenced correctly.",
130
+ },
131
+ {
132
+ ruleId: "CMD-MAN-03",
133
+ action: "Regenerate the command manifest by running pnpm exec werkstatt run command.manifest.generate.",
134
+ },
135
+ {
136
+ ruleId: "CI-LOCAL-05",
137
+ action: "Fix the CI configuration — ensure the local CI workflow matches the pipeline definitions.",
138
+ },
139
+ {
140
+ ruleId: "AGS-05",
141
+ action: "Fix the agent gate search configuration — ensure the search manifest is generated and accessible.",
142
+ docRef: "docs/agents/domain.md",
143
+ },
144
+ {
145
+ ruleId: "AGS-02",
146
+ action: "Fix the agent gate search schema — ensure the search chunk text is within the max length.",
147
+ docRef: "docs/agents/domain.md",
148
+ },
149
+ {
150
+ ruleId: "AGO-01",
151
+ action: "Fix the agent gate output — ensure the gate output matches the declared schema.",
152
+ docRef: "docs/agents/domain.md",
153
+ },
154
+ {
155
+ ruleId: "AGK-03",
156
+ action: "Fix the agent gate key — ensure the gate key is unique and matches the declared catalog.",
157
+ docRef: "docs/agents/domain.md",
158
+ },
159
+ {
160
+ ruleId: "WS-WRITE-02",
161
+ action: "Fix the workspace write — ensure the write intent is declared and the path is within the workspace root.",
162
+ },
163
+ {
164
+ ruleId: "SUPPRESS-VAL-04",
165
+ action: "Fix the suppression validation — ensure the suppression rule matches the declared schema.",
166
+ docRef: "docs/authoring/guide-suppression-matching.md",
167
+ },
168
+ {
169
+ ruleId: "ENV-CONTRACT-02",
170
+ action: "Fix the environment contract — ensure the env variable is declared in .env.example and matches the contract.",
171
+ },
172
+ {
173
+ ruleId: "ENV-CONTRACT-04",
174
+ action: "Fix the environment contract — ensure the env variable type matches the declared schema.",
175
+ },
176
+ {
177
+ ruleId: "ENV-CONTRACT-05",
178
+ action: "Fix the environment contract — ensure the env variable is documented in the .env.example file.",
179
+ },
180
+ {
181
+ ruleId: "DEPLOY-SCRIPTS-03",
182
+ action: "Fix the deploy script — ensure the script is executable and matches the deployment pipeline.",
183
+ },
184
+ {
185
+ ruleId: "FLEET-05",
186
+ action: "Fix the fleet configuration — ensure the fleet entry matches the declared schema.",
187
+ },
188
+ ];
189
+
190
+ export const REMEDIATION_CATALOG: ReadonlyMap<string, RemediationPattern> = new Map(
191
+ REMEDIATION_ENTRIES.map((entry) => [entry.ruleId, entry]),
192
+ );
193
+
194
+ export function lookupRemediation(ruleId: string): RemediationPattern | undefined {
195
+ return REMEDIATION_CATALOG.get(ruleId);
196
+ }
@@ -29,6 +29,7 @@ const NAMED_EFFECT_TARGETS = [
29
29
  "cta",
30
30
  "heading", // RFC-0151 — typographic effects on the section heading
31
31
  "subheading", // typographic effects on the section subheading/tagline
32
+ "background", // lighten overlay on the section background image
32
33
  ] as const;
33
34
 
34
35
  export const namedEffectTargetSchema = z.enum(NAMED_EFFECT_TARGETS);
@@ -106,12 +107,25 @@ export const tiltEffectSchema = z
106
107
  .strict();
107
108
  export type TiltEffect = z.infer<typeof tiltEffectSchema>;
108
109
 
110
+ export const lightenEffectSchema = z
111
+ .object({
112
+ kind: z.literal("lighten"),
113
+ enabled: z.boolean(),
114
+ /** 0..1; opacity of the lightening overlay above the background image. */
115
+ opacity: z.number().min(0).max(1).optional(),
116
+ /** Color alias or raw value for the overlay. Defaults to --ds-color-bg. */
117
+ color: effectColorSchema.optional(),
118
+ })
119
+ .strict();
120
+ export type LightenEffect = z.infer<typeof lightenEffectSchema>;
121
+
109
122
  export const effectSchema = z.discriminatedUnion("kind", [
110
123
  glassEffectSchema,
111
124
  shadowEffectSchema,
112
125
  glowEffectSchema,
113
126
  bulgeEffectSchema,
114
127
  tiltEffectSchema,
128
+ lightenEffectSchema,
115
129
  ]);
116
130
  export type Effect = z.infer<typeof effectSchema>;
117
131
 
@@ -128,6 +142,7 @@ export const EFFECT_KIND_META = {
128
142
  glow: { strategy: "text", maxPerStack: 1 },
129
143
  bulge: { strategy: "text", maxPerStack: 1 },
130
144
  tilt: { strategy: "text", maxPerStack: 1 },
145
+ lighten: { strategy: "surface", maxPerStack: 1 },
131
146
  } as const satisfies Record<EffectKind, { strategy: EffectRenderStrategy; maxPerStack: number }>;
132
147
 
133
148
  /**
@@ -138,6 +153,7 @@ export const EFFECT_KIND_META = {
138
153
  export const TARGET_ALLOWED_KINDS: Record<string, readonly EffectKind[]> = {
139
154
  heading: ["shadow", "glow", "bulge", "tilt"],
140
155
  subheading: ["shadow", "glow", "bulge", "tilt"],
156
+ background: ["lighten"],
141
157
  };
142
158
 
143
159
  const DEFAULT_ALLOWED_KINDS: readonly EffectKind[] = ["glass"];
@@ -19,6 +19,7 @@
19
19
  <item>RFC-0525: added av1 field to VideoManifestSources for AV1 progressive delivery.</item>
20
20
  <item>RFC-0525: added opt-in av1 boolean to mediaSchema (default false) to skip slow AV1 encoding.</item>
21
21
  <item>RFC-0591: added maxSizeMb field to mediaSchema for two-pass bitrate-capped MP4 encoding.</item>
22
+ <item>RFC-0950: added fullscreen field to mediaSchema for content-controlled edge-to-edge layout.</item>
22
23
  </CHANGE_SUMMARY>
23
24
  */
24
25
 
@@ -93,6 +94,9 @@ export const mediaSchema = z
93
94
  loop: z.boolean().optional(),
94
95
  muted: z.boolean().optional(),
95
96
  controls: z.boolean().optional(),
97
+
98
+ /** [RFC-0950] CSS edge-to-edge layout (hero-style), NOT the browser Fullscreen API. */
99
+ fullscreen: z.boolean().optional(),
96
100
  preload: z.enum(["none", "metadata", "auto"]).optional(),
97
101
 
98
102
  /** ambient/background only (RFC-0202): when the loop starts and what a tap does. */
@@ -13,6 +13,7 @@ module owns visual + structural wrapper props only.
13
13
  </MODULE_CONTRACT>
14
14
  <CHANGE_SUMMARY>
15
15
  <item>RFC-0133: backfilled MODULE_MAP and CHANGE_SUMMARY markers for compass.validate compliance.</item>
16
+ <item>Added "flush" density for sections that need zero padding (e.g. fullscreen video flush to header).
16
17
  </CHANGE_SUMMARY>
17
18
  */
18
19
 
@@ -21,7 +22,7 @@ import { sectionBackgroundSchema } from "./section-background.ts";
21
22
  import { effectsSchema } from "./effects.ts";
22
23
  import { sectionMotionConfigSchema } from "./section-motion.ts";
23
24
 
24
- export const sectionDensitySchema = z.enum(["compact", "normal", "spacious"]);
25
+ export const sectionDensitySchema = z.enum(["compact", "normal", "spacious", "flush"]);
25
26
  export type SectionDensity = z.infer<typeof sectionDensitySchema>;
26
27
 
27
28
  export const sectionToneSchema = z.enum(["default", "warning", "success", "muted"]);
@@ -0,0 +1,52 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { claimSourceRefSchema } from "../claim-records.ts";
3
+
4
+ describe("claimSourceRefSchema", () => {
5
+ it("accepts a valid source ref", () => {
6
+ const ref = {
7
+ sourceId: "src-1",
8
+ url: "https://example.com",
9
+ title: "Example",
10
+ retrievedAt: "2026-01-01",
11
+ };
12
+ expect(claimSourceRefSchema.parse(ref)).toEqual(ref);
13
+ });
14
+
15
+ it("rejects missing required fields", () => {
16
+ expect(() => claimSourceRefSchema.parse({ sourceId: "src-1" })).toThrow();
17
+ });
18
+
19
+ it("rejects invalid URL", () => {
20
+ expect(() =>
21
+ claimSourceRefSchema.parse({
22
+ sourceId: "src-1",
23
+ url: "not-a-url",
24
+ title: "Example",
25
+ retrievedAt: "2026-01-01",
26
+ }),
27
+ ).toThrow();
28
+ });
29
+
30
+ it("rejects invalid date format", () => {
31
+ expect(() =>
32
+ claimSourceRefSchema.parse({
33
+ sourceId: "src-1",
34
+ url: "https://example.com",
35
+ title: "Example",
36
+ retrievedAt: "01/01/2026",
37
+ }),
38
+ ).toThrow();
39
+ });
40
+
41
+ it("rejects extra keys (strict)", () => {
42
+ expect(() =>
43
+ claimSourceRefSchema.parse({
44
+ sourceId: "src-1",
45
+ url: "https://example.com",
46
+ title: "Example",
47
+ retrievedAt: "2026-01-01",
48
+ extra: true,
49
+ }),
50
+ ).toThrow();
51
+ });
52
+ });
@@ -0,0 +1,23 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { recordClaimsSchema } from "../claims.ts";
3
+
4
+ describe("recordClaimsSchema", () => {
5
+ it("accepts empty record", () => {
6
+ expect(recordClaimsSchema.parse({})).toEqual({});
7
+ });
8
+
9
+ it("accepts a valid claims record", () => {
10
+ const claims = {
11
+ field1: {
12
+ provenance: "external",
13
+ asOf: "2026-01-01",
14
+ },
15
+ };
16
+ const result = recordClaimsSchema.safeParse(claims);
17
+ expect(result.success).toBe(true);
18
+ });
19
+
20
+ it("rejects non-object", () => {
21
+ expect(() => recordClaimsSchema.parse("not an object")).toThrow();
22
+ });
23
+ });