@thinkingsage/kanon 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (199) hide show
  1. package/CHANGELOG.md +410 -0
  2. package/LICENSE +21 -0
  3. package/README.md +168 -0
  4. package/bridge/mcp-server.cjs +14171 -0
  5. package/package.json +98 -0
  6. package/src/adapters/capabilities.ts +178 -0
  7. package/src/adapters/claude-code.ts +110 -0
  8. package/src/adapters/cline.ts +98 -0
  9. package/src/adapters/codex.ts +173 -0
  10. package/src/adapters/copilot.ts +106 -0
  11. package/src/adapters/cursor.ts +97 -0
  12. package/src/adapters/degradation.ts +95 -0
  13. package/src/adapters/index.ts +324 -0
  14. package/src/adapters/kiro-frontmatter.ts +139 -0
  15. package/src/adapters/kiro-inclusion.ts +86 -0
  16. package/src/adapters/kiro.ts +412 -0
  17. package/src/adapters/qdeveloper.ts +115 -0
  18. package/src/adapters/types.ts +81 -0
  19. package/src/adapters/windsurf.ts +96 -0
  20. package/src/admin.ts +283 -0
  21. package/src/asset-conventions.ts +118 -0
  22. package/src/attribution-backfill.ts +319 -0
  23. package/src/attribution-report.ts +95 -0
  24. package/src/attribution.ts +239 -0
  25. package/src/backends/github.ts +194 -0
  26. package/src/backends/http.ts +122 -0
  27. package/src/backends/index.ts +39 -0
  28. package/src/backends/local.ts +47 -0
  29. package/src/backends/s3.ts +157 -0
  30. package/src/backends/types.ts +59 -0
  31. package/src/base-cache.ts +270 -0
  32. package/src/browse-ui.ts +3754 -0
  33. package/src/browse.ts +1038 -0
  34. package/src/build.ts +1108 -0
  35. package/src/catalog.ts +204 -0
  36. package/src/cli-deprecated.ts +29 -0
  37. package/src/cli.ts +773 -0
  38. package/src/collection-admin.ts +287 -0
  39. package/src/collection-builder.ts +464 -0
  40. package/src/collections.ts +116 -0
  41. package/src/compatibility.ts +105 -0
  42. package/src/config.ts +743 -0
  43. package/src/eval/rubrics/kiro-progressive-steering.ts +841 -0
  44. package/src/eval.ts +1169 -0
  45. package/src/file-writer.ts +61 -0
  46. package/src/format-registry.ts +141 -0
  47. package/src/guild/auto-updater.ts +163 -0
  48. package/src/guild/backend-resolver.ts +49 -0
  49. package/src/guild/cli.ts +592 -0
  50. package/src/guild/collection-expander.ts +47 -0
  51. package/src/guild/global-cache.ts +247 -0
  52. package/src/guild/hook-generator.ts +100 -0
  53. package/src/guild/manifest.ts +154 -0
  54. package/src/guild/path-utils.ts +12 -0
  55. package/src/guild/sync.ts +622 -0
  56. package/src/guild/version-resolver.ts +42 -0
  57. package/src/help/metadata.ts +445 -0
  58. package/src/help/renderer.ts +265 -0
  59. package/src/help/typo-suggester.ts +25 -0
  60. package/src/hooks/expression.ts +493 -0
  61. package/src/hooks/pipeline.ts +141 -0
  62. package/src/import.ts +773 -0
  63. package/src/importers/claude-code.ts +134 -0
  64. package/src/importers/cline.ts +103 -0
  65. package/src/importers/codex.ts +140 -0
  66. package/src/importers/copilot.ts +103 -0
  67. package/src/importers/cursor.ts +105 -0
  68. package/src/importers/index.ts +390 -0
  69. package/src/importers/kiro.ts +110 -0
  70. package/src/importers/qdeveloper.ts +103 -0
  71. package/src/importers/types.ts +54 -0
  72. package/src/importers/windsurf.ts +104 -0
  73. package/src/install.ts +1005 -0
  74. package/src/manifest-admin.ts +306 -0
  75. package/src/mcp-bridge.ts +240 -0
  76. package/src/mutation/delta.ts +50 -0
  77. package/src/mutation/history.ts +66 -0
  78. package/src/mutation/operators.ts +524 -0
  79. package/src/mutation/runner.ts +332 -0
  80. package/src/new.ts +106 -0
  81. package/src/outcomes/collision.ts +127 -0
  82. package/src/outcomes/normalize.ts +208 -0
  83. package/src/outcomes/registry.ts +173 -0
  84. package/src/parser.ts +446 -0
  85. package/src/provenance-backfill-cli.ts +319 -0
  86. package/src/provenance-backfill.ts +520 -0
  87. package/src/publish.ts +354 -0
  88. package/src/reconcile-orchestrator.ts +502 -0
  89. package/src/reconcile-report-renderer.ts +176 -0
  90. package/src/resolve-body.ts +15 -0
  91. package/src/rosetta/builtins/compatibility-profiles.ts +297 -0
  92. package/src/rosetta/builtins/contracts.ts +1033 -0
  93. package/src/rosetta/builtins/pretty-printers/claude-code-native.ts +122 -0
  94. package/src/rosetta/builtins/pretty-printers/cline-native.ts +50 -0
  95. package/src/rosetta/builtins/pretty-printers/codex-native.ts +127 -0
  96. package/src/rosetta/builtins/pretty-printers/copilot-native.ts +50 -0
  97. package/src/rosetta/builtins/pretty-printers/cursor-native.ts +50 -0
  98. package/src/rosetta/builtins/pretty-printers/index.ts +81 -0
  99. package/src/rosetta/builtins/pretty-printers/kiro-native.ts +166 -0
  100. package/src/rosetta/builtins/pretty-printers/kiro-power.ts +108 -0
  101. package/src/rosetta/builtins/pretty-printers/kiro-skill.ts +88 -0
  102. package/src/rosetta/builtins/pretty-printers/qdeveloper-native.ts +51 -0
  103. package/src/rosetta/builtins/pretty-printers/superpowers.ts +97 -0
  104. package/src/rosetta/builtins/pretty-printers/windsurf-native.ts +50 -0
  105. package/src/rosetta/builtins/sources/claude-code-native.ts +348 -0
  106. package/src/rosetta/builtins/sources/cline-native.ts +176 -0
  107. package/src/rosetta/builtins/sources/codex-native.ts +343 -0
  108. package/src/rosetta/builtins/sources/copilot-native.ts +178 -0
  109. package/src/rosetta/builtins/sources/cursor-native.ts +176 -0
  110. package/src/rosetta/builtins/sources/index.ts +95 -0
  111. package/src/rosetta/builtins/sources/kiro-native.ts +462 -0
  112. package/src/rosetta/builtins/sources/kiro-power.ts +285 -0
  113. package/src/rosetta/builtins/sources/kiro-skill.ts +230 -0
  114. package/src/rosetta/builtins/sources/qdeveloper-native.ts +181 -0
  115. package/src/rosetta/builtins/sources/superpowers.ts +240 -0
  116. package/src/rosetta/builtins/sources/windsurf-native.ts +176 -0
  117. package/src/rosetta/builtins/targets/claude-code.ts +181 -0
  118. package/src/rosetta/builtins/targets/cline.ts +87 -0
  119. package/src/rosetta/builtins/targets/codex.ts +226 -0
  120. package/src/rosetta/builtins/targets/copilot.ts +103 -0
  121. package/src/rosetta/builtins/targets/cursor.ts +87 -0
  122. package/src/rosetta/builtins/targets/index.ts +60 -0
  123. package/src/rosetta/builtins/targets/kiro.ts +278 -0
  124. package/src/rosetta/builtins/targets/qdeveloper.ts +103 -0
  125. package/src/rosetta/builtins/targets/windsurf.ts +87 -0
  126. package/src/rosetta/canonical.ts +729 -0
  127. package/src/rosetta/compatibility.ts +432 -0
  128. package/src/rosetta/contracts.ts +329 -0
  129. package/src/rosetta/detector.ts +724 -0
  130. package/src/rosetta/diagnostics.ts +630 -0
  131. package/src/rosetta/engine-bootstrap.ts +103 -0
  132. package/src/rosetta/engine.ts +744 -0
  133. package/src/rosetta/index.ts +381 -0
  134. package/src/rosetta/inspection.ts +530 -0
  135. package/src/rosetta/plan.ts +448 -0
  136. package/src/rosetta/provenance-digest.ts +369 -0
  137. package/src/rosetta/reconcile.ts +812 -0
  138. package/src/rosetta/redaction.ts +467 -0
  139. package/src/rosetta/registry.ts +712 -0
  140. package/src/rosetta/renderers.ts +571 -0
  141. package/src/rosetta/request-guard.ts +335 -0
  142. package/src/rosetta/resolution.ts +419 -0
  143. package/src/rosetta/source-accounting.ts +233 -0
  144. package/src/rosetta/templates.ts +129 -0
  145. package/src/rosetta-cli.ts +717 -0
  146. package/src/rosetta-docs-generator.ts +793 -0
  147. package/src/rosetta-profiles-cli.ts +367 -0
  148. package/src/schemas.ts +1712 -0
  149. package/src/spec-coordination.ts +1141 -0
  150. package/src/temper.ts +747 -0
  151. package/src/template-bundle-loader.ts +312 -0
  152. package/src/template-engine.ts +53 -0
  153. package/src/translation-application-policy.ts +496 -0
  154. package/src/translation-orchestrator.ts +1013 -0
  155. package/src/translation-plan-applier.ts +473 -0
  156. package/src/tutorial.ts +305 -0
  157. package/src/validate.ts +1093 -0
  158. package/src/versioning.ts +553 -0
  159. package/src/wizard.ts +660 -0
  160. package/src/workspace.ts +237 -0
  161. package/templates/eval-contexts/claude-code.md.njk +6 -0
  162. package/templates/eval-contexts/cline.md.njk +6 -0
  163. package/templates/eval-contexts/copilot.md.njk +6 -0
  164. package/templates/eval-contexts/cursor.md.njk +6 -0
  165. package/templates/eval-contexts/kiro.md.njk +10 -0
  166. package/templates/eval-contexts/qdeveloper.md.njk +6 -0
  167. package/templates/eval-contexts/windsurf.md.njk +6 -0
  168. package/templates/harness-adapters/_base/attribution-footer.md.njk +17 -0
  169. package/templates/harness-adapters/_base/base.md.njk +16 -0
  170. package/templates/harness-adapters/claude-code/claude.md.njk +1 -0
  171. package/templates/harness-adapters/claude-code/mcp.json.njk +1 -0
  172. package/templates/harness-adapters/claude-code/settings.json.njk +1 -0
  173. package/templates/harness-adapters/claude-code/skill-library-index.md.njk +13 -0
  174. package/templates/harness-adapters/claude-code/skill.md.njk +19 -0
  175. package/templates/harness-adapters/cline/hook.sh.njk +4 -0
  176. package/templates/harness-adapters/cline/mcp.json.njk +1 -0
  177. package/templates/harness-adapters/cline/rule.md.njk +1 -0
  178. package/templates/harness-adapters/codex/agents-md.md.njk +6 -0
  179. package/templates/harness-adapters/codex/agents-pointer.md.njk +16 -0
  180. package/templates/harness-adapters/codex/skill.md.njk +27 -0
  181. package/templates/harness-adapters/copilot/agents.md.njk +1 -0
  182. package/templates/harness-adapters/copilot/instructions.md.njk +1 -0
  183. package/templates/harness-adapters/copilot/scoped.md.njk +6 -0
  184. package/templates/harness-adapters/cursor/mcp.json.njk +1 -0
  185. package/templates/harness-adapters/cursor/rule.md.njk +6 -0
  186. package/templates/harness-adapters/kiro/hook.json.njk +1 -0
  187. package/templates/harness-adapters/kiro/mcp.json.njk +1 -0
  188. package/templates/harness-adapters/kiro/power-steering.md.njk +3 -0
  189. package/templates/harness-adapters/kiro/power.md.njk +12 -0
  190. package/templates/harness-adapters/kiro/steering.md.njk +16 -0
  191. package/templates/harness-adapters/qdeveloper/agent.md.njk +1 -0
  192. package/templates/harness-adapters/qdeveloper/mcp.json.njk +1 -0
  193. package/templates/harness-adapters/qdeveloper/rule.md.njk +1 -0
  194. package/templates/harness-adapters/windsurf/mcp.json.njk +1 -0
  195. package/templates/harness-adapters/windsurf/rule.md.njk +1 -0
  196. package/templates/harness-adapters/windsurf/workflow.md.njk +1 -0
  197. package/templates/knowledge/hooks.yaml.njk +4 -0
  198. package/templates/knowledge/knowledge.md.njk +53 -0
  199. package/templates/knowledge/mcp-servers.yaml.njk +2 -0
