@fabricorg/gen-conformance 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,64 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Release additive public compiler and generator APIs as minor versions. This includes parameterized
8
+ view schema contracts, the exported usage-contract JSON schema, and the runtime Platform validation
9
+ used by capability generation.
10
+
11
+ ### Patch Changes
12
+
13
+ - Updated dependencies
14
+ - @fabricorg/compiler@2.2.0
15
+
16
+ ## 0.2.1
17
+
18
+ ### Patch Changes
19
+
20
+ - b932767: Add portable parameter schemas and validation for projection views. Projection snapshot keys now
21
+ include a canonical parameter identity, generated capability and experience contracts preserve view
22
+ parameter schemas, and compatible snapshots continue through the explicit `upgradeSnapshot` seam.
23
+ - Updated dependencies [b932767]
24
+ - @fabricorg/compiler@2.1.1
25
+
26
+ ### Additional release notes
27
+
28
+ ### Patch Changes
29
+
30
+ - Preserve projection view parameter schemas in generated conformance plans.
31
+
32
+ ## 0.2.0
33
+
34
+ ### Minor Changes
35
+
36
+ - c504d0a: Make generated artifacts carry their own weight instead of handing back a seam.
37
+
38
+ `gen-graphql` projects each view's JSON Schema into named GraphQL types rather than an opaque
39
+ `JSON` scalar, declares the Federation 2 `@link` directive, and emits `createResolvers()` — an
40
+ executable resolver map whose Query fields read through `ProjectionHost` and whose Mutation fields
41
+ submit through `submitAction()`. Shapes with no GraphQL projection (`oneOf`, `anyOf`, `allOf`, tuple
42
+ `items`, multi-type unions, non-local `$ref`) now fail the generator instead of silently degrading
43
+ to `JSON`; only a schema that genuinely admits any value projects as `JSON`. Recursive `#/$defs`
44
+ references resolve to a single named type.
45
+
46
+ `gen-conformance` emits a runnable suite alongside the plan. The ten Phase 1 checks split into eight
47
+ `MODULE_CONFORMANCE_CHECKS` a module verifies against a governed host and two
48
+ `PLATFORM_CONFORMANCE_CHECKS` a repository owns. A check a module cannot exercise reports
49
+ `not-applicable` with a reason rather than passing silently, and `@fabricorg/gen-conformance/memory`
50
+ ships a reference harness so a suite runs with no infrastructure.
51
+
52
+ `gen-capability` emits a usage contract with its own `formatVersion`, validated by
53
+ `assertUsageContract` and described by `USAGE_CONTRACT_JSON_SCHEMA`.
54
+
55
+ ### Patch Changes
56
+
57
+ - Updated dependencies [c504d0a]
58
+ - Updated dependencies [c504d0a]
59
+ - @fabricorg/platform-host@5.0.0
60
+ - @fabricorg/compiler@2.1.0
61
+
3
62
  ## 0.1.1
4
63
 
5
64
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -9,9 +9,9 @@ var __export = (target, all) => {
9
9
  };
10
10
  var __copyProps = (to, from, except, desc) => {
11
11
  if (from && typeof from === "object" || typeof from === "function") {
12
- for (let key of __getOwnPropNames(from))
13
- if (!__hasOwnProp.call(to, key) && key !== except)
14
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
12
+ for (let key2 of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key2) && key2 !== except)
14
+ __defProp(to, key2, { get: () => from[key2], enumerable: !(desc = __getOwnPropDesc(from, key2)) || desc.enumerable });
15
15
  }
16
16
  return to;
17
17
  };
@@ -20,13 +20,17 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ MODULE_CONFORMANCE_CHECKS: () => MODULE_CONFORMANCE_CHECKS,
23
24
  PHASE_1_CONFORMANCE_CHECKS: () => PHASE_1_CONFORMANCE_CHECKS,
25
+ PLATFORM_CONFORMANCE_CHECKS: () => PLATFORM_CONFORMANCE_CHECKS,
26
+ buildModuleConformancePlan: () => buildModuleConformancePlan,
24
27
  conformanceGenerator: () => conformanceGenerator,
25
- createCertificationResult: () => createCertificationResult
28
+ createCertificationResult: () => createCertificationResult,
29
+ moduleConformanceChecks: () => moduleConformanceChecks
26
30
  });
27
31
  module.exports = __toCommonJS(index_exports);
28
32
  var import_compiler = require("@fabricorg/compiler");
