@warpgogol/werkstatt-shared 0.14.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 (117) hide show
  1. package/README.md +26 -16
  2. package/README.uk.md +24 -14
  3. package/package.json +7 -1
  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/vitest.config.ts +7 -0
  7. package/src/ontology/manifest.ts +19 -0
  8. package/src/ontology/schemas/system/tests/growth.test.ts +22 -0
  9. package/src/ontology/schemas/system/tests/integrations.test.ts +12 -0
  10. package/src/ontology/schemas/system/tests/manifest.test.ts +22 -0
  11. package/src/ontology/schemas/system/tests/page-output.test.ts +13 -0
  12. package/src/ontology/schemas/system/tests/release.test.ts +22 -0
  13. package/src/ontology/schemas/system/tests/text.test.ts +18 -0
  14. package/src/ontology/schemas/system/tests/verification.test.ts +12 -0
  15. package/src/ontology/schemas/tests/biome.test.ts +19 -0
  16. package/src/ontology/schemas/tests/capability.test.ts +22 -0
  17. package/src/ontology/schemas/tests/constellation.test.ts +22 -0
  18. package/src/ontology/schemas/tests/dns-records.test.ts +13 -0
  19. package/src/ontology/schemas/tests/manifest-resolver.test.ts +13 -0
  20. package/src/ontology/schemas/tests/page-entry.test.ts +22 -0
  21. package/src/ontology/schemas/tests/section-archetype.test.ts +12 -0
  22. package/src/ontology/schemas/tests/site-family.test.ts +18 -0
  23. package/src/ontology/schemas/tests/system.test.ts +20 -0
  24. package/src/share/agent/tests/api-catalog.test.ts +8 -0
  25. package/src/share/agent/tests/ard-catalog.test.ts +8 -0
  26. package/src/share/agent/tests/capability.test.ts +14 -0
  27. package/src/share/agent/tests/fleet-catalog.test.ts +15 -0
  28. package/src/share/agent/tests/knowledge.test.ts +20 -0
  29. package/src/share/agent/tests/manifest.test.ts +9 -0
  30. package/src/share/agent/tests/mcp-card.test.ts +8 -0
  31. package/src/share/agent/tests/omit-empty.test.ts +33 -0
  32. package/src/share/agent/tests/openapi.test.ts +8 -0
  33. package/src/share/agent/tests/proof.test.ts +15 -0
  34. package/src/share/knowledge/tests/claim.test.ts +11 -0
  35. package/src/share/knowledge/tests/derivation.test.ts +30 -0
  36. package/src/share/knowledge/tests/freshness.test.ts +18 -0
  37. package/src/share/knowledge/tests/ledger.test.ts +35 -0
  38. package/src/share/knowledge/tests/plan.test.ts +19 -0
  39. package/src/share/knowledge/tests/source.test.ts +19 -0
  40. package/src/share/remediation/remediation-catalog.ts +196 -0
  41. package/src/share/schemas/tests/claim-records.test.ts +52 -0
  42. package/src/share/schemas/tests/claims.test.ts +23 -0
  43. package/src/share/schemas/tests/effects.test.ts +116 -0
  44. package/src/share/schemas/tests/features.test.ts +61 -0
  45. package/src/share/schemas/tests/horizontal-align.test.ts +16 -0
  46. package/src/share/schemas/tests/icon-color.test.ts +16 -0
  47. package/src/share/schemas/tests/live-photo.test.ts +40 -0
  48. package/src/share/schemas/tests/material-credit.test.ts +51 -0
  49. package/src/share/schemas/tests/media.test.ts +26 -0
  50. package/src/share/schemas/tests/navigation.test.ts +58 -0
  51. package/src/share/schemas/tests/page-base.test.ts +19 -0
  52. package/src/share/schemas/tests/participant.test.ts +26 -0
  53. package/src/share/schemas/tests/person.test.ts +12 -0
  54. package/src/share/schemas/tests/print.test.ts +30 -0
  55. package/src/share/schemas/tests/section-background.test.ts +31 -0
  56. package/src/share/schemas/tests/section-body.test.ts +16 -0
  57. package/src/share/schemas/tests/section-cards.test.ts +17 -0
  58. package/src/share/schemas/tests/section-cta.test.ts +41 -0
  59. package/src/share/schemas/tests/section-header.test.ts +31 -0
  60. package/src/share/schemas/tests/section-image.test.ts +24 -0
  61. package/src/share/schemas/tests/section-motion.test.ts +29 -0
  62. package/src/share/schemas/tests/section-shell.test.ts +42 -0
  63. package/src/share/schemas/tests/section-stats.test.ts +17 -0
  64. package/src/share/schemas/tests/site-background.test.ts +33 -0
  65. package/src/share/schemas/tests/standard-list-item.test.ts +16 -0
  66. package/src/share/scripts/tests/external-link-qr.test.ts +8 -0
  67. package/src/share/scripts/tests/external-links.test.ts +25 -0
  68. package/src/share/scripts/tests/gsap-counter.test.ts +8 -0
  69. package/src/share/scripts/tests/gsap-mountain-journey.test.ts +8 -0
  70. package/src/share/scripts/tests/gsap-parallax.test.ts +8 -0
  71. package/src/share/scripts/tests/gsap-reveal.test.ts +8 -0
  72. package/src/share/scripts/tests/gsap-stagger.test.ts +8 -0
  73. package/src/share/scripts/tests/inline-number-animation.test.ts +8 -0
  74. package/src/share/scripts/tests/lenis.test.ts +8 -0
  75. package/src/share/scripts/tests/live-photos.test.ts +8 -0
  76. package/src/share/scripts/tests/lordicon.test.ts +8 -0
  77. package/src/share/scripts/tests/orchestrator.test.ts +8 -0
  78. package/src/share/scripts/tests/scheduler.test.ts +23 -0
  79. package/src/share/semantic/jsonld/tests/article.test.ts +89 -0
  80. package/src/share/semantic/jsonld/tests/breadcrumb.test.ts +62 -0
  81. package/src/share/semantic/jsonld/tests/collection-list.test.ts +39 -0
  82. package/src/share/semantic/jsonld/tests/faq.test.ts +60 -0
  83. package/src/share/semantic/jsonld/tests/initiative.test.ts +56 -0
  84. package/src/share/semantic/jsonld/tests/organization.test.ts +123 -0
  85. package/src/share/semantic/jsonld/tests/person.test.ts +89 -0
  86. package/src/share/semantic/jsonld/tests/service.test.ts +65 -0
  87. package/src/share/semantic/jsonld/tests/shared.test.ts +41 -0
  88. package/src/share/semantic/jsonld/tests/video.test.ts +84 -0
  89. package/src/share/semantic/jsonld/tests/webpage.test.ts +93 -0
  90. package/src/share/semantic/jsonld/tests/website.test.ts +27 -0
  91. package/src/share/semantic/jsonld/types.ts +1 -0
  92. package/src/share/semantic/models.ts +1 -0
  93. package/src/share/semantic/tests/ai.test.ts +55 -0
  94. package/src/share/semantic/tests/block-extraction.test.ts +34 -0
  95. package/src/share/semantic/tests/breadcrumbs.test.ts +127 -0
  96. package/src/share/semantic/tests/build-page.test.ts +122 -0
  97. package/src/share/semantic/tests/business-projection.test.ts +188 -0
  98. package/src/share/semantic/tests/derived-prices-loader.test.ts +46 -0
  99. package/src/share/semantic/tests/extract.test.ts +126 -0
  100. package/src/share/semantic/tests/feed.test.ts +113 -0
  101. package/src/share/semantic/tests/helpers.ts +32 -0
  102. package/src/share/semantic/tests/ids.test.ts +118 -0
  103. package/src/share/semantic/tests/image-sitemap.test.ts +109 -0
  104. package/src/share/semantic/tests/jsonld.test.ts +61 -0
  105. package/src/share/semantic/tests/llms-policy.test.ts +60 -0
  106. package/src/share/semantic/tests/llms.test.ts +118 -0
  107. package/src/share/semantic/tests/markdown-hygiene.test.ts +72 -0
  108. package/src/share/semantic/tests/markdown-page.test.ts +97 -0
  109. package/src/share/semantic/tests/markdown-twin-provenance.test.ts +152 -0
  110. package/src/share/semantic/tests/organization-profile.test.ts +107 -0
  111. package/src/share/semantic/tests/output-projection.test.ts +77 -0
  112. package/src/share/semantic/tests/page-markdown.test.ts +98 -0
  113. package/src/share/semantic/tests/page-utils.test.ts +88 -0
  114. package/src/share/semantic/tests/price-marker-resolver.test.ts +88 -0
  115. package/src/share/semantic/tests/robots.test.ts +70 -0
  116. package/src/share/semantic/tests/update-stamp.test.ts +102 -0
  117. package/src/share/utility-registry.yaml +14 -0