package/src/schemas.ts ADDED
@@ -0,0 +1,1712 @@
1
+ import { z } from "zod";
2
+ import { HARNESS_FORMAT_REGISTRY } from "./format-registry";
3
+
4
+ // --- Harness & Inclusion ---
5
+
6
+ export const SUPPORTED_HARNESSES = [
7
+ "kiro",
8
+ "claude-code",
9
+ "codex",
10
+ "copilot",
11
+ "cursor",
12
+ "windsurf",
13
+ "cline",
14
+ "qdeveloper",
15
+ ] as const;
16
+
17
+ export const HarnessNameSchema = z.enum(SUPPORTED_HARNESSES);
18
+ export type HarnessName = z.infer<typeof HarnessNameSchema>;
19
+
20
+ export const InclusionModeSchema = z.enum([
21
+ "always",
22
+ "auto",
23
+ "fileMatch",
24
+ "manual",
25
+ ]);
26
+ export type InclusionMode = z.infer<typeof InclusionModeSchema>;
27
+
28
+ // --- Kiro Progressive Inclusion ---
29
+
30
+ export const KiroProgressiveInclusionSchema = z.enum([
31
+ "always",
32
+ "fileMatch",
33
+ "manual",
34
+ ]);
35
+ export type KiroProgressiveInclusion = z.infer<
36
+ typeof KiroProgressiveInclusionSchema
37
+ >;
38
+
39
+ export const KiroHarnessConfigSchema = z
40
+ .object({
41
+ format: z.enum(["steering", "power"]).optional(),
42
+ power: z.boolean().optional(),
43
+ inclusion: KiroProgressiveInclusionSchema.optional(),
44
+ fileMatchPattern: z.string().min(1).optional(),
45
+ progressiveWorkflowsStrict: z.boolean().optional(),
46
+ "spec-hooks": z.array(z.record(z.string(), z.unknown())).optional(),
47
+ })
48
+ .passthrough();
49
+
50
+ export const AssetTypeSchema = z.enum([
51
+ "skill",
52
+ // Deprecated alias for "skill" — "power" is Kiro's own output-format
53
+ // concept (harness-config.kiro.format: "power"), not a taxonomy value.
54
+ // Kept valid for backward compat only; canonical going forward is
55
+ // type: "skill" + an explicit harness-config.kiro.format. See ADR-0051.
56
+ "power",
57
+ "rule",
58
+ "workflow",
59
+ "agent",
60
+ "prompt",
61
+ "template",
62
+ "reference-pack",
63
+ ]);
64
+ export type AssetType = z.infer<typeof AssetTypeSchema>;
65
+
66
+ // Backward-compat alias — existing imports of ArtifactTypeSchema continue to compile
67
+ export const ArtifactTypeSchema = AssetTypeSchema;
68
+ export type ArtifactType = AssetType;
69
+
70
+ // --- Bazaar Governance Enums ---
71
+
72
+ export const MaturitySchema = z.enum([
73
+ "experimental",
74
+ "beta",
75
+ "stable",
76
+ "deprecated",
77
+ ]);
78
+ export type Maturity = z.infer<typeof MaturitySchema>;
79
+
80
+ export const TrustLaneSchema = z.enum([
81
+ "official",
82
+ "partner",
83
+ "community",
84
+ "experimental",
85
+ ]);
86
+ export type TrustLane = z.infer<typeof TrustLaneSchema>;
87
+
88
+ export const RiskLevelSchema = z.enum(["low", "medium", "high"]);
89
+ export type RiskLevel = z.infer<typeof RiskLevelSchema>;
90
+
91
+ export const AudienceSchema = z.enum(["beginner", "intermediate", "advanced"]);
92
+ export type Audience = z.infer<typeof AudienceSchema>;
93
+
94
+ // --- Catalog Visibility & Priority (Req 4) ---
95
+
96
+ /**
97
+ * Catalog visibility for an artifact or collection (Req 4.1).
98
+ * - public: listed everywhere (default)
99
+ * - private: excluded entirely from generated catalog.json
100
+ * - unlisted: included in catalog.json but hidden from default browse listings
101
+ */
102
+ export const VisibilitySchema = z
103
+ .enum(["public", "private", "unlisted"])
104
+ .default("public");
105
+ export type Visibility = z.infer<typeof VisibilitySchema>;
106
+
107
+ /**
108
+ * Catalog ordering priority (Req 4.2). Integer 1–100 inclusive, default 50.
109
+ * Higher values sort first in catalog listings.
110
+ */
111
+ export const PrioritySchema = z.number().int().min(1).max(100).default(50);
112
+ export type Priority = z.infer<typeof PrioritySchema>;
113
+
114
+ // --- Collection Manifest ---
115
+
116
+ /**
117
+ * Collection manifests define metadata only — no member list.
118
+ * Membership is declared by artifacts in their own frontmatter via `collections: [...]`.
119
+ */
120
+ export const CollectionSchema = z.object({
121
+ name: z
122
+ .string()
123
+ .min(1)
124
+ .regex(/^[a-z0-9]+(-[a-z0-9]+)*$/, "Collection name must be kebab-case"),
125
+ displayName: z.string().min(1),
126
+ description: z.string().default(""),
127
+ version: z.string().default("0.1.0"),
128
+ author: z.string().default(""),
129
+ trust: TrustLaneSchema.optional(),
130
+ tags: z.array(z.string()).default([]),
131
+ harnesses: z.array(HarnessNameSchema).optional(),
132
+ visibility: VisibilitySchema.optional(),
133
+ priority: PrioritySchema.optional(),
134
+ });
135
+ export type Collection = z.infer<typeof CollectionSchema>;
136
+
137
+ // --- Canonical Events & Actions ---
138
+
139
+ export const CanonicalEventSchema = z.enum([
140
+ "file_edited",
141
+ "file_created",
142
+ "file_deleted",
143
+ "agent_stop",
144
+ "prompt_submit",
145
+ "pre_tool_use",
146
+ "post_tool_use",
147
+ "pre_task",
148
+ "post_task",
149
+ "user_triggered",
150
+ ]);
151
+ export type CanonicalEvent = z.infer<typeof CanonicalEventSchema>;
152
+
153
+ export const CanonicalActionSchema = z.discriminatedUnion("type", [
154
+ z.object({ type: z.literal("ask_agent"), prompt: z.string().min(1) }),
155
+ z.object({ type: z.literal("run_command"), command: z.string().min(1) }),
156
+ ]);
157
+ export type CanonicalAction = z.infer<typeof CanonicalActionSchema>;
158
+
159
+ // --- Canonical Hook ---
160
+
161
+ /**
162
+ * A value that a DES-style hook may write into shared state (Req 3.5).
163
+ * Restricted to string or boolean so gate/postcondition expressions can
164
+ * compare against string/boolean literals deterministically.
165
+ */
166
+ export const HookStateValueSchema = z.union([z.string(), z.boolean()]);
167
+ export type HookStateValue = z.infer<typeof HookStateValueSchema>;
168
+
169
+ export const CanonicalHookSchema = z.object({
170
+ name: z.string().min(1),
171
+ description: z.string().optional(),
172
+ event: CanonicalEventSchema,
173
+ condition: z
174
+ .object({
175
+ file_patterns: z.array(z.string()).optional(),
176
+ tool_types: z.array(z.string()).optional(),
177
+ })
178
+ .optional(),
179
+ action: CanonicalActionSchema,
180
+ // DES-style hook execution (Req 3). All optional — hooks without these
181
+ // fields behave exactly as before.
182
+ /** Boolean precondition expression; the action runs only when it holds (Req 3.1). */
183
+ gate: z.string().optional(),
184
+ /** Boolean expression checked after the action; failure halts the run (Req 3.3). */
185
+ postcondition: z.string().optional(),
186
+ /** State keys this hook writes, visible to later hooks' expressions (Req 3.5). */
187
+ state: z.record(z.string(), HookStateValueSchema).optional(),
188
+ });
189
+ export type CanonicalHook = z.infer<typeof CanonicalHookSchema>;
190
+
191
+ export const HooksFileSchema = z.array(CanonicalHookSchema);
192
+
193
+ // --- MCP Server Definition ---
194
+
195
+ /**
196
+ * Stdio-based MCP server (command + args).
197
+ */
198
+ export const StdioMcpServerSchema = z.object({
199
+ name: z.string().min(1),
200
+ transport: z.literal("stdio").default("stdio"),
201
+ command: z.string().min(1),
202
+ args: z.array(z.string()).default([]),
203
+ env: z.record(z.string(), z.string()).default({}),
204
+ timeout: z.number().optional(),
205
+ autoApprove: z.array(z.string()).optional(),
206
+ disabled: z.boolean().optional(),
207
+ });
208
+ export type StdioMcpServer = z.infer<typeof StdioMcpServerSchema>;
209
+
210
+ /**
211
+ * URL-based MCP server (SSE or HTTP streamable).
212
+ */
213
+ export const UrlMcpServerSchema = z.object({
214
+ name: z.string().min(1),
215
+ transport: z.enum(["sse", "http"]),
216
+ url: z.string().url(),
217
+ env: z.record(z.string(), z.string()).default({}),
218
+ timeout: z.number().optional(),
219
+ autoApprove: z.array(z.string()).optional(),
220
+ disabled: z.boolean().optional(),
221
+ });
222
+ export type UrlMcpServer = z.infer<typeof UrlMcpServerSchema>;
223
+
224
+ /**
225
+ * Preprocessor that infers transport from shape:
226
+ * - Has `url` → URL-based (default to "sse" if transport not specified)
227
+ * - Has `command` → stdio (default to "stdio" if transport not specified)
228
+ */
229
+ const McpServerPreprocess = z.preprocess(
230
+ (val) => {
231
+ if (val && typeof val === "object" && !Array.isArray(val)) {
232
+ const obj = val as Record<string, unknown>;
233
+ if (!obj.transport) {
234
+ if ("url" in obj) {
235
+ return { ...obj, transport: "sse" };
236
+ }
237
+ return { ...obj, transport: "stdio" };
238
+ }
239
+ }
240
+ return val;
241
+ },
242
+ z.union([StdioMcpServerSchema, UrlMcpServerSchema]),
243
+ );
244
+
245
+ /**
246
+ * Union of stdio and URL-based MCP server definitions.
247
+ * Accepts objects without `transport` — infers from shape.
248
+ */
249
+ export const McpServerDefinitionSchema = McpServerPreprocess;
250
+ export type McpServerDefinition = StdioMcpServer | UrlMcpServer;
251
+
252
+ /** Type guard: is this a stdio-based server? */
253
+ export function isStdioServer(
254
+ server: McpServerDefinition,
255
+ ): server is StdioMcpServer {
256
+ // Handle objects that bypass Zod parsing (e.g. test fixtures without transport)
257
+ const s = server as Record<string, unknown>;
258
+ if (!s.transport || s.transport === "stdio") return "command" in s;
259
+ return false;
260
+ }
261
+
262
+ /** Type guard: is this a URL-based server? */
263
+ export function isUrlServer(
264
+ server: McpServerDefinition,
265
+ ): server is UrlMcpServer {
266
+ return server.transport === "sse" || server.transport === "http";
267
+ }
268
+
269
+ export const McpServersFileSchema = z.array(McpServerDefinitionSchema);
270
+
271
+ // --- Category Taxonomy ---
272
+
273
+ export const CATEGORIES = [
274
+ "testing",
275
+ "security",
276
+ "code-style",
277
+ "devops",
278
+ "documentation",
279
+ "architecture",
280
+ "debugging",
281
+ "performance",
282
+ "accessibility",
283
+ "writing",
284
+ ] as const;
285
+
286
+ export const CategoryEnum = z.enum(CATEGORIES);
287
+ export type Category = z.infer<typeof CategoryEnum>;
288
+
289
+ // --- Outcomes Registry ---
290
+
291
+ /**
292
+ * The kind of an outcome declaration.
293
+ * - specification: a declarative description of expected behavior
294
+ * - operation: an action/transformation with input → output shapes
295
+ * - invariant: a property that must hold
296
+ */
297
+ export const OutcomeKindSchema = z.enum([
298
+ "specification",
299
+ "operation",
300
+ "invariant",
301
+ ]);
302
+ export type OutcomeKind = z.infer<typeof OutcomeKindSchema>;
303
+
304
+ /**
305
+ * A formal outcome declaration (Req 2B). Outcomes capture an artifact's
306
+ * intended input/output shapes plus keywords for two-tier collision detection.
307
+ * IDs must be globally unique kebab-case identifiers prefixed with `out-`.
308
+ */
309
+ export const OutcomeSchema = z.object({
310
+ id: z
311
+ .string()
312
+ .regex(
313
+ /^out-[a-z0-9]+(-[a-z0-9]+)*$/,
314
+ "Outcome id must match out-kebab-case",
315
+ )
316
+ .max(64),
317
+ kind: OutcomeKindSchema,
318
+ inputShape: z.string().min(1),
319
+ outputShape: z.string().min(1),
320
+ summary: z.string().max(120),
321
+ keywords: z.array(z.string().max(24)).max(6).default([]),
322
+ related: z.array(z.string()).default([]),
323
+ });
324
+ export type Outcome = z.infer<typeof OutcomeSchema>;
325
+
326
+ // --- Frontmatter ---
327
+
328
+ export const FrontmatterSchema = z
329
+ .object({
330
+ name: z.string().min(1),
331
+ displayName: z.string().optional(),
332
+ description: z.string().default(""),
333
+ keywords: z.array(z.string()).default([]),
334
+ author: z.string().default(""),
335
+ version: z
336
+ .string()
337
+ .regex(
338
+ /^\d+\.\d+\.\d+$/,
339
+ "Version must be a valid semver string (e.g. 1.2.3)",
340
+ )
341
+ .default("0.1.0"),
342
+ migrations: z.boolean().optional(),
343
+ harnesses: z.array(HarnessNameSchema).default([...SUPPORTED_HARNESSES]),
344
+ type: ArtifactTypeSchema.default("skill"),
345
+ inclusion: InclusionModeSchema.default("always"),
346
+ file_patterns: z.array(z.string()).optional(),
347
+ categories: z.array(CategoryEnum).default([]),
348
+ ecosystem: z
349
+ .array(
350
+ z
351
+ .string()
352
+ .min(1)
353
+ .regex(/^[a-z0-9]+(-[a-z0-9]+)*$/),
354
+ )
355
+ .default([]),
356
+ depends: z
357
+ .array(
358
+ z
359
+ .string()
360
+ .min(1)
361
+ .regex(/^[a-z0-9]+(-[a-z0-9]+)*$/),
362
+ )
363
+ .default([]),
364
+ enhances: z
365
+ .array(
366
+ z
367
+ .string()
368
+ .min(1)
369
+ .regex(/^[a-z0-9]+(-[a-z0-9]+)*$/),
370
+ )
371
+ .default([]),
372
+ // Bazaar manifest fields
373
+ id: z
374
+ .string()
375
+ .regex(/^@[a-z0-9-]+\/[a-z0-9-]+$/)
376
+ .optional(),
377
+ license: z.string().optional(),
378
+ maturity: MaturitySchema.default("experimental"),
379
+ trust: TrustLaneSchema.optional(),
380
+ "risk-level": RiskLevelSchema.optional(),
381
+ audience: AudienceSchema.optional(),
382
+ "model-assumptions": z.array(z.string()).default([]),
383
+ successor: z.string().optional(),
384
+ replaces: z.string().optional(),
385
+ collections: z
386
+ .array(
387
+ z
388
+ .string()
389
+ .min(1)
390
+ .regex(/^[a-z0-9]+(-[a-z0-9]+)*$/),
391
+ )
392
+ .default([]),
393
+ "inherit-hooks": z.boolean().default(false),
394
+ visibility: VisibilitySchema.optional(),
395
+ priority: PrioritySchema.optional(),
396
+ outcomes: z.array(OutcomeSchema).default([]),
397
+ // Machine-managed distillation provenance (see ProvenanceRecordSchema).
398
+ // Written by the import/acquisition path, never hand-edited. Absent for
399
+ // artifacts authored from scratch. Defined later in this file, so we
400
+ // reference it lazily to avoid a temporal-dead-zone error.
401
+ provenance: z.lazy(() => ProvenanceRecordSchema).optional(),
402
+ // Curation-owned human/legal attribution (see AttributionRecordSchema and
403
+ // ADR-0064). Additive to `author` (which stays as the display string);
404
+ // captured by the import Attribution_Wizard, preserved across re-sync.
405
+ // Referenced lazily since AttributionRecordSchema is defined later.
406
+ attribution: z.lazy(() => AttributionRecordSchema).optional(),
407
+ })
408
+ .passthrough()
409
+ .superRefine((data, ctx) => {
410
+ const harnessConfig = data["harness-config"] as
411
+ | Record<string, Record<string, unknown>>
412
+ | undefined;
413
+ if (!harnessConfig || typeof harnessConfig !== "object") return;
414
+
415
+ for (const [harness, config] of Object.entries(harnessConfig)) {
416
+ if (!config || typeof config !== "object" || !("format" in config))
417
+ continue;
418
+
419
+ const registryEntry = HARNESS_FORMAT_REGISTRY[harness as HarnessName];
420
+ if (!registryEntry) continue;
421
+
422
+ const formatValue = config.format as string;
423
+ if (!registryEntry.formats.includes(formatValue)) {
424
+ ctx.addIssue({
425
+ code: z.ZodIssueCode.custom,
426
+ path: ["harness-config", harness, "format"],
427
+ message: `Invalid format "${formatValue}" for harness "${harness}". Valid values: ${registryEntry.formats.join(", ")}`,
428
+ });
429
+ }
430
+ }
431
+
432
+ // Validate kiro-specific harness-config through KiroHarnessConfigSchema
433
+ const kiroConfig = harnessConfig.kiro;
434
+ if (kiroConfig && typeof kiroConfig === "object") {
435
+ const result = KiroHarnessConfigSchema.safeParse(kiroConfig);
436
+ if (!result.success) {
437
+ for (const issue of result.error.issues) {
438
+ ctx.addIssue({
439
+ code: z.ZodIssueCode.custom,
440
+ path: ["harness-config", "kiro", ...issue.path.map(String)],
441
+ message: issue.message,
442
+ });
443
+ }
444
+ }
445
+ }
446
+ });
447
+ export type Frontmatter = z.infer<typeof FrontmatterSchema>;
448
+
449
+ // --- Workflow File ---
450
+
451
+ export const WorkflowFileSchema = z.object({
452
+ name: z.string(),
453
+ filename: z.string(),
454
+ content: z.string(),
455
+ });
456
+ export type WorkflowFile = z.infer<typeof WorkflowFileSchema>;
457
+
458
+ // --- Knowledge Artifact ---
459
+
460
+ export const KnowledgeArtifactSchema = z.object({
461
+ name: z.string().min(1),
462
+ frontmatter: FrontmatterSchema,
463
+ body: z.string(),
464
+ hooks: z.array(CanonicalHookSchema).default([]),
465
+ mcpServers: z.array(McpServerDefinitionSchema).default([]),
466
+ workflows: z.array(WorkflowFileSchema).default([]),
467
+ sourcePath: z.string(),
468
+ extraFields: z.record(z.string(), z.unknown()).default({}),
469
+ // Per-harness body overrides, keyed by harness name. Loaded from optional
470
+ // `body.<harness>.md` sibling files. Empty when no override files exist.
471
+ bodyOverrides: z.record(z.string(), z.string()).default({}),
472
+ });
473
+ export type KnowledgeArtifact = z.infer<typeof KnowledgeArtifactSchema>;
474
+
475
+ // --- Catalog ---
476
+
477
+ export const CatalogEntrySchema = z.object({
478
+ name: z.string(),
479
+ displayName: z.string(),
480
+ description: z.string(),
481
+ keywords: z.array(z.string()),
482
+ author: z.string(),
483
+ version: z.string(),
484
+ harnesses: z.array(HarnessNameSchema),
485
+ type: AssetTypeSchema,
486
+ path: z.string(),
487
+ evals: z.boolean().default(false),
488
+ categories: z.array(CategoryEnum),
489
+ ecosystem: z.array(z.string()),
490
+ depends: z.array(z.string()),
491
+ enhances: z.array(z.string()),
492
+ formatByHarness: z.record(z.string(), z.string()).optional(),
493
+ changelog: z.boolean().default(false),
494
+ migrations: z.boolean().default(false),
495
+ // Feature flags — derived from artifact content at catalog generation time
496
+ features: z
497
+ .object({
498
+ hooks: z.boolean().default(false),
499
+ mcp: z.boolean().default(false),
500
+ workflows: z.boolean().default(false),
501
+ conditionalInclusion: z.boolean().default(false),
502
+ })
503
+ .default(() => ({
504
+ hooks: false,
505
+ mcp: false,
506
+ workflows: false,
507
+ conditionalInclusion: false,
508
+ })),
509
+ // Bazaar manifest fields
510
+ id: z.string().optional(),
511
+ license: z.string().optional(),
512
+ maturity: MaturitySchema,
513
+ trust: TrustLaneSchema.optional(),
514
+ "risk-level": RiskLevelSchema.optional(),
515
+ audience: AudienceSchema.optional(),
516
+ "model-assumptions": z.array(z.string()),
517
+ successor: z.string().optional(),
518
+ replaces: z.string().optional(),
519
+ collections: z.array(z.string()).default([]),
520
+ // Projected human/legal attribution (ADR-0064). Copied verbatim from the
521
+ // artifact's curation-owned `attribution` block during catalog generation;
522
+ // powers the gallery relationship chip and the detail "Sources & credits".
523
+ attribution: z.lazy(() => AttributionRecordSchema).optional(),
524
+ // Catalog visibility & ordering (Req 4.4, 4.6)
525
+ visibility: VisibilitySchema,
526
+ priority: PrioritySchema,
527
+ // Outcomes registry — projected subset for external discovery (Req 2H.2)
528
+ outcomes: z
529
+ .array(
530
+ z.object({
531
+ id: z.string(),
532
+ kind: OutcomeKindSchema,
533
+ inputShape: z.string(),
534
+ outputShape: z.string(),
535
+ keywords: z.array(z.string()),
536
+ }),
537
+ )
538
+ .default([]),
539
+ });
540
+ export type CatalogEntry = z.infer<typeof CatalogEntrySchema>;
541
+
542
+ export const CatalogSchema = z.array(CatalogEntrySchema);
543
+
544
+ // --- Capability Matrix ---
545
+
546
+ export const SupportLevelSchema = z.enum(["full", "partial", "none"]);
547
+ export type SupportLevel = z.infer<typeof SupportLevelSchema>;
548
+
549
+ export const DegradationStrategySchema = z.enum(["inline", "comment", "omit"]);
550
+ export type DegradationStrategy = z.infer<typeof DegradationStrategySchema>;
551
+
552
+ export const CapabilityEntrySchema = z
553
+ .object({
554
+ support: SupportLevelSchema,
555
+ degradation: DegradationStrategySchema.optional(),
556
+ })
557
+ .refine(
558
+ (entry) => entry.support === "full" || entry.degradation !== undefined,
559
+ { message: "Degradation strategy required when support is not 'full'" },
560
+ );
561
+ export type CapabilityEntry = z.infer<typeof CapabilityEntrySchema>;
562
+
563
+ // --- Validation ---
564
+
565
+ export const ValidationErrorSchema = z.object({
566
+ field: z.string(),
567
+ message: z.string(),
568
+ filePath: z.string(),
569
+ line: z.number().optional(),
570
+ });
571
+ export type ValidationError = z.infer<typeof ValidationErrorSchema>;
572
+
573
+ export const ValidationWarningSchema = z.object({
574
+ field: z.string(),
575
+ message: z.string(),
576
+ filePath: z.string(),
577
+ });
578
+ export type ValidationWarning = z.infer<typeof ValidationWarningSchema>;
579
+
580
+ export const ValidationResultSchema = z.object({
581
+ artifactName: z.string(),
582
+ valid: z.boolean(),
583
+ errors: z.array(ValidationErrorSchema),
584
+ warnings: z.array(ValidationWarningSchema).optional(),
585
+ });
586
+ export type ValidationResult = z.infer<typeof ValidationResultSchema>;
587
+
588
+ // --- Workspace Config ---
589
+
590
+ export const WorkspaceProjectSchema = z.object({
591
+ name: z.string().min(1),
592
+ root: z.string().min(1),
593
+ harnesses: z.array(HarnessNameSchema).min(1),
594
+ artifacts: z
595
+ .object({
596
+ include: z.array(z.string()).optional(),
597
+ exclude: z.array(z.string()).optional(),
598
+ })
599
+ .optional(),
600
+ overrides: z.record(z.string(), z.record(z.string(), z.unknown())).optional(),
601
+ });
602
+ export type WorkspaceProject = z.infer<typeof WorkspaceProjectSchema>;
603
+
604
+ export const WorkspaceConfigSchema = z.object({
605
+ knowledgeSources: z.array(z.string()).min(1),
606
+ sharedMcpServers: z.string().optional(),
607
+ defaults: z
608
+ .object({
609
+ harnesses: z.array(HarnessNameSchema).optional(),
610
+ buildOptions: z.record(z.string(), z.unknown()).optional(),
611
+ })
612
+ .optional(),
613
+ projects: z.array(WorkspaceProjectSchema).min(1),
614
+ });
615
+ export type WorkspaceConfig = z.infer<typeof WorkspaceConfigSchema>;
616
+
617
+ // --- Temper Output ---
618
+
619
+ export const TemperSectionSchema = z.object({
620
+ title: z.string(),
621
+ content: z.string(),
622
+ type: z.enum([
623
+ "system-prompt",
624
+ "steering",
625
+ "hooks",
626
+ "mcp-servers",
627
+ "degradation-report",
628
+ ]),
629
+ });
630
+ export type TemperSection = z.infer<typeof TemperSectionSchema>;
631
+
632
+ export const TemperOutputSchema = z.object({
633
+ artifactName: z.string(),
634
+ harnessName: z.string(),
635
+ sections: z.array(TemperSectionSchema),
636
+ degradations: z.array(z.string()),
637
+ fileCount: z.number(),
638
+ hooksTranslated: z.number(),
639
+ hooksDegraded: z.number(),
640
+ mcpServers: z.array(z.string()),
641
+ });
642
+ export type TemperOutput = z.infer<typeof TemperOutputSchema>;
643
+
644
+ // --- Version Manifest ---
645
+
646
+ export const VersionManifestSchema = z.object({
647
+ artifactName: z.string().min(1),
648
+ version: z.string().regex(/^\d+\.\d+\.\d+$/),
649
+ harnessName: z.string().min(1),
650
+ sourcePath: z.string().min(1),
651
+ installedAt: z.string().datetime(),
652
+ files: z.array(z.string()),
653
+ });
654
+ export type VersionManifest = z.infer<typeof VersionManifestSchema>;
655
+
656
+ // ═══════════════════════════════════════════════════════════════════════════════
657
+ // Rosetta Stone — Public Schemas and Types
658
+ // ═══════════════════════════════════════════════════════════════════════════════
659
+ //
660
+ // All Rosetta Stone data shapes are defined here with Zod 4 and exported with
661
+ // inferred TypeScript types. Rosetta modules compose but never redefine these
662
+ // public schemas. Schemas use .strict() unless an explicit extension map exists.
663
+ //
664
+ // Requirements: 1.2, 2.4, 8.1, 8.2, 8.6, 13.1, 15.3
665
+ // ═══════════════════════════════════════════════════════════════════════════════
666
+
667
+ // --- Rosetta Primitives and Version Schemas ---
668
+
669
+ /** SemVer pattern for canonical schema versions */
670
+ const SEMVER_PATTERN =
671
+ /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
672
+
673
+ /**
674
+ * Validates a normalized relative path.
675
+ * Rules:
676
+ * - Uses `/` separator only
677
+ * - Unicode NFC normalized
678
+ * - No empty or `.` segments
679
+ * - No `..` (traversal)
680
+ * - No absolute/root/drive/UNC prefix
681
+ * - No NUL character
682
+ */
683
+ function validateRelativePath(val: string, ctx: z.RefinementCtx): void {
684
+ if (val.length === 0) {
685
+ ctx.addIssue({
686
+ code: z.ZodIssueCode.custom,
687
+ message: "Path must not be empty",
688
+ });
689
+ return;
690
+ }
691
+ if (val.includes("\0")) {
692
+ ctx.addIssue({
693
+ code: z.ZodIssueCode.custom,
694
+ message: "Path must not contain NUL character",
695
+ });
696
+ return;
697
+ }
698
+ // Reject absolute/drive/UNC prefixes
699
+ if (val.startsWith("/") || val.startsWith("\\")) {
700
+ ctx.addIssue({
701
+ code: z.ZodIssueCode.custom,
702
+ message: "Path must not be absolute",
703
+ });
704
+ return;
705
+ }
706
+ if (/^[A-Za-z]:/.test(val)) {
707
+ ctx.addIssue({
708
+ code: z.ZodIssueCode.custom,
709
+ message: "Path must not contain a drive prefix",
710
+ });
711
+ return;
712
+ }
713
+ if (val.startsWith("\\\\") || val.startsWith("//")) {
714
+ ctx.addIssue({
715
+ code: z.ZodIssueCode.custom,
716
+ message: "Path must not be a UNC path",
717
+ });
718
+ return;
719
+ }
720
+ // Check NFC normalization
721
+ if (val !== val.normalize("NFC")) {
722
+ ctx.addIssue({
723
+ code: z.ZodIssueCode.custom,
724
+ message: "Path must be Unicode NFC normalized",
725
+ });
726
+ return;
727
+ }
728
+ // Only forward slashes
729
+ if (val.includes("\\")) {
730
+ ctx.addIssue({
731
+ code: z.ZodIssueCode.custom,
732
+ message: "Path must use '/' separator only",
733
+ });
734
+ return;
735
+ }
736
+ // Check segments
737
+ const segments = val.split("/");
738
+ for (const seg of segments) {
739
+ if (seg === "") {
740
+ ctx.addIssue({
741
+ code: z.ZodIssueCode.custom,
742
+ message: "Path must not contain empty segments",
743
+ });
744
+ return;
745
+ }
746
+ if (seg === ".") {
747
+ ctx.addIssue({
748
+ code: z.ZodIssueCode.custom,
749
+ message: "Path must not contain '.' segments",
750
+ });
751
+ return;
752
+ }
753
+ if (seg === "..") {
754
+ ctx.addIssue({
755
+ code: z.ZodIssueCode.custom,
756
+ message: "Path must not contain '..' traversal",
757
+ });
758
+ return;
759
+ }
760
+ }
761
+ }
762
+
763
+ export const FormatIdentifierSchema = z
764
+ .string()
765
+ .regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/);
766
+ export type FormatIdentifier = z.infer<typeof FormatIdentifierSchema>;
767
+
768
+ export const NormalizedRelativePathSchema = z
769
+ .string()
770
+ .superRefine(validateRelativePath);
771
+ export type NormalizedRelativePath = z.infer<
772
+ typeof NormalizedRelativePathSchema
773
+ >;
774
+
775
+ export const ContractVersionSchema = z.literal("1.0");
776
+ export type ContractVersion = z.infer<typeof ContractVersionSchema>;
777
+
778
+ export const CanonicalSchemaVersionSchema = z.string().regex(SEMVER_PATTERN);
779
+ export type CanonicalSchemaVersion = z.infer<
780
+ typeof CanonicalSchemaVersionSchema
781
+ >;
782
+
783
+ export const LifecycleStatusSchema = z.enum([
784
+ "experimental",
785
+ "active",
786
+ "deprecated",
787
+ "retired",
788
+ ]);
789
+ export type LifecycleStatus = z.infer<typeof LifecycleStatusSchema>;
790
+
791
+ export const DirectionSchema = z.enum(["source", "target", "bidirectional"]);
792
+ export type Direction = z.infer<typeof DirectionSchema>;
793
+
794
+ export const RosettaSeveritySchema = z.enum(["info", "warning", "error"]);
795
+ export type RosettaSeverity = z.infer<typeof RosettaSeveritySchema>;
796
+
797
+ // --- Recursive JSON Value ---
798
+
799
+ export type JsonValue =
800
+ | null
801
+ | boolean
802
+ | number
803
+ | string
804
+ | JsonValue[]
805
+ | { [key: string]: JsonValue };
806
+
807
+ export const JsonValueSchema: z.ZodType<JsonValue> = z.lazy(() =>
808
+ z.union([
809
+ z.null(),
810
+ z.boolean(),
811
+ z.number().finite(),
812
+ z.string(),
813
+ z.array(JsonValueSchema),
814
+ z.record(z.string(), JsonValueSchema),
815
+ ]),
816
+ );
817
+
818
+ // --- Source Documents ---
819
+
820
+ export const SourceDocumentSchema = z
821
+ .object({
822
+ path: NormalizedRelativePathSchema,
823
+ content: z.union([z.string(), z.instanceof(Uint8Array)]),
824
+ mediaType: z.string().optional(),
825
+ executable: z.boolean().default(false),
826
+ })
827
+ .strict();
828
+ export type SourceDocument = z.infer<typeof SourceDocumentSchema>;
829
+ export type SourceDocumentInput = z.input<typeof SourceDocumentSchema>;
830
+
831
+ // --- Lifecycle Metadata ---
832
+
833
+ export const LifecycleMetadataSchema = z
834
+ .object({
835
+ status: LifecycleStatusSchema,
836
+ introducedIn: CanonicalSchemaVersionSchema,
837
+ deprecatedIn: CanonicalSchemaVersionSchema.optional(),
838
+ retiredIn: CanonicalSchemaVersionSchema.optional(),
839
+ replacement: FormatIdentifierSchema.optional(),
840
+ })
841
+ .strict();
842
+ export type LifecycleMetadata = z.infer<typeof LifecycleMetadataSchema>;
843
+
844
+ // --- Canonical Version Range ---
845
+
846
+ export const CanonicalVersionRangeSchema = z
847
+ .object({
848
+ minInclusive: CanonicalSchemaVersionSchema,
849
+ maxExclusive: CanonicalSchemaVersionSchema,
850
+ })
851
+ .strict();
852
+ export type CanonicalVersionRange = z.infer<typeof CanonicalVersionRangeSchema>;
853
+
854
+ // --- Schema Reference ---
855
+
856
+ export const SchemaReferenceSchema = z
857
+ .object({
858
+ type: z.enum(["zod", "json-schema", "grammar", "none"]),
859
+ location: z.string().optional(),
860
+ description: z.string().optional(),
861
+ })
862
+ .strict();
863
+ export type SchemaReference = z.infer<typeof SchemaReferenceSchema>;
864
+
865
+ // --- Path Convention ---
866
+
867
+ export const PathConventionSchema = z
868
+ .object({
869
+ pattern: z.string().min(1),
870
+ required: z.boolean().default(false),
871
+ description: z.string().optional(),
872
+ })
873
+ .strict();
874
+ export type PathConvention = z.infer<typeof PathConventionSchema>;
875
+
876
+ // --- Detection Rule Kinds and Contract ---
877
+
878
+ export const DetectionRuleKindSchema = z.enum([
879
+ "path-glob",
880
+ "basename",
881
+ "extension",
882
+ "content-marker",
883
+ "frontmatter-key",
884
+ "json-pointer",
885
+ "yaml-key",
886
+ ]);
887
+ export type DetectionRuleKind = z.infer<typeof DetectionRuleKindSchema>;
888
+
889
+ export const DetectionRuleSchema = z
890
+ .object({
891
+ id: z.string().min(1),
892
+ kind: DetectionRuleKindSchema,
893
+ pattern: z.string().min(1),
894
+ weight: z.number().int(),
895
+ required: z.boolean().default(false),
896
+ evidenceLabel: z.string().min(1),
897
+ maxParseBytes: z.number().int().positive().optional(),
898
+ })
899
+ .strict();
900
+ export type DetectionRule = z.infer<typeof DetectionRuleSchema>;
901
+
902
+ export const DetectionContractSchema = z
903
+ .object({
904
+ threshold: z.number().min(0).max(1),
905
+ rules: z.array(DetectionRuleSchema),
906
+ })
907
+ .strict();
908
+ export type DetectionContract = z.infer<typeof DetectionContractSchema>;
909
+
910
+ // --- Variant Contract ---
911
+
912
+ export const VariantContractSchema = z
913
+ .object({
914
+ id: FormatIdentifierSchema,
915
+ description: z.string().optional(),
916
+ pathConventions: z.array(PathConventionSchema).default([]),
917
+ defaults: z.record(z.string(), JsonValueSchema).default({}),
918
+ optionOverrides: z.record(z.string(), JsonValueSchema).default({}),
919
+ })
920
+ .strict();
921
+ export type VariantContract = z.infer<typeof VariantContractSchema>;
922
+
923
+ // --- Format Option Definition ---
924
+
925
+ export const FormatOptionDefinitionSchema = z
926
+ .object({
927
+ type: z.enum(["string", "boolean", "number", "enum"]),
928
+ description: z.string().min(1),
929
+ required: z.boolean().default(false),
930
+ defaultValue: JsonValueSchema.optional(),
931
+ enumValues: z.array(z.string()).optional(),
932
+ effective: z.boolean().default(true),
933
+ })
934
+ .strict();
935
+ export type FormatOptionDefinition = z.infer<
936
+ typeof FormatOptionDefinitionSchema
937
+ >;
938
+
939
+ // --- Normalization Rule ---
940
+
941
+ export const NormalizationRuleSchema = z
942
+ .object({
943
+ id: z.string().min(1),
944
+ description: z.string().min(1),
945
+ scope: z.enum(["source", "canonical", "both"]),
946
+ })
947
+ .strict();
948
+ export type NormalizationRule = z.infer<typeof NormalizationRuleSchema>;
949
+
950
+ // --- Format Security Policy ---
951
+
952
+ export const FormatSecurityPolicySchema = z
953
+ .object({
954
+ sensitiveValuePolicy: z.enum(["reject", "preserve", "reference-only"]),
955
+ allowedReferencePatterns: z.array(z.string()).default([]),
956
+ })
957
+ .strict();
958
+ export type FormatSecurityPolicy = z.infer<typeof FormatSecurityPolicySchema>;
959
+
960
+ // --- Canonical Capability ---
961
+
962
+ /** Closed enum of all translatable KnowledgeArtifact capabilities */
963
+ export const CanonicalCapabilitySchema = z.enum([
964
+ "frontmatter",
965
+ "body",
966
+ "hooks",
967
+ "mcp-servers",
968
+ "workflows",
969
+ "body-overrides",
970
+ "extra-fields",
971
+ "path-scoping",
972
+ "toggleable-rules",
973
+ "file-match-inclusion",
974
+ "system-prompt-merging",
975
+ // Asset-type capabilities (one per AssetTypeSchema value)
976
+ "skill",
977
+ "power",
978
+ "rule",
979
+ "workflow",
980
+ "agent",
981
+ "prompt",
982
+ "template",
983
+ "reference-pack",
984
+ ]);
985
+ export type CanonicalCapability = z.infer<typeof CanonicalCapabilitySchema>;
986
+
987
+ // --- Rosetta Compatibility Profile ---
988
+
989
+ /**
990
+ * Compatibility entry for the Rosetta Stone. Reuses the same support/degradation
991
+ * semantics as the existing CapabilityEntrySchema but is independent to allow
992
+ * future divergence and keeps the Rosetta boundary self-contained.
993
+ */
994
+ export const RosettaCompatibilityEntrySchema = z
995
+ .object({
996
+ support: SupportLevelSchema,
997
+ degradation: DegradationStrategySchema.optional(),
998
+ })
999
+ .strict()
1000
+ .refine(
1001
+ (entry) =>
1002
+ entry.support === "full"
1003
+ ? entry.degradation === undefined
1004
+ : entry.degradation !== undefined,
1005
+ {
1006
+ message:
1007
+ "Degradation action is required for 'partial'/'none' and forbidden for 'full'",
1008
+ },
1009
+ );
1010
+ export type RosettaCompatibilityEntry = z.infer<
1011
+ typeof RosettaCompatibilityEntrySchema
1012
+ >;
1013
+
1014
+ /**
1015
+ * A complete compatibility profile: every canonical capability must have an entry.
1016
+ * Enforced by Zod refinement checking completeness against CanonicalCapabilitySchema values.
1017
+ */
1018
+ export const RosettaCompatibilityProfileSchema = z
1019
+ .record(CanonicalCapabilitySchema, RosettaCompatibilityEntrySchema)
1020
+ .refine(
1021
+ (profile) => {
1022
+ const required = CanonicalCapabilitySchema.options;
1023
+ return required.every((cap) => cap in profile);
1024
+ },
1025
+ {
1026
+ message:
1027
+ "Compatibility profile must include an entry for every canonical capability",
1028
+ },
1029
+ );
1030
+ export type RosettaCompatibilityProfile = z.infer<
1031
+ typeof RosettaCompatibilityProfileSchema
1032
+ >;
1033
+
1034
+ // --- Format Contract ---
1035
+
1036
+ export const FormatContractSchema = z
1037
+ .object({
1038
+ id: FormatIdentifierSchema,
1039
+ contractVersion: ContractVersionSchema,
1040
+ direction: DirectionSchema,
1041
+ harness: HarnessNameSchema.nullable(),
1042
+ aliases: z.array(FormatIdentifierSchema),
1043
+ lifecycle: LifecycleMetadataSchema,
1044
+ canonicalVersions: CanonicalVersionRangeSchema,
1045
+ schemaReference: SchemaReferenceSchema,
1046
+ pathConventions: z.array(PathConventionSchema),
1047
+ detection: DetectionContractSchema,
1048
+ variants: z
1049
+ .record(FormatIdentifierSchema, VariantContractSchema)
1050
+ .default({}),
1051
+ defaultVariant: FormatIdentifierSchema.optional(),
1052
+ optionDefinitions: z
1053
+ .record(z.string(), FormatOptionDefinitionSchema)
1054
+ .default({}),
1055
+ defaults: z.record(z.string(), JsonValueSchema).default({}),
1056
+ normalizationRules: z.array(NormalizationRuleSchema),
1057
+ compatibility: RosettaCompatibilityProfileSchema,
1058
+ security: FormatSecurityPolicySchema,
1059
+ })
1060
+ .strict();
1061
+ export type FormatContract = z.infer<typeof FormatContractSchema>;
1062
+
1063
+ // --- Translation Phase ---
1064
+
1065
+ export const TranslationPhaseSchema = z.enum([
1066
+ "request",
1067
+ "registry",
1068
+ "detection",
1069
+ "source-validation",
1070
+ "source-translation",
1071
+ "canonical-validation",
1072
+ "compatibility",
1073
+ "target-translation",
1074
+ "plan-validation",
1075
+ "redaction",
1076
+ ]);
1077
+ export type TranslationPhase = z.infer<typeof TranslationPhaseSchema>;
1078
+
1079
+ // --- Source and Canonical Diagnostic Locations ---
1080
+
1081
+ export const SourceLocationSchema = z
1082
+ .object({
1083
+ path: NormalizedRelativePathSchema,
1084
+ field: z.string().optional(),
1085
+ line: z.number().int().positive().optional(),
1086
+ column: z.number().int().nonnegative().optional(),
1087
+ offset: z.number().int().nonnegative().optional(),
1088
+ })
1089
+ .strict();
1090
+ export type SourceLocation = z.infer<typeof SourceLocationSchema>;
1091
+
1092
+ export const SourceDiagnosticLocationSchema = SourceLocationSchema;
1093
+ export type SourceDiagnosticLocation = SourceLocation;
1094
+
1095
+ export const CanonicalDiagnosticLocationSchema = z
1096
+ .object({
1097
+ artifactName: z.string().min(1),
1098
+ fieldPath: z.string().min(1),
1099
+ })
1100
+ .strict();
1101
+ export type CanonicalDiagnosticLocation = z.infer<
1102
+ typeof CanonicalDiagnosticLocationSchema
1103
+ >;
1104
+
1105
+ // --- Degradation Detail ---
1106
+
1107
+ export const DegradationDetailSchema = z
1108
+ .object({
1109
+ capability: CanonicalCapabilitySchema,
1110
+ action: DegradationStrategySchema,
1111
+ affectedValueCount: z.number().int().nonnegative(),
1112
+ expectedSemanticChange: z.string().optional(),
1113
+ })
1114
+ .strict();
1115
+ export type DegradationDetail = z.infer<typeof DegradationDetailSchema>;
1116
+
1117
+ // --- Translation Diagnostic ---
1118
+
1119
+ export const TranslationDiagnosticSchema = z
1120
+ .object({
1121
+ code: z.string().regex(/^RS_[A-Z0-9_]+$/),
1122
+ severity: RosettaSeveritySchema,
1123
+ phase: TranslationPhaseSchema,
1124
+ formatId: FormatIdentifierSchema.optional(),
1125
+ message: z.string().min(1),
1126
+ remediation: z.string().min(1),
1127
+ source: SourceDiagnosticLocationSchema.optional(),
1128
+ canonical: CanonicalDiagnosticLocationSchema.optional(),
1129
+ degradation: DegradationDetailSchema.optional(),
1130
+ unavailableDetails: z.array(z.string()).default([]),
1131
+ blocking: z.boolean(),
1132
+ })
1133
+ .strict();
1134
+ export type TranslationDiagnostic = z.infer<typeof TranslationDiagnosticSchema>;
1135
+
1136
+ // --- Translation Plan ---
1137
+
1138
+ export const OutputFileSchema = z
1139
+ .object({
1140
+ relativePath: NormalizedRelativePathSchema,
1141
+ content: z.union([z.string(), z.instanceof(Uint8Array)]),
1142
+ executable: z.boolean().default(false),
1143
+ mediaType: z.string().optional(),
1144
+ })
1145
+ .strict();
1146
+ export type OutputFile = z.infer<typeof OutputFileSchema>;
1147
+
1148
+ export const PlanOperationSchema = z
1149
+ .object({
1150
+ kind: z.literal("write-file"),
1151
+ relativePath: NormalizedRelativePathSchema,
1152
+ outputFileIndex: z.number().int().nonnegative(),
1153
+ })
1154
+ .strict();
1155
+ export type PlanOperation = z.infer<typeof PlanOperationSchema>;
1156
+
1157
+ export const TranslationPlanSchema = z
1158
+ .object({
1159
+ schemaVersion: z.literal("1.0"),
1160
+ formatId: FormatIdentifierSchema,
1161
+ variant: FormatIdentifierSchema.optional(),
1162
+ canonicalSchemaVersion: CanonicalSchemaVersionSchema,
1163
+ outputFiles: z.array(OutputFileSchema),
1164
+ operations: z.array(PlanOperationSchema),
1165
+ applicationState: z.enum(["eligible", "policy-required", "withheld"]),
1166
+ policyDiagnosticCodes: z.array(z.string()),
1167
+ })
1168
+ .strict();
1169
+ export type TranslationPlan = z.infer<typeof TranslationPlanSchema>;
1170
+
1171
+ // --- Format Selection ---
1172
+
1173
+ export const FormatSelectionSchema = z
1174
+ .object({
1175
+ formatId: FormatIdentifierSchema.optional(),
1176
+ variant: FormatIdentifierSchema.optional(),
1177
+ options: z.record(z.string(), JsonValueSchema).default({}),
1178
+ })
1179
+ .strict();
1180
+ export type FormatSelection = z.infer<typeof FormatSelectionSchema>;
1181
+
1182
+ // --- Canonical Output Options ---
1183
+
1184
+ export const CanonicalOutputOptionsSchema = z
1185
+ .object({
1186
+ emitEmptyAuxiliaryFiles: z.boolean().default(false),
1187
+ destinationName: z.string().min(1).optional(),
1188
+ })
1189
+ .strict();
1190
+ export type CanonicalOutputOptions = z.infer<
1191
+ typeof CanonicalOutputOptionsSchema
1192
+ >;
1193
+
1194
+ // --- Translation Requests (Discriminated Union) ---
1195
+
1196
+ export const InboundTranslationRequestSchema = z
1197
+ .object({
1198
+ mode: z.literal("inbound"),
1199
+ sourceDocuments: z.array(SourceDocumentSchema),
1200
+ source: FormatSelectionSchema,
1201
+ canonical: CanonicalOutputOptionsSchema,
1202
+ canonicalSchemaVersion: CanonicalSchemaVersionSchema,
1203
+ strict: z.boolean(),
1204
+ callerContext: z.record(z.string(), JsonValueSchema),
1205
+ })
1206
+ .strict();
1207
+ export type InboundTranslationRequest = z.infer<
1208
+ typeof InboundTranslationRequestSchema
1209
+ >;
1210
+
1211
+ export const OutboundTranslationRequestSchema = z
1212
+ .object({
1213
+ mode: z.literal("outbound"),
1214
+ artifact: KnowledgeArtifactSchema,
1215
+ target: FormatSelectionSchema.extend({
1216
+ formatId: FormatIdentifierSchema,
1217
+ }).strict(),
1218
+ canonicalSchemaVersion: CanonicalSchemaVersionSchema,
1219
+ strict: z.boolean(),
1220
+ callerContext: z.record(z.string(), JsonValueSchema),
1221
+ })
1222
+ .strict();
1223
+ export type OutboundTranslationRequest = z.infer<
1224
+ typeof OutboundTranslationRequestSchema
1225
+ >;
1226
+
1227
+ export const TranscodeTranslationRequestSchema = z
1228
+ .object({
1229
+ mode: z.literal("transcode"),
1230
+ sourceDocuments: z.array(SourceDocumentSchema),
1231
+ source: FormatSelectionSchema,
1232
+ target: FormatSelectionSchema.extend({
1233
+ formatId: FormatIdentifierSchema,
1234
+ }).strict(),
1235
+ canonicalSchemaVersion: CanonicalSchemaVersionSchema,
1236
+ strict: z.boolean(),
1237
+ callerContext: z.record(z.string(), JsonValueSchema),
1238
+ })
1239
+ .strict();
1240
+ export type TranscodeTranslationRequest = z.infer<
1241
+ typeof TranscodeTranslationRequestSchema
1242
+ >;
1243
+
1244
+ export const TranslationRequestSchema = z.discriminatedUnion("mode", [
1245
+ InboundTranslationRequestSchema,
1246
+ OutboundTranslationRequestSchema,
1247
+ TranscodeTranslationRequestSchema,
1248
+ ]);
1249
+ export type TranslationRequest = z.infer<typeof TranslationRequestSchema>;
1250
+
1251
+ // --- Resolved Format Summary ---
1252
+
1253
+ export const ResolvedFormatSummarySchema = z
1254
+ .object({
1255
+ formatId: FormatIdentifierSchema,
1256
+ variant: FormatIdentifierSchema.optional(),
1257
+ contractVersion: ContractVersionSchema,
1258
+ lifecycle: LifecycleStatusSchema,
1259
+ })
1260
+ .strict();
1261
+ export type ResolvedFormatSummary = z.infer<typeof ResolvedFormatSummarySchema>;
1262
+
1263
+ // --- Applied Default ---
1264
+
1265
+ export const AppliedDefaultSchema = z
1266
+ .object({
1267
+ field: z.string().min(1),
1268
+ value: JsonValueSchema,
1269
+ rule: z.string().min(1),
1270
+ })
1271
+ .strict();
1272
+ export type AppliedDefault = z.infer<typeof AppliedDefaultSchema>;
1273
+
1274
+ // --- Applied Normalization ---
1275
+
1276
+ export const AppliedNormalizationSchema = z
1277
+ .object({
1278
+ ruleId: z.string().min(1),
1279
+ field: z.string().min(1),
1280
+ description: z.string().min(1),
1281
+ })
1282
+ .strict();
1283
+ export type AppliedNormalization = z.infer<typeof AppliedNormalizationSchema>;
1284
+
1285
+ // --- Degradation Record ---
1286
+
1287
+ export const DegradationRecordSchema = z
1288
+ .object({
1289
+ capability: CanonicalCapabilitySchema,
1290
+ canonicalPaths: z.array(z.string()),
1291
+ action: DegradationStrategySchema,
1292
+ affectedValueCount: z.number().int().nonnegative(),
1293
+ expectedSemanticChange: z.string().optional(),
1294
+ })
1295
+ .strict();
1296
+ export type DegradationRecord = z.infer<typeof DegradationRecordSchema>;
1297
+
1298
+ // --- Translation Result ---
1299
+
1300
+ export const TranslationResultSchema = z
1301
+ .object({
1302
+ schemaVersion: z.literal("1.0"),
1303
+ status: z.enum(["success", "partial", "failure"]),
1304
+ registryVersion: z.string().min(1),
1305
+ sourceFormat: ResolvedFormatSummarySchema.optional(),
1306
+ targetFormat: ResolvedFormatSummarySchema.optional(),
1307
+ canonical: KnowledgeArtifactSchema.optional(),
1308
+ plan: TranslationPlanSchema.optional(),
1309
+ diagnostics: z.array(TranslationDiagnosticSchema),
1310
+ defaults: z.array(AppliedDefaultSchema),
1311
+ normalizations: z.array(AppliedNormalizationSchema),
1312
+ degradations: z.array(DegradationRecordSchema),
1313
+ })
1314
+ .strict();
1315
+ export type TranslationResult = z.infer<typeof TranslationResultSchema>;
1316
+
1317
+ // --- Detection Models ---
1318
+
1319
+ export const DetectionEvidenceSchema = z
1320
+ .object({
1321
+ ruleId: z.string().min(1),
1322
+ kind: DetectionRuleKindSchema,
1323
+ outcome: z.enum([
1324
+ "matched",
1325
+ "missing-required",
1326
+ "conflicting",
1327
+ "not-matched",
1328
+ ]),
1329
+ paths: z.array(NormalizedRelativePathSchema),
1330
+ marker: z.string().optional(),
1331
+ metadataLocation: SourceLocationSchema.optional(),
1332
+ })
1333
+ .strict();
1334
+ export type DetectionEvidence = z.infer<typeof DetectionEvidenceSchema>;
1335
+
1336
+ export const DetectionCandidateSchema = z
1337
+ .object({
1338
+ formatId: FormatIdentifierSchema,
1339
+ confidence: z.number().min(0).max(1),
1340
+ threshold: z.number().min(0).max(1),
1341
+ qualifies: z.boolean(),
1342
+ evidence: z.array(DetectionEvidenceSchema),
1343
+ })
1344
+ .strict();
1345
+ export type DetectionCandidate = z.infer<typeof DetectionCandidateSchema>;
1346
+
1347
+ // --- Registry Failure ---
1348
+
1349
+ export const RegistryFailureSchema = z
1350
+ .object({
1351
+ code: z.literal("RS_REGISTRY_FAILURE"),
1352
+ message: z.string().min(1),
1353
+ })
1354
+ .strict();
1355
+ export type RegistryFailure = z.infer<typeof RegistryFailureSchema>;
1356
+
1357
+ // --- Profiles ---
1358
+
1359
+ export const AcquisitionProfileSchema = z.object({
1360
+ repo: z.string().min(1),
1361
+ branch: z.string().min(1).default("main"),
1362
+ remote: z.string().min(1).default("origin"),
1363
+ checkoutPrefix: z.string().optional(),
1364
+ credentialReference: z.string().optional(),
1365
+ });
1366
+ export type AcquisitionProfile = z.infer<typeof AcquisitionProfileSchema>;
1367
+
1368
+ export const TranslationProfileSchema = z.object({
1369
+ sourceFormat: FormatIdentifierSchema.optional(),
1370
+ sourceSubpath: z.string().optional(),
1371
+ targetFormat: FormatIdentifierSchema.optional(),
1372
+ targetVariant: FormatIdentifierSchema.optional(),
1373
+ canonicalDestination: z.string().optional(),
1374
+ collections: z.array(z.string()).default([]),
1375
+ strict: z.boolean().default(false),
1376
+ canonicalSchemaVersion: CanonicalSchemaVersionSchema.optional(),
1377
+ options: z.record(z.string(), JsonValueSchema).default({}),
1378
+ });
1379
+ export type TranslationProfile = z.infer<typeof TranslationProfileSchema>;
1380
+
1381
+ // --- Machine-Output Envelopes ---
1382
+
1383
+ export const InspectionReportEnvelopeSchema = z
1384
+ .object({
1385
+ machineSchemaVersion: z.literal("1.0"),
1386
+ generatedAt: z.string().datetime(),
1387
+ registryVersion: z.string().min(1),
1388
+ request: TranslationRequestSchema,
1389
+ sourceFormat: ResolvedFormatSummarySchema.optional(),
1390
+ targetFormat: ResolvedFormatSummarySchema.optional(),
1391
+ detection: z
1392
+ .object({
1393
+ candidates: z.array(DetectionCandidateSchema),
1394
+ selected: FormatIdentifierSchema.optional(),
1395
+ })
1396
+ .strict()
1397
+ .optional(),
1398
+ canonical: z
1399
+ .object({
1400
+ artifactName: z.string().optional(),
1401
+ fieldCount: z.number().int().nonnegative(),
1402
+ })
1403
+ .strict()
1404
+ .optional(),
1405
+ compatibility: z
1406
+ .object({
1407
+ counts: z.record(
1408
+ CanonicalCapabilitySchema,
1409
+ z
1410
+ .object({
1411
+ support: SupportLevelSchema,
1412
+ affectedValues: z.number().int().nonnegative(),
1413
+ })
1414
+ .strict(),
1415
+ ),
1416
+ })
1417
+ .strict()
1418
+ .optional(),
1419
+ plan: z
1420
+ .object({
1421
+ fileCount: z.number().int().nonnegative(),
1422
+ paths: z.array(z.string()),
1423
+ })
1424
+ .strict()
1425
+ .optional(),
1426
+ defaults: z.array(AppliedDefaultSchema),
1427
+ normalizations: z.array(AppliedNormalizationSchema),
1428
+ diagnostics: z.array(TranslationDiagnosticSchema),
1429
+ degradations: z.array(DegradationRecordSchema),
1430
+ })
1431
+ .strict();
1432
+ export type InspectionReportEnvelope = z.infer<
1433
+ typeof InspectionReportEnvelopeSchema
1434
+ >;
1435
+
1436
+ export const DiagnosticsEnvelopeSchema = z
1437
+ .object({
1438
+ machineSchemaVersion: z.literal("1.0"),
1439
+ generatedAt: z.string().datetime(),
1440
+ registryVersion: z.string().min(1),
1441
+ diagnostics: z.array(TranslationDiagnosticSchema),
1442
+ status: z.enum(["success", "partial", "failure"]),
1443
+ })
1444
+ .strict();
1445
+ export type DiagnosticsEnvelope = z.infer<typeof DiagnosticsEnvelopeSchema>;
1446
+
1447
+ // --- Provenance Record ---
1448
+
1449
+ export const ProvenanceRecordSchema = z
1450
+ .object({
1451
+ upstream: z.string().min(1),
1452
+ sourcePath: z.string().min(1),
1453
+ sourceFormat: FormatIdentifierSchema,
1454
+ sourceRevision: z.string().min(1),
1455
+ contract: z.string().min(1),
1456
+ baseDigest: z.string().min(1),
1457
+ importedAt: z.string().datetime(),
1458
+ })
1459
+ .strict();
1460
+ export type ProvenanceRecord = z.infer<typeof ProvenanceRecordSchema>;
1461
+
1462
+ // --- Attribution Record ---
1463
+
1464
+ /**
1465
+ * The copyright-relevant relationship between this artifact and an upstream
1466
+ * work. Captured (not inferred) at import time by the Attribution_Wizard.
1467
+ *
1468
+ * - `verbatim`: vendored unchanged; the body is upstream's.
1469
+ * - `adapted`: materially edited from upstream.
1470
+ * - `inspired-by`: original expression here, only the idea is upstream's.
1471
+ * - `packaged`: repackaged/reformatted, authorship unchanged.
1472
+ */
1473
+ export const RelationshipSchema = z.enum([
1474
+ "verbatim",
1475
+ "adapted",
1476
+ "inspired-by",
1477
+ "packaged",
1478
+ ]);
1479
+ export type Relationship = z.infer<typeof RelationshipSchema>;
1480
+
1481
+ /**
1482
+ * One upstream work this artifact derives from. `source-repo`/`source-commit`
1483
+ * may overlap with the machine-owned ProvenanceRecord intentionally; that
1484
+ * overlap is not deduplicated. `license` reuses the SPDX conventions of the
1485
+ * frontmatter `license` field.
1486
+ */
1487
+ export const UpstreamWorkSchema = z.object({
1488
+ work: z.string().min(1),
1489
+ authors: z.array(z.string().min(1)).min(1),
1490
+ url: z.string().url().optional(),
1491
+ license: z.string().optional(),
1492
+ "source-repo": z.string().min(1).optional(),
1493
+ "source-commit": z.string().min(1).optional(),
1494
+ relationship: RelationshipSchema.default("verbatim"),
1495
+ });
1496
+ export type UpstreamWork = z.infer<typeof UpstreamWorkSchema>;
1497
+
1498
+ /**
1499
+ * Curation-owned, human/legal attribution for an artifact (see ADR-0064). The
1500
+ * counterpart to the machine-owned ProvenanceRecord: `provenance` answers
1501
+ * "where do I re-sync from" and is overwritten on every import; `attribution`
1502
+ * answers "who do I credit and under what license" and is preserved across
1503
+ * every re-sync (classified `curation-owned` in the Field_Ownership_Policy).
1504
+ */
1505
+ export const AttributionRecordSchema = z.object({
1506
+ upstream: z.array(UpstreamWorkSchema).min(1),
1507
+ "curated-by": z.string().min(1).optional(),
1508
+ notice: z.string().optional(),
1509
+ });
1510
+ export type AttributionRecord = z.infer<typeof AttributionRecordSchema>;
1511
+
1512
+ // --- Reconciliation: field ownership and three-way merge ---
1513
+
1514
+ /**
1515
+ * The four ownership classes that determine which merge rule applies to a
1516
+ * reconcilable field during Three_Way_Reconciliation (Requirement 18).
1517
+ *
1518
+ * - `curation-owned`: always keep Ours; never overwritten from upstream.
1519
+ * - `upstream-owned`: fast-forward to Theirs when Base == Ours; conflict when
1520
+ * both sides diverged.
1521
+ * - `merge-by-union`: deterministic union of Ours and Theirs additions minus
1522
+ * members removed between Base and Theirs.
1523
+ * - `machine-owned`: recomputed from the merged result (never merged directly).
1524
+ */
1525
+ export const FieldOwnershipClassSchema = z.enum([
1526
+ "curation-owned",
1527
+ "upstream-owned",
1528
+ "merge-by-union",
1529
+ "machine-owned",
1530
+ ]);
1531
+ export type FieldOwnershipClass = z.infer<typeof FieldOwnershipClassSchema>;
1532
+
1533
+ /**
1534
+ * The closed set of canonical fields and capabilities that participate in
1535
+ * reconciliation. A complete Field_Ownership_Policy assigns exactly one
1536
+ * FieldOwnershipClass to every member of this set (Requirement 18.14). The
1537
+ * Configuration_Validator rejects any policy that references a field outside
1538
+ * this set or omits a classification for one of its members.
1539
+ */
1540
+ export const ReconcilableFieldSchema = z.enum([
1541
+ // Curation-owned frontmatter fields
1542
+ "categories",
1543
+ "trust",
1544
+ "collections",
1545
+ "audience",
1546
+ "priority",
1547
+ "visibility",
1548
+ "hooks",
1549
+ "attribution",
1550
+ // Upstream-owned capabilities
1551
+ "body",
1552
+ "workflows",
1553
+ "mcpServers",
1554
+ // Merge-by-union frontmatter fields
1555
+ "keywords",
1556
+ "enhances",
1557
+ "depends",
1558
+ // Machine-owned fields
1559
+ "provenance",
1560
+ "version",
1561
+ ]);
1562
+ export type ReconcilableField = z.infer<typeof ReconcilableFieldSchema>;
1563
+
1564
+ /**
1565
+ * A Field_Ownership_Policy maps each reconcilable canonical field to an
1566
+ * ownership class. It is overridable per upstream in configuration; a complete
1567
+ * policy classifies every member of ReconcilableFieldSchema. This base schema
1568
+ * accepts a partial record so that per-upstream overrides can specify only the
1569
+ * fields they change; the Configuration_Validator enforces completeness against
1570
+ * DEFAULT_FIELD_OWNERSHIP_POLICY before use (Requirement 18.14).
1571
+ */
1572
+ export const FieldOwnershipPolicySchema = z
1573
+ .record(ReconcilableFieldSchema, FieldOwnershipClassSchema)
1574
+ .refine(
1575
+ (policy) =>
1576
+ Object.keys(policy).every((field) =>
1577
+ (ReconcilableFieldSchema.options as readonly string[]).includes(field),
1578
+ ),
1579
+ {
1580
+ message:
1581
+ "Field_Ownership_Policy references a field outside ReconcilableFieldSchema",
1582
+ },
1583
+ );
1584
+ export type FieldOwnershipPolicy = z.infer<typeof FieldOwnershipPolicySchema>;
1585
+
1586
+ /**
1587
+ * The documented default Field_Ownership_Policy. Every reconcilable field is
1588
+ * classified so the default is complete (Requirement 18.14). Per ADR-0049 and
1589
+ * the Rosetta Stone design:
1590
+ *
1591
+ * - Curation-owned fields (`categories`, `trust`, `collections`, `audience`,
1592
+ * `priority`, `visibility`, `hooks`, `attribution`) always keep the curated
1593
+ * (Ours) value. `hooks` is curation-owned because maintainers routinely tune
1594
+ * hooks locally; `attribution` is curation-owned so an upstream re-sync never
1595
+ * clobbers hand-confirmed credit (ADR-0064).
1596
+ * - Upstream-owned fields (`body`, `workflows`, `mcpServers`) fast-forward to
1597
+ * the upstream (Theirs) value only when the maintainer never edited them.
1598
+ * - Merge-by-union fields (`keywords`, `enhances`, `depends`) take the
1599
+ * deterministic union of both sides minus upstream removals.
1600
+ * - Machine-owned fields (`provenance`, `version`) are recomputed from the
1601
+ * merged result and are never merged directly.
1602
+ */
1603
+ export const DEFAULT_FIELD_OWNERSHIP_POLICY: Readonly<
1604
+ Record<ReconcilableField, FieldOwnershipClass>
1605
+ > = Object.freeze({
1606
+ categories: "curation-owned",
1607
+ trust: "curation-owned",
1608
+ collections: "curation-owned",
1609
+ audience: "curation-owned",
1610
+ priority: "curation-owned",
1611
+ visibility: "curation-owned",
1612
+ hooks: "curation-owned",
1613
+ attribution: "curation-owned",
1614
+ body: "upstream-owned",
1615
+ workflows: "upstream-owned",
1616
+ mcpServers: "upstream-owned",
1617
+ keywords: "merge-by-union",
1618
+ enhances: "merge-by-union",
1619
+ depends: "merge-by-union",
1620
+ provenance: "machine-owned",
1621
+ version: "machine-owned",
1622
+ });
1623
+
1624
+ /**
1625
+ * The per-field and per-artifact classification produced by a
1626
+ * Three_Way_Reconciliation (Requirement 18).
1627
+ */
1628
+ export const ReconciliationOutcomeSchema = z.enum([
1629
+ "clean",
1630
+ "fast-forward",
1631
+ "merged",
1632
+ "conflict",
1633
+ "orphaned",
1634
+ "new",
1635
+ ]);
1636
+ export type ReconciliationOutcome = z.infer<typeof ReconciliationOutcomeSchema>;
1637
+
1638
+ /**
1639
+ * A Reconciliation_Request. `base` is optional to express the reduced-confidence
1640
+ * two-way path used when the Base_Artifact cannot be reconstructed or its
1641
+ * provenance digest fails self-verification (Requirements 18.11, 18.16).
1642
+ */
1643
+ export const ReconciliationRequestSchema = z
1644
+ .object({
1645
+ base: KnowledgeArtifactSchema.optional(),
1646
+ ours: KnowledgeArtifactSchema,
1647
+ theirs: KnowledgeArtifactSchema,
1648
+ policy: FieldOwnershipPolicySchema,
1649
+ })
1650
+ .strict();
1651
+ export type ReconciliationRequest = z.infer<typeof ReconciliationRequestSchema>;
1652
+
1653
+ /**
1654
+ * A Reconciliation_Diagnostic extends the shared TranslationDiagnostic shape
1655
+ * with reconciliation-specific fields identifying the affected field, its
1656
+ * ownership class, the per-field outcome, whether a Base value was available,
1657
+ * and the confidence of the merge (reduced when Base is absent).
1658
+ */
1659
+ export const ReconciliationDiagnosticSchema =
1660
+ TranslationDiagnosticSchema.extend({
1661
+ field: ReconcilableFieldSchema,
1662
+ fieldClass: FieldOwnershipClassSchema,
1663
+ outcome: ReconciliationOutcomeSchema,
1664
+ baseValuePresent: z.boolean(),
1665
+ confidence: z.enum(["full", "reduced"]),
1666
+ }).strict();
1667
+ export type ReconciliationDiagnostic = z.infer<
1668
+ typeof ReconciliationDiagnosticSchema
1669
+ >;
1670
+
1671
+ /**
1672
+ * The result of reconciling a single artifact: the merged KnowledgeArtifact,
1673
+ * its overall outcome, and the ordered reconciliation diagnostics.
1674
+ */
1675
+ export const ReconciliationResultSchema = z
1676
+ .object({
1677
+ artifact: KnowledgeArtifactSchema,
1678
+ outcome: ReconciliationOutcomeSchema,
1679
+ diagnostics: z.array(ReconciliationDiagnosticSchema).default([]),
1680
+ })
1681
+ .strict();
1682
+ export type ReconciliationResult = z.infer<typeof ReconciliationResultSchema>;
1683
+
1684
+ /**
1685
+ * A single entry in a Reconciliation_Report, pairing an artifact's identity
1686
+ * (upstream and name, used for stable ordering) with its reconciliation result.
1687
+ */
1688
+ export const ReconciliationReportEntrySchema = z
1689
+ .object({
1690
+ upstream: z.string().min(1),
1691
+ artifactName: z.string().min(1),
1692
+ result: ReconciliationResultSchema,
1693
+ })
1694
+ .strict();
1695
+ export type ReconciliationReportEntry = z.infer<
1696
+ typeof ReconciliationReportEntrySchema
1697
+ >;
1698
+
1699
+ /**
1700
+ * A deterministic Reconciliation_Report aggregating results across every
1701
+ * Provenance_Record-bearing artifact for one or more upstreams. Entries are
1702
+ * ordered by outcome, then upstream identifier, then artifact name
1703
+ * (Requirement 18.15). Carries its own machineSchemaVersion, independent of
1704
+ * InspectionReportEnvelopeSchema and DiagnosticsEnvelopeSchema.
1705
+ */
1706
+ export const ReconciliationReportSchema = z
1707
+ .object({
1708
+ machineSchemaVersion: z.literal("1.0"),
1709
+ entries: z.array(ReconciliationReportEntrySchema).default([]),
1710
+ })
1711
+ .strict();
1712
+ export type ReconciliationReport = z.infer<typeof ReconciliationReportSchema>;