29
- var PHASE_1_CONFORMANCE_CHECKS = [
33
+ var MODULE_CONFORMANCE_CHECKS = [
30
34
  "fabric.idempotency.same-command-replay.v1",
31
35
  "fabric.idempotency.conflicting-payload.v1",
32
36
  "fabric.idempotency.concurrent-submission.v1",
@@ -34,10 +38,216 @@ var PHASE_1_CONFORMANCE_CHECKS = [
34
38
  "fabric.authorization.offline-replay.v1",
35
39
  "fabric.events.compatibility.v1",
36
40
  "fabric.provenance.propagation.v1",
37
- "fabric.consumers.tolerant-envelope.v1",
41
+ "fabric.consumers.tolerant-envelope.v1"
42
+ ];
43
+ var PLATFORM_CONFORMANCE_CHECKS = [
38
44
  "fabric.documentation.parity.v1",
39
45
  "fabric.documentation.llms-contract.v1"
40
46
  ];
47
+ var PHASE_1_CONFORMANCE_CHECKS = [...MODULE_CONFORMANCE_CHECKS, ...PLATFORM_CONFORMANCE_CHECKS];
48
+ var ConformanceFailure = class extends Error {
49
+ name = "ConformanceFailure";
50
+ };
51
+ function expect(condition, message) {
52
+ if (!condition) throw new ConformanceFailure(message);
53
+ }
54
+ var idempotentActions = (plan) => plan.actions.filter((action) => action.idempotency !== "prohibited" && action.idempotent);
55
+ var key = (label, action) => `conformance:${label}:${action.actionId}`;
56
+ var conflictReason = (conflict) => conflict.code ?? conflict.message;
57
+ async function conflictOf(run) {
58
+ try {
59
+ await run();
60
+ return { thrown: false, message: "" };
61
+ } catch (error) {
62
+ const code = error.code;
63
+ return { thrown: true, ...code ? { code } : {}, message: error instanceof Error ? error.message : String(error) };
64
+ }
65
+ }
66
+ async function forEachAction(actions, reason, body) {
67
+ if (actions.length === 0) return { status: "not-applicable", reason };
68
+ const evidence = [];
69
+ for (const action of actions) evidence.push(...await body(action));
70
+ return { status: "passed", evidence };
71
+ }
72
+ function moduleConformanceChecks() {
73
+ return [
74
+ {
75
+ id: "fabric.idempotency.same-command-replay.v1",
76
+ title: "replaying one command key with the same payload does not re-execute",
77
+ run: (harness, plan) => forEachAction(idempotentActions(plan), "module declares no idempotent action", async (action) => {
78
+ const input = { actionId: action.actionId, parameters: harness.parameters(action.actionId), idempotencyKey: key("replay", action) };
79
+ const first = await harness.submit(input);
80
+ const before = await harness.sideEffects?.(action.actionId);
81
+ const second = await harness.submit(input);
82
+ expect(first.actionInvocationId === second.actionInvocationId, `replay of ${action.actionId} produced a second invocation ${second.actionInvocationId} for key ${input.idempotencyKey}`);
83
+ const after = await harness.sideEffects?.(action.actionId);
84
+ if (before !== void 0 && after !== void 0) {
85
+ expect(after === before, `replay of ${action.actionId} returned the original invocation but produced ${after - before} further effects; the handler ran again`);
86
+ }
87
+ return [`invocation:${first.actionInvocationId}`, `key:${input.idempotencyKey}`, `effects:${after ?? "unobserved"}`];
88
+ })
89
+ },
90
+ {
91
+ id: "fabric.idempotency.conflicting-payload.v1",
92
+ title: "reusing a command key with an altered payload is refused",
93
+ run: (harness, plan) => forEachAction(idempotentActions(plan), "module declares no idempotent action", async (action) => {
94
+ const idempotencyKey = key("conflict", action);
95
+ const parameters = harness.parameters(action.actionId);
96
+ await harness.submit({ actionId: action.actionId, parameters, idempotencyKey });
97
+ const conflict = await conflictOf(() => harness.submit({
98
+ actionId: action.actionId,
99
+ parameters: { ...parameters, "x-conformance-altered": true },
100
+ idempotencyKey
101
+ }));
102
+ expect(conflict.thrown, `altered payload reusing key ${idempotencyKey} was accepted instead of refused`);
103
+ expect(
104
+ conflict.code === "IDEMPOTENCY_CONFLICT" || /idempotenc/i.test(conflict.message),
105
+ `altered payload for ${action.actionId} was refused, but not as an idempotency conflict: ${conflict.message}`
106
+ );
107
+ return [`key:${idempotencyKey}`, `refusal:${conflictReason(conflict)}`];
108
+ })
109
+ },
110
+ {
111
+ id: "fabric.idempotency.concurrent-submission.v1",
112
+ title: "concurrent identical submissions collapse to one invocation",
113
+ run: (harness, plan) => forEachAction(idempotentActions(plan), "module declares no idempotent action", async (action) => {
114
+ const input = { actionId: action.actionId, parameters: harness.parameters(action.actionId), idempotencyKey: key("concurrent", action) };
115
+ const before = await harness.sideEffects?.(action.actionId);
116
+ const results = await Promise.all([harness.submit(input), harness.submit(input), harness.submit(input)]);
117
+ const ids = new Set(results.map((result) => result.actionInvocationId));
118
+ expect(ids.size === 1, `concurrent submissions of ${action.actionId} produced ${ids.size} invocations: ${[...ids].join(", ")}`);
119
+ const after = await harness.sideEffects?.(action.actionId);
120
+ if (before !== void 0 && after !== void 0) {
121
+ const executions = after - before;
122
+ expect(executions <= 1, `${results.length} concurrent submissions of ${action.actionId} collapsed to one invocation but produced ${executions} executions' worth of effects`);
123
+ }
124
+ return [`invocation:${[...ids][0]}`, `attempts:${results.length}`, `effects:${after ?? "unobserved"}`];
125
+ })
126
+ },
127
+ {
128
+ id: "fabric.authorization.governing-moment.v1",
129
+ title: "an authorization binding must match the action's declared governing moment",
130
+ run: (harness, plan) => forEachAction(
131
+ plan.actions.filter((action) => action.authorityMoment !== void 0),
132
+ "module declares no action with an authority moment",
133
+ async (action) => {
134
+ const mismatched = action.authorityMoment === "capture" ? "execution" : "capture";
135
+ const rejection = await conflictOf(() => harness.submit({
136
+ actionId: action.actionId,
137
+ parameters: harness.parameters(action.actionId),
138
+ authorizationBinding: { governingMoment: mismatched, capturedAt: new Date(Date.now() - 6e4).toISOString() }
139
+ }));
140
+ expect(rejection.thrown, `a binding declaring governingMoment "${mismatched}" was accepted for ${action.actionId}, governed at "${action.authorityMoment}"`);
141
+ expect(
142
+ /governingmoment|governing moment/i.test(conflictReason(rejection)),
143
+ `the binding for ${action.actionId} was refused, but not for its governing moment: ${conflictReason(rejection)}`
144
+ );
145
+ return [`action:${action.actionId}`, `declared:${action.authorityMoment}`, `refused:${mismatched}`];
146
+ }
147
+ )
148
+ },
149
+ {
150
+ id: "fabric.authorization.offline-replay.v1",
151
+ title: "an offline capture replayed after authority is withdrawn is refused into reconciliation",
152
+ run: (harness, plan) => forEachAction(
153
+ plan.actions.filter((action) => action.connectivity === "offline-capturable" && action.authorityMoment !== void 0 && action.authorityMoment !== "capture"),
154
+ "module declares no offline-capturable action governed at execution",
155
+ async (action) => {
156
+ await harness.revokeAuthority(action.actionId);
157
+ const replay = await harness.submit({
158
+ actionId: action.actionId,
159
+ parameters: harness.parameters(action.actionId),
160
+ idempotencyKey: key("offline-replay", action),
161
+ executionReason: "offline_replay"
162
+ });
163
+ expect(
164
+ replay.status === "reconciliation_required",
165
+ `replay of ${action.actionId} after authority withdrawal returned status "${replay.status}" instead of reconciliation_required`
166
+ );
167
+ expect(replay.reconciliation !== void 0, `reconciliation_required was returned for ${action.actionId} without a reconciliation outcome`);
168
+ return [`action:${action.actionId}`, `reconciliation:${replay.reconciliation?.kind}`];
169
+ }
170
+ )
171
+ },
172
+ {
173
+ id: "fabric.events.compatibility.v1",
174
+ title: "every consumed event version is one the module still declares",
175
+ async run(_harness, plan) {
176
+ if (plan.views.length === 0) return { status: "not-applicable", reason: "module declares no views" };
177
+ const declared = new Map(plan.eventTypes.map((event) => [event.eventType, event.schemaVersion]));
178
+ const evidence = [];
179
+ for (const view of plan.views) {
180
+ for (const consumption of view.consumes) {
181
+ const current = declared.get(consumption.eventType);
182
+ if (current === void 0) continue;
183
+ expect(
184
+ consumption.schemaVersions.includes(current),
185
+ `view ${view.name}@${view.version} consumes ${consumption.eventType} at [${consumption.schemaVersions.join(", ")}] but the module now emits version ${current}`
186
+ );
187
+ evidence.push(`${view.name}@${view.version}:${consumption.eventType}=${current}`);
188
+ }
189
+ }
190
+ if (evidence.length === 0) return { status: "not-applicable", reason: "no view consumes an event this module declares" };
191
+ return { status: "passed", evidence };
192
+ }
193
+ },
194
+ {
195
+ id: "fabric.provenance.propagation.v1",
196
+ title: "submission provenance reaches the events the action emits",
197
+ run: (harness, plan) => forEachAction(
198
+ plan.actions.filter((action) => action.mutatesDomain),
199
+ "module declares no domain-mutating action",
200
+ async (action) => {
201
+ const correlationId = `conformance-corr-${action.actionId}`;
202
+ const submitted = await harness.submit({
203
+ actionId: action.actionId,
204
+ parameters: harness.parameters(action.actionId),
205
+ correlationId,
206
+ // Audit attributes are allowlisted per application, so provenance identity is asserted on correlation alone.
207
+ provenance: { source: "system", correlationId }
208
+ });
209
+ const emitted = (await harness.events()).filter((event) => event.actionInvocationId === submitted.actionInvocationId);
210
+ expect(emitted.length > 0, `action ${action.actionId} mutates domain but emitted no events`);
211
+ for (const event of emitted) {
212
+ expect(event.correlationId === correlationId, `event ${event.eventType} carried correlationId ${String(event.correlationId)} instead of ${correlationId}`);
213
+ }
214
+ return [`invocation:${submitted.actionInvocationId}`, `events:${emitted.length}`, `correlationId:${correlationId}`];
215
+ }
216
+ )
217
+ },
218
+ {
219
+ id: "fabric.consumers.tolerant-envelope.v1",
220
+ title: "emitted envelopes are complete, and a consumer tolerates fields it does not know",
221
+ run: (harness, plan) => forEachAction(
222
+ plan.actions.filter((action) => action.mutatesDomain),
223
+ "module declares no domain-mutating action",
224
+ async (action) => {
225
+ const submitted = await harness.submit({
226
+ actionId: action.actionId,
227
+ parameters: harness.parameters(action.actionId),
228
+ idempotencyKey: key("envelope", action)
229
+ });
230
+ const emitted = (await harness.events()).filter((event) => event.actionInvocationId === submitted.actionInvocationId);
231
+ expect(emitted.length > 0, `action ${action.actionId} mutates domain but emitted no events`);
232
+ const required = ["eventType", "tenantId", "spaceId", "subjectType", "subjectId", "sequence", "correlationId"];
233
+ for (const event of emitted) {
234
+ for (const field of required) {
235
+ expect(event[field] !== void 0 && event[field] !== null, `event ${event.eventType} omits the canonical envelope field "${field}"`);
236
+ }
237
+ }
238
+ const evidence = emitted.map((event) => `${event.eventType}@${event.sequence}`);
239
+ if (!harness.acceptsEnvelope) return [...evidence, "consumer:unobserved"];
240
+ for (const event of emitted) {
241
+ const extended = { ...event, "x-conformance-unknown": true, consistency: "provisional-until-reconciled" };
242
+ const accepted = await harness.acceptsEnvelope(extended);
243
+ expect(accepted, `a consumer rejected ${event.eventType} once it carried a field it did not recognise; additive event changes would break it`);
244
+ }
245
+ return [...evidence, `consumer:tolerated:${emitted.length}`];
246
+ }
247
+ )
248
+ }
249
+ ];
250
+ }
41
251
  function createCertificationResult(input) {
42
252
  const results = new Map(input.checks.map((check) => [check.id, check]));
43
253
  if (results.size !== input.checks.length) throw new Error("Certification evidence contains duplicate check identifiers.");
@@ -49,13 +259,83 @@ function createCertificationResult(input) {
49
259
  if (input.checks.some((check) => check.status === "passed" && check.evidence.length === 0)) throw new Error("Passed certification checks require evidence references.");
50
260
  return { ...input, formatVersion: 1, checks: [...input.checks].sort((a, b) => a.id.localeCompare(b.id)), passed: input.checks.every((check) => check.status === "passed") };
51
261
  }
52
- var conformanceGenerator = { name: "@fabricorg/gen-conformance", version: "0.1.1", generate(ir) {
53
- return ir.modules.map((module2) => ({ path: `${module2.namespace}/conformance-plan.json`, content: (0, import_compiler.stableStringify)({ formatVersion: 1, generator: { name: conformanceGenerator.name, version: conformanceGenerator.version }, compilerVersion: ir.compilerVersion, manifestDigest: ir.manifestDigest, module: module2.namespace, requiredChecks: PHASE_1_CONFORMANCE_CHECKS }) }));
54
- } };
262
+ function buildModuleConformancePlan(module2, manifestDigest) {
263
+ return {
264
+ formatVersion: 1,
265
+ module: module2.namespace,
266
+ manifestDigest,
267
+ requiredChecks: MODULE_CONFORMANCE_CHECKS,
268
+ platformChecks: PLATFORM_CONFORMANCE_CHECKS,
269
+ actions: module2.actions.map((action) => ({
270
+ actionId: action.actionId,
271
+ version: action.version,
272
+ mutatesDomain: action.mutatesDomain,
273
+ idempotent: action.idempotent,
274
+ ...action.execution?.idempotency ? { idempotency: action.execution.idempotency } : {},
275
+ ...action.execution?.authorityMoment ? { authorityMoment: action.execution.authorityMoment } : {},
276
+ ...action.execution?.connectivity ? { connectivity: action.execution.connectivity } : {},
277
+ ...action.execution?.consistency ? { consistency: action.execution.consistency } : {}
278
+ })),
279
+ views: module2.views.map((view) => ({
280
+ name: view.name,
281
+ version: view.version,
282
+ ...view.parameterSchema ? { parameterSchema: view.parameterSchema } : {},
283
+ consumes: view.consumes.map((consumption) => ({ eventType: consumption.eventType, schemaVersions: [...consumption.schemaVersions] }))
284
+ })),
285
+ eventTypes: module2.eventTypes.map((event) => ({ eventType: event.eventType, schemaVersion: event.schemaVersion }))
286
+ };
287
+ }
288
+ function suiteSource(plan, generator) {
289
+ return [
290
+ `// Generated by ${generator.name}@${generator.version}. Do not edit.`,
291
+ `// Manifest digest: ${plan.manifestDigest}`,
292
+ `// Supply ./conformance.harness with a createConformanceHarness() factory returning a fresh, isolated harness.`,
293
+ 'import { expect, it } from "vitest";',
294
+ 'import { moduleConformanceChecks, type ModuleConformancePlan } from "@fabricorg/gen-conformance";',
295
+ 'import { createConformanceHarness } from "./conformance.harness";',
296
+ "",
297
+ `export const plan: ModuleConformancePlan = ${JSON.stringify(plan, null, 2)};`,
298
+ "",
299
+ "for (const check of moduleConformanceChecks()) {",
300
+ " it(`${check.id} \u2014 ${check.title}`, async () => {",
301
+ " const outcome = await check.run(await createConformanceHarness(), plan);",
302
+ ' expect(["passed", "not-applicable"]).toContain(outcome.status);',
303
+ " });",
304
+ "}",
305
+ ""
306
+ ].join("\n");
307
+ }
308
+ var conformanceGenerator = {
309
+ name: "@fabricorg/gen-conformance",
310
+ version: "0.3.0",
311
+ generate(ir) {
312
+ return ir.modules.flatMap((module2) => {
313
+ const plan = buildModuleConformancePlan(module2, ir.manifestDigest);
314
+ return [
315
+ {
316
+ path: `${module2.namespace}/conformance-plan.json`,
317
+ content: (0, import_compiler.stableStringify)({
318
+ ...plan,
319
+ generator: { name: conformanceGenerator.name, version: conformanceGenerator.version },
320
+ compilerVersion: ir.compilerVersion
321
+ })
322
+ },
323
+ {
324
+ path: `${module2.namespace}/conformance.test.ts`,
325
+ content: suiteSource(plan, { name: conformanceGenerator.name, version: conformanceGenerator.version })
326
+ }
327
+ ];
328
+ });
329
+ }
330
+ };
55
331
  // Annotate the CommonJS export names for ESM import in node:
56
332
  0 && (module.exports = {
333
+ MODULE_CONFORMANCE_CHECKS,
57
334
  PHASE_1_CONFORMANCE_CHECKS,
335
+ PLATFORM_CONFORMANCE_CHECKS,
336
+ buildModuleConformancePlan,
58
337
  conformanceGenerator,
59
- createCertificationResult
338
+ createCertificationResult,
339
+ moduleConformanceChecks
60
340
  });
61
341
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../index.ts"],"sourcesContent":["import { stableStringify, type FabricCompilerIr, type GeneratorTarget } from \"@fabricorg/compiler\";\n\nexport const PHASE_1_CONFORMANCE_CHECKS = [\n\t\"fabric.idempotency.same-command-replay.v1\", \"fabric.idempotency.conflicting-payload.v1\",\n\t\"fabric.idempotency.concurrent-submission.v1\", \"fabric.authorization.governing-moment.v1\",\n\t\"fabric.authorization.offline-replay.v1\", \"fabric.events.compatibility.v1\",\n\t\"fabric.provenance.propagation.v1\", \"fabric.consumers.tolerant-envelope.v1\",\n\t\"fabric.documentation.parity.v1\", \"fabric.documentation.llms-contract.v1\",\n] as const;\nexport type Phase1ConformanceCheckId = typeof PHASE_1_CONFORMANCE_CHECKS[number];\nexport interface ConformanceEvidence { id: Phase1ConformanceCheckId; status: \"passed\" | \"failed\"; evidence: string[]; }\nexport interface CertificationResult { formatVersion: 1; manifestDigest: string; compilerVersion: string; generatorDigests: Record<string, string>; checks: ConformanceEvidence[]; passed: boolean; }\n\nexport function createCertificationResult(input: Omit<CertificationResult, \"formatVersion\" | \"passed\">): CertificationResult {\n\tconst results = new Map(input.checks.map((check) => [check.id, check]));\n\tif (results.size !== input.checks.length) throw new Error(\"Certification evidence contains duplicate check identifiers.\");\n\tconst missing = PHASE_1_CONFORMANCE_CHECKS.filter((id) => !results.has(id));\n\tif (missing.length) throw new Error(`Certification evidence is missing mandatory checks: ${missing.join(\", \")}`);\n\tif (!/^[0-9a-f]{64}$/.test(input.manifestDigest)) throw new Error(\"Certification manifestDigest must be a lowercase SHA-256 digest.\");\n\tconst generatorDigests = Object.entries(input.generatorDigests);\n\tif (!generatorDigests.length || generatorDigests.some(([, digest]) => !/^[0-9a-f]{64}$/.test(digest))) throw new Error(\"Certification generatorDigests must contain SHA-256 evidence.\");\n\tif (input.checks.some((check) => check.status === \"passed\" && check.evidence.length === 0)) throw new Error(\"Passed certification checks require evidence references.\");\n\treturn { ...input, formatVersion: 1, checks: [...input.checks].sort((a, b) => a.id.localeCompare(b.id)), passed: input.checks.every((check) => check.status === \"passed\") };\n}\n\nexport const conformanceGenerator: GeneratorTarget = { name: \"@fabricorg/gen-conformance\", version: \"0.1.1\", generate(ir: FabricCompilerIr) { return ir.modules.map((module) => ({ path: `${module.namespace}/conformance-plan.json`, content: stableStringify({ formatVersion: 1, generator: { name: conformanceGenerator.name, version: conformanceGenerator.version }, compilerVersion: ir.compilerVersion, manifestDigest: ir.manifestDigest, module: module.namespace, requiredChecks: PHASE_1_CONFORMANCE_CHECKS }) })); } };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAA6E;AAEtE,IAAM,6BAA6B;AAAA,EACzC;AAAA,EAA6C;AAAA,EAC7C;AAAA,EAA+C;AAAA,EAC/C;AAAA,EAA0C;AAAA,EAC1C;AAAA,EAAoC;AAAA,EACpC;AAAA,EAAkC;AACnC;AAKO,SAAS,0BAA0B,OAAmF;AAC5H,QAAM,UAAU,IAAI,IAAI,MAAM,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC;AACtE,MAAI,QAAQ,SAAS,MAAM,OAAO,OAAQ,OAAM,IAAI,MAAM,8DAA8D;AACxH,QAAM,UAAU,2BAA2B,OAAO,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;AAC1E,MAAI,QAAQ,OAAQ,OAAM,IAAI,MAAM,uDAAuD,QAAQ,KAAK,IAAI,CAAC,EAAE;AAC/G,MAAI,CAAC,iBAAiB,KAAK,MAAM,cAAc,EAAG,OAAM,IAAI,MAAM,kEAAkE;AACpI,QAAM,mBAAmB,OAAO,QAAQ,MAAM,gBAAgB;AAC9D,MAAI,CAAC,iBAAiB,UAAU,iBAAiB,KAAK,CAAC,CAAC,EAAE,MAAM,MAAM,CAAC,iBAAiB,KAAK,MAAM,CAAC,EAAG,OAAM,IAAI,MAAM,+DAA+D;AACtL,MAAI,MAAM,OAAO,KAAK,CAAC,UAAU,MAAM,WAAW,YAAY,MAAM,SAAS,WAAW,CAAC,EAAG,OAAM,IAAI,MAAM,0DAA0D;AACtK,SAAO,EAAE,GAAG,OAAO,eAAe,GAAG,QAAQ,CAAC,GAAG,MAAM,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,GAAG,cAAc,EAAE,EAAE,CAAC,GAAG,QAAQ,MAAM,OAAO,MAAM,CAAC,UAAU,MAAM,WAAW,QAAQ,EAAE;AAC3K;AAEO,IAAM,uBAAwC,EAAE,MAAM,8BAA8B,SAAS,SAAS,SAAS,IAAsB;AAAE,SAAO,GAAG,QAAQ,IAAI,CAACA,aAAY,EAAE,MAAM,GAAGA,QAAO,SAAS,0BAA0B,aAAS,iCAAgB,EAAE,eAAe,GAAG,WAAW,EAAE,MAAM,qBAAqB,MAAM,SAAS,qBAAqB,QAAQ,GAAG,iBAAiB,GAAG,iBAAiB,gBAAgB,GAAG,gBAAgB,QAAQA,QAAO,WAAW,gBAAgB,2BAA2B,CAAC,EAAE,EAAE;AAAG,EAAE;","names":["module"]}
1
+ {"version":3,"sources":["../index.ts"],"sourcesContent":["import { stableStringify, type FabricCompilerIr, type GeneratorTarget } from \"@fabricorg/compiler\";\nimport type { ModuleManifest } from \"@fabricorg/platform\";\n\n/** Checks a single module's own behaviour, verifiable against a governed host. */\nexport const MODULE_CONFORMANCE_CHECKS = [\n\t\"fabric.idempotency.same-command-replay.v1\",\n\t\"fabric.idempotency.conflicting-payload.v1\",\n\t\"fabric.idempotency.concurrent-submission.v1\",\n\t\"fabric.authorization.governing-moment.v1\",\n\t\"fabric.authorization.offline-replay.v1\",\n\t\"fabric.events.compatibility.v1\",\n\t\"fabric.provenance.propagation.v1\",\n\t\"fabric.consumers.tolerant-envelope.v1\",\n] as const;\n\n/**\n * Checks that belong to a repository rather than a module. They are certification\n * evidence like any other check, but no per-module suite can produce them.\n */\nexport const PLATFORM_CONFORMANCE_CHECKS = [\n\t\"fabric.documentation.parity.v1\",\n\t\"fabric.documentation.llms-contract.v1\",\n] as const;\n\nexport const PHASE_1_CONFORMANCE_CHECKS = [...MODULE_CONFORMANCE_CHECKS, ...PLATFORM_CONFORMANCE_CHECKS] as const;\n\nexport type ModuleConformanceCheckId = typeof MODULE_CONFORMANCE_CHECKS[number];\nexport type PlatformConformanceCheckId = typeof PLATFORM_CONFORMANCE_CHECKS[number];\nexport type Phase1ConformanceCheckId = ModuleConformanceCheckId | PlatformConformanceCheckId;\n\nexport interface ConformanceEvidence { id: Phase1ConformanceCheckId; status: \"passed\" | \"failed\"; evidence: string[] }\n\nexport interface CertificationResult {\n\tformatVersion: 1;\n\tmanifestDigest: string;\n\tcompilerVersion: string;\n\tgeneratorDigests: Record<string, string>;\n\tchecks: ConformanceEvidence[];\n\tpassed: boolean;\n}\n\n// ── Plan ────────────────────────────────────────────────────────────────────\n\nexport interface PlannedAction {\n\tactionId: string;\n\tversion: number;\n\tmutatesDomain: boolean;\n\tidempotent: boolean;\n\tidempotency?: \"required\" | \"supported\" | \"prohibited\";\n\tauthorityMoment?: \"capture\" | \"execution\" | \"both\";\n\tconnectivity?: \"online-required\" | \"offline-capturable\";\n\tconsistency?: \"authoritative-now\" | \"provisional-until-reconciled\";\n}\n\nexport interface PlannedView {\n\tname: string;\n\tversion: string;\n\tparameterSchema?: ModuleManifest[\"views\"][number][\"parameterSchema\"];\n\tconsumes: Array<{ eventType: string; schemaVersions: number[] }>;\n}\n\nexport interface ModuleConformancePlan {\n\tformatVersion: 1;\n\tmodule: string;\n\tmanifestDigest: string;\n\trequiredChecks: readonly ModuleConformanceCheckId[];\n\tplatformChecks: readonly PlatformConformanceCheckId[];\n\tactions: PlannedAction[];\n\tviews: PlannedView[];\n\teventTypes: Array<{ eventType: string; schemaVersion: number }>;\n}\n\n// ── Harness contract ────────────────────────────────────────────────────────\n\nexport interface ConformanceScope { tenantId: string; spaceId: string; actorId: string; actorType: string }\n\nexport interface ConformanceSubmitInput {\n\tactionId: string;\n\tparameters: Record<string, unknown>;\n\tidempotencyKey?: string;\n\tcorrelationId?: string;\n\tprovenance?: { source: string; correlationId: string; auditAttributes?: Record<string, string> };\n\t/**\n\t * Declares only the intent of the binding. The harness completes tenant, actor,\n\t * action and parameter-digest identity, because only it knows the command shape.\n\t */\n\tauthorizationBinding?: { governingMoment: \"capture\" | \"execution\" | \"both\"; capturedAt?: string; expiresAt?: string };\n\texecutionReason?: \"initial\" | \"offline_replay\";\n}\n\nexport interface ConformanceSubmitResult {\n\tactionInvocationId: string;\n\tstatus: string;\n\treconciliation?: { kind: string };\n}\n\nexport interface ConformanceEventEnvelope {\n\teventType: string;\n\tcorrelationId?: string;\n\tactionInvocationId?: string;\n\ttenantId?: string;\n\tspaceId?: string;\n\tsubjectType?: string;\n\tsubjectId?: string;\n\tsequence?: number;\n\t[key: string]: unknown;\n}\n\n/**\n * What an application supplies so its module's generated suite can run. Structural\n * by design: any store or host that satisfies it is a valid subject.\n */\nexport interface ConformanceHarness {\n\tscope: ConformanceScope;\n\t/** Representative parameters for an action; the module owns its own fixtures. */\n\tparameters(actionId: string): Record<string, unknown>;\n\tsubmit(input: ConformanceSubmitInput): Promise<ConformanceSubmitResult>;\n\tevents(): Promise<ConformanceEventEnvelope[]>;\n\t/** Withdraw execution-time authority so a replay must be refused. */\n\trevokeAuthority(actionId: string): Promise<void>;\n\t/**\n\t * Observable effects an action has produced so far — events appended, rows written,\n\t * whatever the application counts. Supply it and the idempotency checks prove the\n\t * handler did not run twice, rather than only that the same identifier came back.\n\t */\n\tsideEffects?(actionId: string): Promise<number>;\n\t/**\n\t * Hand a real emitted envelope to a real consumer. Supply it and the\n\t * tolerant-envelope check stops being producer-side only: it proves a consumer\n\t * survives fields it does not recognise, which is what tolerance means.\n\t */\n\tacceptsEnvelope?(envelope: ConformanceEventEnvelope): Promise<boolean> | boolean;\n}\n\nexport type ConformanceOutcome =\n\t| { status: \"passed\"; evidence: string[] }\n\t| { status: \"not-applicable\"; reason: string };\n\nexport interface ConformanceCheck {\n\tid: ModuleConformanceCheckId;\n\ttitle: string;\n\trun(harness: ConformanceHarness, plan: ModuleConformancePlan): Promise<ConformanceOutcome>;\n}\n\nclass ConformanceFailure extends Error {\n\toverride readonly name = \"ConformanceFailure\";\n}\n\nfunction expect(condition: unknown, message: string): asserts condition {\n\tif (!condition) throw new ConformanceFailure(message);\n}\n\nconst idempotentActions = (plan: ModuleConformancePlan): PlannedAction[] =>\n\tplan.actions.filter((action) => action.idempotency !== \"prohibited\" && action.idempotent);\n\nconst key = (label: string, action: PlannedAction): string => `conformance:${label}:${action.actionId}`;\n\nconst conflictReason = (conflict: { code?: string; message: string }): string => conflict.code ?? conflict.message;\n\nasync function conflictOf(run: () => Promise<unknown>): Promise<{ thrown: boolean; code?: string; message: string }> {\n\ttry {\n\t\tawait run();\n\t\treturn { thrown: false, message: \"\" };\n\t} catch (error) {\n\t\tconst code = (error as { code?: string }).code;\n\t\treturn { thrown: true, ...(code ? { code } : {}), message: error instanceof Error ? error.message : String(error) };\n\t}\n}\n\n/**\n * Runs a check against every eligible action, not just the first. A module whose\n * first action conforms and whose second does not must fail, or certification\n * means nothing for the rest of the module.\n */\nasync function forEachAction(\n\tactions: PlannedAction[],\n\treason: string,\n\tbody: (action: PlannedAction) => Promise<string[]>,\n): Promise<ConformanceOutcome> {\n\tif (actions.length === 0) return { status: \"not-applicable\", reason };\n\tconst evidence: string[] = [];\n\tfor (const action of actions) evidence.push(...await body(action));\n\treturn { status: \"passed\", evidence };\n}\n\nexport function moduleConformanceChecks(): ConformanceCheck[] {\n\treturn [\n\t\t{\n\t\t\tid: \"fabric.idempotency.same-command-replay.v1\",\n\t\t\ttitle: \"replaying one command key with the same payload does not re-execute\",\n\t\t\trun: (harness, plan) => forEachAction(idempotentActions(plan), \"module declares no idempotent action\", async (action) => {\n\t\t\t\tconst input = { actionId: action.actionId, parameters: harness.parameters(action.actionId), idempotencyKey: key(\"replay\", action) };\n\t\t\t\tconst first = await harness.submit(input);\n\t\t\t\tconst before = await harness.sideEffects?.(action.actionId);\n\t\t\t\tconst second = await harness.submit(input);\n\t\t\t\texpect(first.actionInvocationId === second.actionInvocationId, `replay of ${action.actionId} produced a second invocation ${second.actionInvocationId} for key ${input.idempotencyKey}`);\n\t\t\t\tconst after = await harness.sideEffects?.(action.actionId);\n\t\t\t\tif (before !== undefined && after !== undefined) {\n\t\t\t\t\texpect(after === before, `replay of ${action.actionId} returned the original invocation but produced ${after - before} further effects; the handler ran again`);\n\t\t\t\t}\n\t\t\t\treturn [`invocation:${first.actionInvocationId}`, `key:${input.idempotencyKey}`, `effects:${after ?? \"unobserved\"}`];\n\t\t\t}),\n\t\t},\n\t\t{\n\t\t\tid: \"fabric.idempotency.conflicting-payload.v1\",\n\t\t\ttitle: \"reusing a command key with an altered payload is refused\",\n\t\t\trun: (harness, plan) => forEachAction(idempotentActions(plan), \"module declares no idempotent action\", async (action) => {\n\t\t\t\tconst idempotencyKey = key(\"conflict\", action);\n\t\t\t\tconst parameters = harness.parameters(action.actionId);\n\t\t\t\tawait harness.submit({ actionId: action.actionId, parameters, idempotencyKey });\n\t\t\t\tconst conflict = await conflictOf(() => harness.submit({\n\t\t\t\t\tactionId: action.actionId,\n\t\t\t\t\tparameters: { ...parameters, \"x-conformance-altered\": true },\n\t\t\t\t\tidempotencyKey,\n\t\t\t\t}));\n\t\t\t\texpect(conflict.thrown, `altered payload reusing key ${idempotencyKey} was accepted instead of refused`);\n\t\t\t\texpect(\n\t\t\t\t\tconflict.code === \"IDEMPOTENCY_CONFLICT\" || /idempotenc/i.test(conflict.message),\n\t\t\t\t\t`altered payload for ${action.actionId} was refused, but not as an idempotency conflict: ${conflict.message}`,\n\t\t\t\t);\n\t\t\t\treturn [`key:${idempotencyKey}`, `refusal:${conflictReason(conflict)}`];\n\t\t\t}),\n\t\t},\n\t\t{\n\t\t\tid: \"fabric.idempotency.concurrent-submission.v1\",\n\t\t\ttitle: \"concurrent identical submissions collapse to one invocation\",\n\t\t\trun: (harness, plan) => forEachAction(idempotentActions(plan), \"module declares no idempotent action\", async (action) => {\n\t\t\t\tconst input = { actionId: action.actionId, parameters: harness.parameters(action.actionId), idempotencyKey: key(\"concurrent\", action) };\n\t\t\t\tconst before = await harness.sideEffects?.(action.actionId);\n\t\t\t\tconst results = await Promise.all([harness.submit(input), harness.submit(input), harness.submit(input)]);\n\t\t\t\tconst ids = new Set(results.map((result) => result.actionInvocationId));\n\t\t\t\texpect(ids.size === 1, `concurrent submissions of ${action.actionId} produced ${ids.size} invocations: ${[...ids].join(\", \")}`);\n\t\t\t\tconst after = await harness.sideEffects?.(action.actionId);\n\t\t\t\tif (before !== undefined && after !== undefined) {\n\t\t\t\t\tconst executions = after - before;\n\t\t\t\t\texpect(executions <= 1, `${results.length} concurrent submissions of ${action.actionId} collapsed to one invocation but produced ${executions} executions' worth of effects`);\n\t\t\t\t}\n\t\t\t\treturn [`invocation:${[...ids][0]}`, `attempts:${results.length}`, `effects:${after ?? \"unobserved\"}`];\n\t\t\t}),\n\t\t},\n\t\t{\n\t\t\tid: \"fabric.authorization.governing-moment.v1\",\n\t\t\ttitle: \"an authorization binding must match the action's declared governing moment\",\n\t\t\trun: (harness, plan) => forEachAction(\n\t\t\t\tplan.actions.filter((action) => action.authorityMoment !== undefined),\n\t\t\t\t\"module declares no action with an authority moment\",\n\t\t\t\tasync (action) => {\n\t\t\t\t\tconst mismatched = action.authorityMoment === \"capture\" ? \"execution\" : \"capture\";\n\t\t\t\t\tconst rejection = await conflictOf(() => harness.submit({\n\t\t\t\t\t\tactionId: action.actionId,\n\t\t\t\t\t\tparameters: harness.parameters(action.actionId),\n\t\t\t\t\t\tauthorizationBinding: { governingMoment: mismatched, capturedAt: new Date(Date.now() - 60_000).toISOString() },\n\t\t\t\t\t}));\n\t\t\t\t\texpect(rejection.thrown, `a binding declaring governingMoment \"${mismatched}\" was accepted for ${action.actionId}, governed at \"${action.authorityMoment}\"`);\n\t\t\t\t\texpect(\n\t\t\t\t\t\t/governingmoment|governing moment/i.test(conflictReason(rejection)),\n\t\t\t\t\t\t`the binding for ${action.actionId} was refused, but not for its governing moment: ${conflictReason(rejection)}`,\n\t\t\t\t\t);\n\t\t\t\t\treturn [`action:${action.actionId}`, `declared:${action.authorityMoment}`, `refused:${mismatched}`];\n\t\t\t\t},\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tid: \"fabric.authorization.offline-replay.v1\",\n\t\t\ttitle: \"an offline capture replayed after authority is withdrawn is refused into reconciliation\",\n\t\t\trun: (harness, plan) => forEachAction(\n\t\t\t\tplan.actions.filter((action) =>\n\t\t\t\t\taction.connectivity === \"offline-capturable\" && action.authorityMoment !== undefined && action.authorityMoment !== \"capture\"),\n\t\t\t\t\"module declares no offline-capturable action governed at execution\",\n\t\t\t\tasync (action) => {\n\t\t\t\t\tawait harness.revokeAuthority(action.actionId);\n\t\t\t\t\tconst replay = await harness.submit({\n\t\t\t\t\t\tactionId: action.actionId,\n\t\t\t\t\t\tparameters: harness.parameters(action.actionId),\n\t\t\t\t\t\tidempotencyKey: key(\"offline-replay\", action),\n\t\t\t\t\t\texecutionReason: \"offline_replay\",\n\t\t\t\t\t});\n\t\t\t\t\texpect(\n\t\t\t\t\t\treplay.status === \"reconciliation_required\",\n\t\t\t\t\t\t`replay of ${action.actionId} after authority withdrawal returned status \"${replay.status}\" instead of reconciliation_required`,\n\t\t\t\t\t);\n\t\t\t\t\texpect(replay.reconciliation !== undefined, `reconciliation_required was returned for ${action.actionId} without a reconciliation outcome`);\n\t\t\t\t\treturn [`action:${action.actionId}`, `reconciliation:${replay.reconciliation?.kind}`];\n\t\t\t\t},\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tid: \"fabric.events.compatibility.v1\",\n\t\t\ttitle: \"every consumed event version is one the module still declares\",\n\t\t\tasync run(_harness, plan) {\n\t\t\t\tif (plan.views.length === 0) return { status: \"not-applicable\", reason: \"module declares no views\" };\n\t\t\t\tconst declared = new Map(plan.eventTypes.map((event) => [event.eventType, event.schemaVersion]));\n\t\t\t\tconst evidence: string[] = [];\n\t\t\t\tfor (const view of plan.views) {\n\t\t\t\t\tfor (const consumption of view.consumes) {\n\t\t\t\t\t\tconst current = declared.get(consumption.eventType);\n\t\t\t\t\t\tif (current === undefined) continue;\n\t\t\t\t\t\texpect(\n\t\t\t\t\t\t\tconsumption.schemaVersions.includes(current),\n\t\t\t\t\t\t\t`view ${view.name}@${view.version} consumes ${consumption.eventType} at [${consumption.schemaVersions.join(\", \")}] but the module now emits version ${current}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tevidence.push(`${view.name}@${view.version}:${consumption.eventType}=${current}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (evidence.length === 0) return { status: \"not-applicable\", reason: \"no view consumes an event this module declares\" };\n\t\t\t\treturn { status: \"passed\", evidence };\n\t\t\t},\n\t\t},\n\t\t{\n\t\t\tid: \"fabric.provenance.propagation.v1\",\n\t\t\ttitle: \"submission provenance reaches the events the action emits\",\n\t\t\trun: (harness, plan) => forEachAction(\n\t\t\t\tplan.actions.filter((action) => action.mutatesDomain),\n\t\t\t\t\"module declares no domain-mutating action\",\n\t\t\t\tasync (action) => {\n\t\t\t\t\tconst correlationId = `conformance-corr-${action.actionId}`;\n\t\t\t\t\tconst submitted = await harness.submit({\n\t\t\t\t\t\tactionId: action.actionId,\n\t\t\t\t\t\tparameters: harness.parameters(action.actionId),\n\t\t\t\t\t\tcorrelationId,\n\t\t\t\t\t\t// Audit attributes are allowlisted per application, so provenance identity is asserted on correlation alone.\n\t\t\t\t\t\tprovenance: { source: \"system\", correlationId },\n\t\t\t\t\t});\n\t\t\t\t\tconst emitted = (await harness.events()).filter((event) => event.actionInvocationId === submitted.actionInvocationId);\n\t\t\t\t\texpect(emitted.length > 0, `action ${action.actionId} mutates domain but emitted no events`);\n\t\t\t\t\tfor (const event of emitted) {\n\t\t\t\t\t\texpect(event.correlationId === correlationId, `event ${event.eventType} carried correlationId ${String(event.correlationId)} instead of ${correlationId}`);\n\t\t\t\t\t}\n\t\t\t\t\treturn [`invocation:${submitted.actionInvocationId}`, `events:${emitted.length}`, `correlationId:${correlationId}`];\n\t\t\t\t},\n\t\t\t),\n\t\t},\n\t\t{\n\t\t\tid: \"fabric.consumers.tolerant-envelope.v1\",\n\t\t\ttitle: \"emitted envelopes are complete, and a consumer tolerates fields it does not know\",\n\t\t\trun: (harness, plan) => forEachAction(\n\t\t\t\tplan.actions.filter((action) => action.mutatesDomain),\n\t\t\t\t\"module declares no domain-mutating action\",\n\t\t\t\tasync (action) => {\n\t\t\t\t\tconst submitted = await harness.submit({\n\t\t\t\t\t\tactionId: action.actionId,\n\t\t\t\t\t\tparameters: harness.parameters(action.actionId),\n\t\t\t\t\t\tidempotencyKey: key(\"envelope\", action),\n\t\t\t\t\t});\n\t\t\t\t\tconst emitted = (await harness.events()).filter((event) => event.actionInvocationId === submitted.actionInvocationId);\n\t\t\t\t\texpect(emitted.length > 0, `action ${action.actionId} mutates domain but emitted no events`);\n\t\t\t\t\tconst required = [\"eventType\", \"tenantId\", \"spaceId\", \"subjectType\", \"subjectId\", \"sequence\", \"correlationId\"] as const;\n\t\t\t\t\tfor (const event of emitted) {\n\t\t\t\t\t\tfor (const field of required) {\n\t\t\t\t\t\t\texpect(event[field] !== undefined && event[field] !== null, `event ${event.eventType} omits the canonical envelope field \"${field}\"`);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tconst evidence = emitted.map((event) => `${event.eventType}@${event.sequence}`);\n\t\t\t\t\tif (!harness.acceptsEnvelope) return [...evidence, \"consumer:unobserved\"];\n\t\t\t\t\tfor (const event of emitted) {\n\t\t\t\t\t\t// Additive fields are exactly what a future schema version introduces.\n\t\t\t\t\t\tconst extended = { ...event, \"x-conformance-unknown\": true, consistency: \"provisional-until-reconciled\" };\n\t\t\t\t\t\tconst accepted = await harness.acceptsEnvelope(extended);\n\t\t\t\t\t\texpect(accepted, `a consumer rejected ${event.eventType} once it carried a field it did not recognise; additive event changes would break it`);\n\t\t\t\t\t}\n\t\t\t\t\treturn [...evidence, `consumer:tolerated:${emitted.length}`];\n\t\t\t\t},\n\t\t\t),\n\t\t},\n\t];\n}\n\n// ── Certification evidence ──────────────────────────────────────────────────\n\nexport function createCertificationResult(input: Omit<CertificationResult, \"formatVersion\" | \"passed\">): CertificationResult {\n\tconst results = new Map(input.checks.map((check) => [check.id, check]));\n\tif (results.size !== input.checks.length) throw new Error(\"Certification evidence contains duplicate check identifiers.\");\n\tconst missing = PHASE_1_CONFORMANCE_CHECKS.filter((id) => !results.has(id));\n\tif (missing.length) throw new Error(`Certification evidence is missing mandatory checks: ${missing.join(\", \")}`);\n\tif (!/^[0-9a-f]{64}$/.test(input.manifestDigest)) throw new Error(\"Certification manifestDigest must be a lowercase SHA-256 digest.\");\n\tconst generatorDigests = Object.entries(input.generatorDigests);\n\tif (!generatorDigests.length || generatorDigests.some(([, digest]) => !/^[0-9a-f]{64}$/.test(digest))) throw new Error(\"Certification generatorDigests must contain SHA-256 evidence.\");\n\tif (input.checks.some((check) => check.status === \"passed\" && check.evidence.length === 0)) throw new Error(\"Passed certification checks require evidence references.\");\n\treturn { ...input, formatVersion: 1, checks: [...input.checks].sort((a, b) => a.id.localeCompare(b.id)), passed: input.checks.every((check) => check.status === \"passed\") };\n}\n\n// ── Generator ───────────────────────────────────────────────────────────────\n\nexport function buildModuleConformancePlan(module: ModuleManifest, manifestDigest: string): ModuleConformancePlan {\n\treturn {\n\t\tformatVersion: 1,\n\t\tmodule: module.namespace,\n\t\tmanifestDigest,\n\t\trequiredChecks: MODULE_CONFORMANCE_CHECKS,\n\t\tplatformChecks: PLATFORM_CONFORMANCE_CHECKS,\n\t\tactions: module.actions.map((action) => ({\n\t\t\tactionId: action.actionId,\n\t\t\tversion: action.version,\n\t\t\tmutatesDomain: action.mutatesDomain,\n\t\t\tidempotent: action.idempotent,\n\t\t\t...(action.execution?.idempotency ? { idempotency: action.execution.idempotency } : {}),\n\t\t\t...(action.execution?.authorityMoment ? { authorityMoment: action.execution.authorityMoment } : {}),\n\t\t\t...(action.execution?.connectivity ? { connectivity: action.execution.connectivity } : {}),\n\t\t\t...(action.execution?.consistency ? { consistency: action.execution.consistency } : {}),\n\t\t})),\n\t\tviews: module.views.map((view) => ({\n\t\t\tname: view.name,\n\t\t\tversion: view.version,\n\t\t\t...(view.parameterSchema ? { parameterSchema: view.parameterSchema } : {}),\n\t\t\tconsumes: view.consumes.map((consumption) => ({ eventType: consumption.eventType, schemaVersions: [...consumption.schemaVersions] })),\n\t\t})),\n\t\teventTypes: module.eventTypes.map((event) => ({ eventType: event.eventType, schemaVersion: event.schemaVersion })),\n\t};\n}\n\nfunction suiteSource(plan: ModuleConformancePlan, generator: { name: string; version: string }): string {\n\treturn [\n\t\t`// Generated by ${generator.name}@${generator.version}. Do not edit.`,\n\t\t`// Manifest digest: ${plan.manifestDigest}`,\n\t\t`// Supply ./conformance.harness with a createConformanceHarness() factory returning a fresh, isolated harness.`,\n\t\t'import { expect, it } from \"vitest\";',\n\t\t'import { moduleConformanceChecks, type ModuleConformancePlan } from \"@fabricorg/gen-conformance\";',\n\t\t'import { createConformanceHarness } from \"./conformance.harness\";',\n\t\t\"\",\n\t\t`export const plan: ModuleConformancePlan = ${JSON.stringify(plan, null, 2)};`,\n\t\t\"\",\n\t\t\"for (const check of moduleConformanceChecks()) {\",\n\t\t\" it(`${check.id} — ${check.title}`, async () => {\",\n\t\t\" const outcome = await check.run(await createConformanceHarness(), plan);\",\n\t\t' expect([\"passed\", \"not-applicable\"]).toContain(outcome.status);',\n\t\t\" });\",\n\t\t\"}\",\n\t\t\"\",\n\t].join(\"\\n\");\n}\n\nexport const conformanceGenerator: GeneratorTarget = {\n\tname: \"@fabricorg/gen-conformance\",\n\tversion: \"0.3.0\",\n\tgenerate(ir: FabricCompilerIr) {\n\t\treturn ir.modules.flatMap((module) => {\n\t\t\tconst plan = buildModuleConformancePlan(module, ir.manifestDigest);\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tpath: `${module.namespace}/conformance-plan.json`,\n\t\t\t\t\tcontent: stableStringify({\n\t\t\t\t\t\t...plan,\n\t\t\t\t\t\tgenerator: { name: conformanceGenerator.name, version: conformanceGenerator.version },\n\t\t\t\t\t\tcompilerVersion: ir.compilerVersion,\n\t\t\t\t\t}),\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tpath: `${module.namespace}/conformance.test.ts`,\n\t\t\t\t\tcontent: suiteSource(plan, { name: conformanceGenerator.name, version: conformanceGenerator.version }),\n\t\t\t\t},\n\t\t\t];\n\t\t});\n\t},\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAA6E;AAItE,IAAM,4BAA4B;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD;AAMO,IAAM,8BAA8B;AAAA,EAC1C;AAAA,EACA;AACD;AAEO,IAAM,6BAA6B,CAAC,GAAG,2BAA2B,GAAG,2BAA2B;AAwHvG,IAAM,qBAAN,cAAiC,MAAM;AAAA,EACpB,OAAO;AAC1B;AAEA,SAAS,OAAO,WAAoB,SAAoC;AACvE,MAAI,CAAC,UAAW,OAAM,IAAI,mBAAmB,OAAO;AACrD;AAEA,IAAM,oBAAoB,CAAC,SAC1B,KAAK,QAAQ,OAAO,CAAC,WAAW,OAAO,gBAAgB,gBAAgB,OAAO,UAAU;AAEzF,IAAM,MAAM,CAAC,OAAe,WAAkC,eAAe,KAAK,IAAI,OAAO,QAAQ;AAErG,IAAM,iBAAiB,CAAC,aAAyD,SAAS,QAAQ,SAAS;AAE3G,eAAe,WAAW,KAA2F;AACpH,MAAI;AACH,UAAM,IAAI;AACV,WAAO,EAAE,QAAQ,OAAO,SAAS,GAAG;AAAA,EACrC,SAAS,OAAO;AACf,UAAM,OAAQ,MAA4B;AAC1C,WAAO,EAAE,QAAQ,MAAM,GAAI,OAAO,EAAE,KAAK,IAAI,CAAC,GAAI,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,EAAE;AAAA,EACnH;AACD;AAOA,eAAe,cACd,SACA,QACA,MAC8B;AAC9B,MAAI,QAAQ,WAAW,EAAG,QAAO,EAAE,QAAQ,kBAAkB,OAAO;AACpE,QAAM,WAAqB,CAAC;AAC5B,aAAW,UAAU,QAAS,UAAS,KAAK,GAAG,MAAM,KAAK,MAAM,CAAC;AACjE,SAAO,EAAE,QAAQ,UAAU,SAAS;AACrC;AAEO,SAAS,0BAA8C;AAC7D,SAAO;AAAA,IACN;AAAA,MACC,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,KAAK,CAAC,SAAS,SAAS,cAAc,kBAAkB,IAAI,GAAG,wCAAwC,OAAO,WAAW;AACxH,cAAM,QAAQ,EAAE,UAAU,OAAO,UAAU,YAAY,QAAQ,WAAW,OAAO,QAAQ,GAAG,gBAAgB,IAAI,UAAU,MAAM,EAAE;AAClI,cAAM,QAAQ,MAAM,QAAQ,OAAO,KAAK;AACxC,cAAM,SAAS,MAAM,QAAQ,cAAc,OAAO,QAAQ;AAC1D,cAAM,SAAS,MAAM,QAAQ,OAAO,KAAK;AACzC,eAAO,MAAM,uBAAuB,OAAO,oBAAoB,aAAa,OAAO,QAAQ,iCAAiC,OAAO,kBAAkB,YAAY,MAAM,cAAc,EAAE;AACvL,cAAM,QAAQ,MAAM,QAAQ,cAAc,OAAO,QAAQ;AACzD,YAAI,WAAW,UAAa,UAAU,QAAW;AAChD,iBAAO,UAAU,QAAQ,aAAa,OAAO,QAAQ,kDAAkD,QAAQ,MAAM,yCAAyC;AAAA,QAC/J;AACA,eAAO,CAAC,cAAc,MAAM,kBAAkB,IAAI,OAAO,MAAM,cAAc,IAAI,WAAW,SAAS,YAAY,EAAE;AAAA,MACpH,CAAC;AAAA,IACF;AAAA,IACA;AAAA,MACC,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,KAAK,CAAC,SAAS,SAAS,cAAc,kBAAkB,IAAI,GAAG,wCAAwC,OAAO,WAAW;AACxH,cAAM,iBAAiB,IAAI,YAAY,MAAM;AAC7C,cAAM,aAAa,QAAQ,WAAW,OAAO,QAAQ;AACrD,cAAM,QAAQ,OAAO,EAAE,UAAU,OAAO,UAAU,YAAY,eAAe,CAAC;AAC9E,cAAM,WAAW,MAAM,WAAW,MAAM,QAAQ,OAAO;AAAA,UACtD,UAAU,OAAO;AAAA,UACjB,YAAY,EAAE,GAAG,YAAY,yBAAyB,KAAK;AAAA,UAC3D;AAAA,QACD,CAAC,CAAC;AACF,eAAO,SAAS,QAAQ,+BAA+B,cAAc,kCAAkC;AACvG;AAAA,UACC,SAAS,SAAS,0BAA0B,cAAc,KAAK,SAAS,OAAO;AAAA,UAC/E,uBAAuB,OAAO,QAAQ,qDAAqD,SAAS,OAAO;AAAA,QAC5G;AACA,eAAO,CAAC,OAAO,cAAc,IAAI,WAAW,eAAe,QAAQ,CAAC,EAAE;AAAA,MACvE,CAAC;AAAA,IACF;AAAA,IACA;AAAA,MACC,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,KAAK,CAAC,SAAS,SAAS,cAAc,kBAAkB,IAAI,GAAG,wCAAwC,OAAO,WAAW;AACxH,cAAM,QAAQ,EAAE,UAAU,OAAO,UAAU,YAAY,QAAQ,WAAW,OAAO,QAAQ,GAAG,gBAAgB,IAAI,cAAc,MAAM,EAAE;AACtI,cAAM,SAAS,MAAM,QAAQ,cAAc,OAAO,QAAQ;AAC1D,cAAM,UAAU,MAAM,QAAQ,IAAI,CAAC,QAAQ,OAAO,KAAK,GAAG,QAAQ,OAAO,KAAK,GAAG,QAAQ,OAAO,KAAK,CAAC,CAAC;AACvG,cAAM,MAAM,IAAI,IAAI,QAAQ,IAAI,CAAC,WAAW,OAAO,kBAAkB,CAAC;AACtE,eAAO,IAAI,SAAS,GAAG,6BAA6B,OAAO,QAAQ,aAAa,IAAI,IAAI,iBAAiB,CAAC,GAAG,GAAG,EAAE,KAAK,IAAI,CAAC,EAAE;AAC9H,cAAM,QAAQ,MAAM,QAAQ,cAAc,OAAO,QAAQ;AACzD,YAAI,WAAW,UAAa,UAAU,QAAW;AAChD,gBAAM,aAAa,QAAQ;AAC3B,iBAAO,cAAc,GAAG,GAAG,QAAQ,MAAM,8BAA8B,OAAO,QAAQ,6CAA6C,UAAU,+BAA+B;AAAA,QAC7K;AACA,eAAO,CAAC,cAAc,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,IAAI,YAAY,QAAQ,MAAM,IAAI,WAAW,SAAS,YAAY,EAAE;AAAA,MACtG,CAAC;AAAA,IACF;AAAA,IACA;AAAA,MACC,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,KAAK,CAAC,SAAS,SAAS;AAAA,QACvB,KAAK,QAAQ,OAAO,CAAC,WAAW,OAAO,oBAAoB,MAAS;AAAA,QACpE;AAAA,QACA,OAAO,WAAW;AACjB,gBAAM,aAAa,OAAO,oBAAoB,YAAY,cAAc;AACxE,gBAAM,YAAY,MAAM,WAAW,MAAM,QAAQ,OAAO;AAAA,YACvD,UAAU,OAAO;AAAA,YACjB,YAAY,QAAQ,WAAW,OAAO,QAAQ;AAAA,YAC9C,sBAAsB,EAAE,iBAAiB,YAAY,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,GAAM,EAAE,YAAY,EAAE;AAAA,UAC9G,CAAC,CAAC;AACF,iBAAO,UAAU,QAAQ,wCAAwC,UAAU,sBAAsB,OAAO,QAAQ,kBAAkB,OAAO,eAAe,GAAG;AAC3J;AAAA,YACC,oCAAoC,KAAK,eAAe,SAAS,CAAC;AAAA,YAClE,mBAAmB,OAAO,QAAQ,mDAAmD,eAAe,SAAS,CAAC;AAAA,UAC/G;AACA,iBAAO,CAAC,UAAU,OAAO,QAAQ,IAAI,YAAY,OAAO,eAAe,IAAI,WAAW,UAAU,EAAE;AAAA,QACnG;AAAA,MACD;AAAA,IACD;AAAA,IACA;AAAA,MACC,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,KAAK,CAAC,SAAS,SAAS;AAAA,QACvB,KAAK,QAAQ,OAAO,CAAC,WACpB,OAAO,iBAAiB,wBAAwB,OAAO,oBAAoB,UAAa,OAAO,oBAAoB,SAAS;AAAA,QAC7H;AAAA,QACA,OAAO,WAAW;AACjB,gBAAM,QAAQ,gBAAgB,OAAO,QAAQ;AAC7C,gBAAM,SAAS,MAAM,QAAQ,OAAO;AAAA,YACnC,UAAU,OAAO;AAAA,YACjB,YAAY,QAAQ,WAAW,OAAO,QAAQ;AAAA,YAC9C,gBAAgB,IAAI,kBAAkB,MAAM;AAAA,YAC5C,iBAAiB;AAAA,UAClB,CAAC;AACD;AAAA,YACC,OAAO,WAAW;AAAA,YAClB,aAAa,OAAO,QAAQ,gDAAgD,OAAO,MAAM;AAAA,UAC1F;AACA,iBAAO,OAAO,mBAAmB,QAAW,4CAA4C,OAAO,QAAQ,mCAAmC;AAC1I,iBAAO,CAAC,UAAU,OAAO,QAAQ,IAAI,kBAAkB,OAAO,gBAAgB,IAAI,EAAE;AAAA,QACrF;AAAA,MACD;AAAA,IACD;AAAA,IACA;AAAA,MACC,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,MAAM,IAAI,UAAU,MAAM;AACzB,YAAI,KAAK,MAAM,WAAW,EAAG,QAAO,EAAE,QAAQ,kBAAkB,QAAQ,2BAA2B;AACnG,cAAM,WAAW,IAAI,IAAI,KAAK,WAAW,IAAI,CAAC,UAAU,CAAC,MAAM,WAAW,MAAM,aAAa,CAAC,CAAC;AAC/F,cAAM,WAAqB,CAAC;AAC5B,mBAAW,QAAQ,KAAK,OAAO;AAC9B,qBAAW,eAAe,KAAK,UAAU;AACxC,kBAAM,UAAU,SAAS,IAAI,YAAY,SAAS;AAClD,gBAAI,YAAY,OAAW;AAC3B;AAAA,cACC,YAAY,eAAe,SAAS,OAAO;AAAA,cAC3C,QAAQ,KAAK,IAAI,IAAI,KAAK,OAAO,aAAa,YAAY,SAAS,QAAQ,YAAY,eAAe,KAAK,IAAI,CAAC,sCAAsC,OAAO;AAAA,YAC9J;AACA,qBAAS,KAAK,GAAG,KAAK,IAAI,IAAI,KAAK,OAAO,IAAI,YAAY,SAAS,IAAI,OAAO,EAAE;AAAA,UACjF;AAAA,QACD;AACA,YAAI,SAAS,WAAW,EAAG,QAAO,EAAE,QAAQ,kBAAkB,QAAQ,iDAAiD;AACvH,eAAO,EAAE,QAAQ,UAAU,SAAS;AAAA,MACrC;AAAA,IACD;AAAA,IACA;AAAA,MACC,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,KAAK,CAAC,SAAS,SAAS;AAAA,QACvB,KAAK,QAAQ,OAAO,CAAC,WAAW,OAAO,aAAa;AAAA,QACpD;AAAA,QACA,OAAO,WAAW;AACjB,gBAAM,gBAAgB,oBAAoB,OAAO,QAAQ;AACzD,gBAAM,YAAY,MAAM,QAAQ,OAAO;AAAA,YACtC,UAAU,OAAO;AAAA,YACjB,YAAY,QAAQ,WAAW,OAAO,QAAQ;AAAA,YAC9C;AAAA;AAAA,YAEA,YAAY,EAAE,QAAQ,UAAU,cAAc;AAAA,UAC/C,CAAC;AACD,gBAAM,WAAW,MAAM,QAAQ,OAAO,GAAG,OAAO,CAAC,UAAU,MAAM,uBAAuB,UAAU,kBAAkB;AACpH,iBAAO,QAAQ,SAAS,GAAG,UAAU,OAAO,QAAQ,uCAAuC;AAC3F,qBAAW,SAAS,SAAS;AAC5B,mBAAO,MAAM,kBAAkB,eAAe,SAAS,MAAM,SAAS,0BAA0B,OAAO,MAAM,aAAa,CAAC,eAAe,aAAa,EAAE;AAAA,UAC1J;AACA,iBAAO,CAAC,cAAc,UAAU,kBAAkB,IAAI,UAAU,QAAQ,MAAM,IAAI,iBAAiB,aAAa,EAAE;AAAA,QACnH;AAAA,MACD;AAAA,IACD;AAAA,IACA;AAAA,MACC,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,KAAK,CAAC,SAAS,SAAS;AAAA,QACvB,KAAK,QAAQ,OAAO,CAAC,WAAW,OAAO,aAAa;AAAA,QACpD;AAAA,QACA,OAAO,WAAW;AACjB,gBAAM,YAAY,MAAM,QAAQ,OAAO;AAAA,YACtC,UAAU,OAAO;AAAA,YACjB,YAAY,QAAQ,WAAW,OAAO,QAAQ;AAAA,YAC9C,gBAAgB,IAAI,YAAY,MAAM;AAAA,UACvC,CAAC;AACD,gBAAM,WAAW,MAAM,QAAQ,OAAO,GAAG,OAAO,CAAC,UAAU,MAAM,uBAAuB,UAAU,kBAAkB;AACpH,iBAAO,QAAQ,SAAS,GAAG,UAAU,OAAO,QAAQ,uCAAuC;AAC3F,gBAAM,WAAW,CAAC,aAAa,YAAY,WAAW,eAAe,aAAa,YAAY,eAAe;AAC7G,qBAAW,SAAS,SAAS;AAC5B,uBAAW,SAAS,UAAU;AAC7B,qBAAO,MAAM,KAAK,MAAM,UAAa,MAAM,KAAK,MAAM,MAAM,SAAS,MAAM,SAAS,wCAAwC,KAAK,GAAG;AAAA,YACrI;AAAA,UACD;AACA,gBAAM,WAAW,QAAQ,IAAI,CAAC,UAAU,GAAG,MAAM,SAAS,IAAI,MAAM,QAAQ,EAAE;AAC9E,cAAI,CAAC,QAAQ,gBAAiB,QAAO,CAAC,GAAG,UAAU,qBAAqB;AACxE,qBAAW,SAAS,SAAS;AAE5B,kBAAM,WAAW,EAAE,GAAG,OAAO,yBAAyB,MAAM,aAAa,+BAA+B;AACxG,kBAAM,WAAW,MAAM,QAAQ,gBAAgB,QAAQ;AACvD,mBAAO,UAAU,uBAAuB,MAAM,SAAS,sFAAsF;AAAA,UAC9I;AACA,iBAAO,CAAC,GAAG,UAAU,sBAAsB,QAAQ,MAAM,EAAE;AAAA,QAC5D;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACD;AAIO,SAAS,0BAA0B,OAAmF;AAC5H,QAAM,UAAU,IAAI,IAAI,MAAM,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC;AACtE,MAAI,QAAQ,SAAS,MAAM,OAAO,OAAQ,OAAM,IAAI,MAAM,8DAA8D;AACxH,QAAM,UAAU,2BAA2B,OAAO,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;AAC1E,MAAI,QAAQ,OAAQ,OAAM,IAAI,MAAM,uDAAuD,QAAQ,KAAK,IAAI,CAAC,EAAE;AAC/G,MAAI,CAAC,iBAAiB,KAAK,MAAM,cAAc,EAAG,OAAM,IAAI,MAAM,kEAAkE;AACpI,QAAM,mBAAmB,OAAO,QAAQ,MAAM,gBAAgB;AAC9D,MAAI,CAAC,iBAAiB,UAAU,iBAAiB,KAAK,CAAC,CAAC,EAAE,MAAM,MAAM,CAAC,iBAAiB,KAAK,MAAM,CAAC,EAAG,OAAM,IAAI,MAAM,+DAA+D;AACtL,MAAI,MAAM,OAAO,KAAK,CAAC,UAAU,MAAM,WAAW,YAAY,MAAM,SAAS,WAAW,CAAC,EAAG,OAAM,IAAI,MAAM,0DAA0D;AACtK,SAAO,EAAE,GAAG,OAAO,eAAe,GAAG,QAAQ,CAAC,GAAG,MAAM,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,GAAG,cAAc,EAAE,EAAE,CAAC,GAAG,QAAQ,MAAM,OAAO,MAAM,CAAC,UAAU,MAAM,WAAW,QAAQ,EAAE;AAC3K;AAIO,SAAS,2BAA2BA,SAAwB,gBAA+C;AACjH,SAAO;AAAA,IACN,eAAe;AAAA,IACf,QAAQA,QAAO;AAAA,IACf;AAAA,IACA,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,SAASA,QAAO,QAAQ,IAAI,CAAC,YAAY;AAAA,MACxC,UAAU,OAAO;AAAA,MACjB,SAAS,OAAO;AAAA,MAChB,eAAe,OAAO;AAAA,MACtB,YAAY,OAAO;AAAA,MACnB,GAAI,OAAO,WAAW,cAAc,EAAE,aAAa,OAAO,UAAU,YAAY,IAAI,CAAC;AAAA,MACrF,GAAI,OAAO,WAAW,kBAAkB,EAAE,iBAAiB,OAAO,UAAU,gBAAgB,IAAI,CAAC;AAAA,MACjG,GAAI,OAAO,WAAW,eAAe,EAAE,cAAc,OAAO,UAAU,aAAa,IAAI,CAAC;AAAA,MACxF,GAAI,OAAO,WAAW,cAAc,EAAE,aAAa,OAAO,UAAU,YAAY,IAAI,CAAC;AAAA,IACtF,EAAE;AAAA,IACF,OAAOA,QAAO,MAAM,IAAI,CAAC,UAAU;AAAA,MAClC,MAAM,KAAK;AAAA,MACX,SAAS,KAAK;AAAA,MACd,GAAI,KAAK,kBAAkB,EAAE,iBAAiB,KAAK,gBAAgB,IAAI,CAAC;AAAA,MACxE,UAAU,KAAK,SAAS,IAAI,CAAC,iBAAiB,EAAE,WAAW,YAAY,WAAW,gBAAgB,CAAC,GAAG,YAAY,cAAc,EAAE,EAAE;AAAA,IACrI,EAAE;AAAA,IACF,YAAYA,QAAO,WAAW,IAAI,CAAC,WAAW,EAAE,WAAW,MAAM,WAAW,eAAe,MAAM,cAAc,EAAE;AAAA,EAClH;AACD;AAEA,SAAS,YAAY,MAA6B,WAAsD;AACvG,SAAO;AAAA,IACN,mBAAmB,UAAU,IAAI,IAAI,UAAU,OAAO;AAAA,IACtD,uBAAuB,KAAK,cAAc;AAAA,IAC1C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,8CAA8C,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA,IAC3E;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,EAAE,KAAK,IAAI;AACZ;AAEO,IAAM,uBAAwC;AAAA,EACpD,MAAM;AAAA,EACN,SAAS;AAAA,EACT,SAAS,IAAsB;AAC9B,WAAO,GAAG,QAAQ,QAAQ,CAACA,YAAW;AACrC,YAAM,OAAO,2BAA2BA,SAAQ,GAAG,cAAc;AACjE,aAAO;AAAA,QACN;AAAA,UACC,MAAM,GAAGA,QAAO,SAAS;AAAA,UACzB,aAAS,iCAAgB;AAAA,YACxB,GAAG;AAAA,YACH,WAAW,EAAE,MAAM,qBAAqB,MAAM,SAAS,qBAAqB,QAAQ;AAAA,YACpF,iBAAiB,GAAG;AAAA,UACrB,CAAC;AAAA,QACF;AAAA,QACA;AAAA,UACC,MAAM,GAAGA,QAAO,SAAS;AAAA,UACzB,SAAS,YAAY,MAAM,EAAE,MAAM,qBAAqB,MAAM,SAAS,qBAAqB,QAAQ,CAAC;AAAA,QACtG;AAAA,MACD;AAAA,IACD,CAAC;AAAA,EACF;AACD;","names":["module"]}
package/dist/index.d.cts CHANGED
@@ -1,7 +1,17 @@
1
1
  import { GeneratorTarget } from '@fabricorg/compiler';
2
+ import { ModuleManifest } from '@fabricorg/platform';
2
3
 
4
+ /** Checks a single module's own behaviour, verifiable against a governed host. */
5
+ declare const MODULE_CONFORMANCE_CHECKS: readonly ["fabric.idempotency.same-command-replay.v1", "fabric.idempotency.conflicting-payload.v1", "fabric.idempotency.concurrent-submission.v1", "fabric.authorization.governing-moment.v1", "fabric.authorization.offline-replay.v1", "fabric.events.compatibility.v1", "fabric.provenance.propagation.v1", "fabric.consumers.tolerant-envelope.v1"];
6
+ /**
7
+ * Checks that belong to a repository rather than a module. They are certification
8
+ * evidence like any other check, but no per-module suite can produce them.
9
+ */
10
+ declare const PLATFORM_CONFORMANCE_CHECKS: readonly ["fabric.documentation.parity.v1", "fabric.documentation.llms-contract.v1"];
3
11
  declare const PHASE_1_CONFORMANCE_CHECKS: readonly ["fabric.idempotency.same-command-replay.v1", "fabric.idempotency.conflicting-payload.v1", "fabric.idempotency.concurrent-submission.v1", "fabric.authorization.governing-moment.v1", "fabric.authorization.offline-replay.v1", "fabric.events.compatibility.v1", "fabric.provenance.propagation.v1", "fabric.consumers.tolerant-envelope.v1", "fabric.documentation.parity.v1", "fabric.documentation.llms-contract.v1"];
4
- type Phase1ConformanceCheckId = typeof PHASE_1_CONFORMANCE_CHECKS[number];
12
+ type ModuleConformanceCheckId = typeof MODULE_CONFORMANCE_CHECKS[number];
13
+ type PlatformConformanceCheckId = typeof PLATFORM_CONFORMANCE_CHECKS[number];
14
+ type Phase1ConformanceCheckId = ModuleConformanceCheckId | PlatformConformanceCheckId;
5
15
  interface ConformanceEvidence {
6
16
  id: Phase1ConformanceCheckId;
7
17
  status: "passed" | "failed";
@@ -15,7 +25,123 @@ interface CertificationResult {
15
25
  checks: ConformanceEvidence[];
16
26
  passed: boolean;
17
27
  }
28
+ interface PlannedAction {
29
+ actionId: string;
30
+ version: number;
31
+ mutatesDomain: boolean;
32
+ idempotent: boolean;
33
+ idempotency?: "required" | "supported" | "prohibited";
34
+ authorityMoment?: "capture" | "execution" | "both";
35
+ connectivity?: "online-required" | "offline-capturable";
36
+ consistency?: "authoritative-now" | "provisional-until-reconciled";
37
+ }
38
+ interface PlannedView {
39
+ name: string;
40
+ version: string;
41
+ parameterSchema?: ModuleManifest["views"][number]["parameterSchema"];
42
+ consumes: Array<{
43
+ eventType: string;
44
+ schemaVersions: number[];
45
+ }>;
46
+ }
47
+ interface ModuleConformancePlan {
48
+ formatVersion: 1;
49
+ module: string;
50
+ manifestDigest: string;
51
+ requiredChecks: readonly ModuleConformanceCheckId[];
52
+ platformChecks: readonly PlatformConformanceCheckId[];
53
+ actions: PlannedAction[];
54
+ views: PlannedView[];
55
+ eventTypes: Array<{
56
+ eventType: string;
57
+ schemaVersion: number;
58
+ }>;
59
+ }
60
+ interface ConformanceScope {
61
+ tenantId: string;
62
+ spaceId: string;
63
+ actorId: string;
64
+ actorType: string;
65
+ }
66
+ interface ConformanceSubmitInput {
67
+ actionId: string;
68
+ parameters: Record<string, unknown>;
69
+ idempotencyKey?: string;
70
+ correlationId?: string;
71
+ provenance?: {
72
+ source: string;
73
+ correlationId: string;
74
+ auditAttributes?: Record<string, string>;
75
+ };
76
+ /**
77
+ * Declares only the intent of the binding. The harness completes tenant, actor,
78
+ * action and parameter-digest identity, because only it knows the command shape.
79
+ */
80
+ authorizationBinding?: {
81
+ governingMoment: "capture" | "execution" | "both";
82
+ capturedAt?: string;
83
+ expiresAt?: string;
84
+ };
85
+ executionReason?: "initial" | "offline_replay";
86
+ }
87
+ interface ConformanceSubmitResult {
88
+ actionInvocationId: string;
89
+ status: string;
90
+ reconciliation?: {
91
+ kind: string;
92
+ };
93
+ }
94
+ interface ConformanceEventEnvelope {
95
+ eventType: string;
96
+ correlationId?: string;
97
+ actionInvocationId?: string;
98
+ tenantId?: string;
99
+ spaceId?: string;
100
+ subjectType?: string;
101
+ subjectId?: string;
102
+ sequence?: number;
103
+ [key: string]: unknown;
104
+ }
105
+ /**
106
+ * What an application supplies so its module's generated suite can run. Structural
107
+ * by design: any store or host that satisfies it is a valid subject.
108
+ */
109
+ interface ConformanceHarness {
110
+ scope: ConformanceScope;
111
+ /** Representative parameters for an action; the module owns its own fixtures. */
112
+ parameters(actionId: string): Record<string, unknown>;
113
+ submit(input: ConformanceSubmitInput): Promise<ConformanceSubmitResult>;
114
+ events(): Promise<ConformanceEventEnvelope[]>;
115
+ /** Withdraw execution-time authority so a replay must be refused. */
116
+ revokeAuthority(actionId: string): Promise<void>;
117
+ /**
118
+ * Observable effects an action has produced so far — events appended, rows written,
119
+ * whatever the application counts. Supply it and the idempotency checks prove the
120
+ * handler did not run twice, rather than only that the same identifier came back.
121
+ */
122
+ sideEffects?(actionId: string): Promise<number>;
123
+ /**
124
+ * Hand a real emitted envelope to a real consumer. Supply it and the
125
+ * tolerant-envelope check stops being producer-side only: it proves a consumer
126
+ * survives fields it does not recognise, which is what tolerance means.
127
+ */
128
+ acceptsEnvelope?(envelope: ConformanceEventEnvelope): Promise<boolean> | boolean;
129
+ }
130
+ type ConformanceOutcome = {
131
+ status: "passed";
132
+ evidence: string[];
133
+ } | {
134
+ status: "not-applicable";
135
+ reason: string;
136
+ };
137
+ interface ConformanceCheck {
138
+ id: ModuleConformanceCheckId;
139
+ title: string;
140
+ run(harness: ConformanceHarness, plan: ModuleConformancePlan): Promise<ConformanceOutcome>;
141
+ }
142
+ declare function moduleConformanceChecks(): ConformanceCheck[];
18
143
  declare function createCertificationResult(input: Omit<CertificationResult, "formatVersion" | "passed">): CertificationResult;
144
+ declare function buildModuleConformancePlan(module: ModuleManifest, manifestDigest: string): ModuleConformancePlan;
19
145
  declare const conformanceGenerator: GeneratorTarget;
20
146
 
21
- export { type CertificationResult, type ConformanceEvidence, PHASE_1_CONFORMANCE_CHECKS, type Phase1ConformanceCheckId, conformanceGenerator, createCertificationResult };
147
+ export { type CertificationResult, type ConformanceCheck, type ConformanceEventEnvelope, type ConformanceEvidence, type ConformanceHarness, type ConformanceOutcome, type ConformanceScope, type ConformanceSubmitInput, type ConformanceSubmitResult, MODULE_CONFORMANCE_CHECKS, type ModuleConformanceCheckId, type ModuleConformancePlan, PHASE_1_CONFORMANCE_CHECKS, PLATFORM_CONFORMANCE_CHECKS, type Phase1ConformanceCheckId, type PlannedAction, type PlannedView, type PlatformConformanceCheckId, buildModuleConformancePlan, conformanceGenerator, createCertificationResult, moduleConformanceChecks };