@@ -0,0 +1,8 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { buildApiCatalog } from "../api-catalog.ts";
3
+
4
+ describe("buildApiCatalog", () => {
5
+ it("is a function", () => {
6
+ expect(typeof buildApiCatalog).toBe("function");
7
+ });
8
+ });
@@ -0,0 +1,8 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { buildArdCatalog } from "../ard-catalog.ts";
3
+
4
+ describe("buildArdCatalog", () => {
5
+ it("is a function", () => {
6
+ expect(typeof buildArdCatalog).toBe("function");
7
+ });
8
+ });
@@ -0,0 +1,14 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { resolveActiveCapabilities, capabilityToActionRef } from "../capability.ts";
3
+
4
+ describe("resolveActiveCapabilities", () => {
5
+ it("is a function", () => {
6
+ expect(typeof resolveActiveCapabilities).toBe("function");
7
+ });
8
+ });
9
+
10
+ describe("capabilityToActionRef", () => {
11
+ it("is a function", () => {
12
+ expect(typeof capabilityToActionRef).toBe("function");
13
+ });
14
+ });
@@ -0,0 +1,15 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { FLEET_AGENT_CATALOG_SCHEMA, buildFleetAgentCatalog } from "../fleet-catalog.ts";
3
+
4
+ describe("FLEET_AGENT_CATALOG_SCHEMA", () => {
5
+ it("is a string constant", () => {
6
+ expect(typeof FLEET_AGENT_CATALOG_SCHEMA).toBe("string");
7
+ expect(FLEET_AGENT_CATALOG_SCHEMA).toContain("fleet.agent-catalog");
8
+ });
9
+ });
10
+
11
+ describe("buildFleetAgentCatalog", () => {
12
+ it("is a function", () => {
13
+ expect(typeof buildFleetAgentCatalog).toBe("function");
14
+ });
15
+ });
@@ -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
+ });
@@ -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
+ }
@@ -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
+ });