@githolon/dsl 0.101.6 → 0.102.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 (120) hide show
  1. package/dart/CHANGELOG.md +13 -0
  2. package/dart/lib/nomos_client.dart +3 -52
  3. package/dart/lib/src/dev_cloud.dart +5 -0
  4. package/dart/lib/src/home.dart +10 -15
  5. package/dart/lib/src/nms_conformance_runtime.dart +12 -0
  6. package/dart/lib/src/nms_generated_runtime.dart +29 -0
  7. package/dart/lib/src/nms_test_environment.dart +8 -0
  8. package/dart/lib/src/node_runner_transport.dart +56 -18
  9. package/dart/lib/src/provider.dart +5 -1
  10. package/dart/lib/src/record_origin.dart +55 -0
  11. package/dart/lib/src/runner/node-entry.mjs +9105 -0
  12. package/dart/lib/src/runner/offline-install.mjs +4729 -0
  13. package/dart/lib/src/session_bound.dart +23 -10
  14. package/dart/lib/src/source_trust.dart +51 -0
  15. package/dart/lib/src/test_harness.dart +490 -58
  16. package/dart/lib/src/webview_bridge.dart +167 -58
  17. package/dart/lib/src/workspace_name.dart +7 -1
  18. package/dart/pubspec.lock +3 -3
  19. package/dart/pubspec.yaml +4 -2
  20. package/dart/test/acquire_session_credentials_test.dart +34 -17
  21. package/dart/test/acquire_session_test.dart +109 -24
  22. package/dart/test/adv_realm_interference_test.dart +227 -99
  23. package/dart/test/bundle_version_pairing_test.dart +1 -1
  24. package/dart/test/cloud_bound_topology_test.dart +1 -1
  25. package/dart/test/cluster_attested_test.dart +52 -35
  26. package/dart/test/cluster_births_test.dart +5 -2
  27. package/dart/test/cluster_device_keyed_acceptance_test.dart +5 -2
  28. package/dart/test/cluster_local_autosync_test.dart +5 -2
  29. package/dart/test/cluster_scale_test.dart +5 -2
  30. package/dart/test/compat_test.dart +1 -1
  31. package/dart/test/dlq_session_surface_test.dart +2 -1
  32. package/dart/test/errors_test.dart +1 -1
  33. package/dart/test/first_app_gauntlet_test.dart +78 -51
  34. package/dart/test/four_layer_nested_topology_test.dart +1 -1
  35. package/dart/test/harness_phase_timeout_test.dart +1 -1
  36. package/dart/test/home_parity_test.dart +9 -5
  37. package/dart/test/local_sync_inert_test.dart +22 -14
  38. package/dart/test/node_runner_transport_test.dart +9 -5
  39. package/dart/test/null_slot_test.dart +1 -1
  40. package/dart/test/parent_signer_recovery_test.dart +5 -2
  41. package/dart/test/schema_validation_test.dart +1 -1
  42. package/dart/test/sealing_client_test.dart +2 -1
  43. package/dart/test/session_bound_test.dart +92 -119
  44. package/dart/test/stale_bundle_test.dart +1 -1
  45. package/dart/test/test_harness_test.dart +77 -22
  46. package/dart/test/vo_read_typing_test.dart +32 -14
  47. package/dart/test/watch_after_offer_stall_test.dart +2 -1
  48. package/dart/test/webview_bridge_test.dart +17 -4
  49. package/dart/test/wire_test.dart +1 -1
  50. package/dart_types/CHANGELOG.md +8 -0
  51. package/dart_types/lib/nomos_types.dart +7 -6
  52. package/dart_types/lib/src/activity.dart +23 -13
  53. package/dart_types/lib/src/foreign_ref.dart +61 -112
  54. package/dart_types/lib/src/invitation.dart +96 -0
  55. package/dart_types/lib/src/nomos_ref.dart +97 -59
  56. package/dart_types/pubspec.yaml +1 -1
  57. package/dart_types/test/surfaced_test.dart +125 -19
  58. package/package.json +7 -3
  59. package/runtime/generated-application-host.js +8851 -0
  60. package/src/activity.ts +2 -2
  61. package/src/aggregate.ts +24 -1
  62. package/src/application_composition.ts +282 -0
  63. package/src/application_topology.ts +151 -0
  64. package/src/attested_core.ts +2 -2
  65. package/src/authoring_context.ts +9 -0
  66. package/src/birth_meter_ensure.ts +1 -1
  67. package/src/births.ts +53 -5
  68. package/src/build_package.ts +79 -71
  69. package/src/business_birth.ts +93 -10
  70. package/src/clear_directive.ts +3 -1
  71. package/src/codegen_dart.ts +369 -420
  72. package/src/codegen_dart_application.ts +1508 -0
  73. package/src/codegen_dart_client.ts +156 -95
  74. package/src/codegen_dart_scenario.ts +299 -0
  75. package/src/codegen_openapi.ts +8 -3
  76. package/src/codegen_proof.ts +1113 -1137
  77. package/src/codegen_provider_dart.ts +12 -1
  78. package/src/codegen_ts.ts +1176 -496
  79. package/src/compat_package_main.ts +22 -10
  80. package/src/compile_package_main.ts +1536 -337
  81. package/src/contract.ts +10 -4
  82. package/src/dart_barrel_guard.ts +5 -1
  83. package/src/describe_model.ts +13 -5
  84. package/src/directive.ts +244 -5
  85. package/src/engine_entry.ts +56 -13
  86. package/src/engine_javascript.ts +31 -0
  87. package/src/evolve_preview.ts +3 -12
  88. package/src/framework/application_home.ts +24 -10
  89. package/src/framework/capability.ts +15 -1
  90. package/src/framework/domain_lifecycle.ts +8 -0
  91. package/src/framework/framework_aggregates.ts +2 -2
  92. package/src/framework/genesis.ts +11 -1
  93. package/src/framework/home.ts +178 -75
  94. package/src/framework/impure_capability.ts +24 -7
  95. package/src/framework/relations.ts +13 -5
  96. package/src/framework/workspaces.ts +13 -12
  97. package/src/generated_client_names.ts +42 -3
  98. package/src/idof_lint.ts +65 -13
  99. package/src/index.ts +46 -12
  100. package/src/intent.ts +587 -0
  101. package/src/law_check.ts +64 -16
  102. package/src/precondition.ts +16 -4
  103. package/src/read_projection_namespace.ts +2 -7
  104. package/src/recipient.ts +33 -0
  105. package/src/relation_schema.ts +93 -0
  106. package/src/secondary_ensure.ts +11 -2
  107. package/src/shape_compat.ts +11 -1
  108. package/src/usd.ts +30 -8
  109. package/src/usd_layers.ts +447 -246
  110. package/src/usd_state.ts +1 -1
  111. package/src/value_object.ts +49 -13
  112. package/src/wire_encode.ts +124 -26
  113. package/src/workspace_sharing.ts +269 -0
  114. package/src/zod_introspection.ts +84 -0
  115. package/dart/example/nomos_secure_key_store.dart +0 -82
  116. package/dart/example/nomos_webview_transport.dart +0 -63
  117. package/dart/lib/nomos_headless.dart +0 -50
  118. package/dart/lib/testing.dart +0 -14
  119. package/dart/test/co2_product_gauntlet_test.dart +0 -244
  120. package/src/framework/identity.ts +0 -537
@@ -7,8 +7,8 @@
7
7
 
8
8
  /**
9
9
  * GENERATED PROOF CODEGEN — `build/<name>.proof.mts`, the runnable e2e SYNTHESIZED
10
- * FROM THE LAW ITSELF (the field-test-6 ask: reshaping the domain meant rewriting
11
- * test/e2e.mts by hand; now the proof reshapes itself on every compile).
10
+ * FROM THE LAW ITSELF (reshaping the domain used to mean repairing a second,
11
+ * handwritten client story; now the proof reshapes itself on every compile).
12
12
  *
13
13
  * `generateTsProof(modules, opts)` reads the domain's ACTUAL directives / queries /
14
14
  * counts (the same composed modules every other emitter sees) and emits a
@@ -35,17 +35,17 @@
35
35
  import type { z } from "zod";
36
36
 
37
37
  import { BUSINESS_BIRTH_SEED_PAYLOAD_FIELD, type AggregateHandle } from "./aggregate.js";
38
- import type { Field } from "./fields.js";
39
- import type { Directive } from "./directive.js";
38
+ import type { Directive, ReferentialMarker } from "./directive.js";
40
39
  import type { DomainModule } from "./codegen_dart.js";
41
40
  import type { QueryDecl } from "./query.js";
42
41
  import type { FieldOp } from "./ops.js";
42
+ import type { Field } from "./fields.js";
43
43
  import type { RelationTypeDecl, Rewrite } from "./relation_schema.js";
44
44
  import type { WorkspaceInvariantDecl } from "./framework/workspace_invariant.js";
45
45
  import { finishCount } from "./count.js";
46
46
  import { clearDirectiveId } from "./clear_directive.js";
47
47
  import type { DomainInterface } from "./shape_compat.js";
48
- import { voMetaOf, voSample } from "./value_object.js";
48
+ import { idOfMetaOf, idOfTargetKindOf, voMetaOf, voSample } from "./value_object.js";
49
49
  import { mintedCreateField } from "./workspace_routing.js";
50
50
  import { deterministicPorts } from "./ctx.js";
51
51
  import { __setDispatchDomain, __setDispatchContext } from "./framework/relations.js";
@@ -54,8 +54,8 @@ import { __resetAuthoring, __drainAuthoring } from "./authoring.js";
54
54
  import { __resetReads, __drainReads } from "./read.js";
55
55
  import {
56
56
  autoStampFields,
57
- tsClientFactoryName,
58
- tsHashConstName,
57
+ domainEncryptionMap,
58
+ tsApplicationName,
59
59
  zodArrayElement,
60
60
  zodDef,
61
61
  zodEnumValues,
@@ -63,6 +63,10 @@ import {
63
63
  zodObjectShape,
64
64
  zodUnwrapLazy,
65
65
  } from "./codegen_ts.js";
66
+ import { isNamespacedAggregate, qualifyReadProjectionType } from "./read_projection_namespace.js";
67
+ import { isBusinessIntent } from "./intent.js";
68
+ import { zodSampleNumber, zodSampleString } from "./zod_introspection.js";
69
+ import { generatedAggregateCollectionName } from "./generated_client_names.js";
66
70
 
67
71
  /** Shared empty visited-set for the lazy-recursion guard (no allocation on the common path). */
68
72
  const EMPTY_LAZY_VISITED: ReadonlySet<z.ZodTypeAny> = new Set();
@@ -161,37 +165,23 @@ function uniquifyBirthPayload(
161
165
  return suffixed;
162
166
  }
163
167
 
164
- // Constrained-string candidates probed against a field's OWN schema when the readable `sample-<field>`
165
- // fails it (a `.regex()/.length()/.email()/.url()` bound — co2: a locale-pattern `defaultLocale` was
166
- // handed `sample-defaultLocale`, violating its own schema and killing the whole leg downstream). Ordered
167
- // common-first; the READABLE sample stays the first try so unconstrained fields are byte-stable.
168
- const STRING_CANDIDATES: readonly string[] = [
169
- "sample", "en", "en-GB", "AA", "A1", "a", "1", "2026-01-01", "2026-01-01T00:00:00Z",
170
- "a@example.com", "https://example.com", "#000000", "00000000-0000-0000-0000-000000000000",
171
- "0000000000000000000000000000000000000000000000000000000000000000", // a 64-hex digest
172
- ];
173
168
  function sampleString(zt: z.ZodTypeAny, field: string): string {
174
- const readable = `sample-${field}`;
175
- if (zt.safeParse(readable).success) return readable;
176
- for (const cand of SUBJECT_CANDIDATES) if (zt.safeParse(cand).success) return cand;
177
- for (const cand of STRING_CANDIDATES) if (zt.safeParse(cand).success) return cand;
178
- // NO INVALID SAMPLE (co2): returning a schema-violating string poisons every consumer downstream (the
179
- // recipe probe, the proof leg, the generated .mts) with a mystery refusal — throw NAMED instead (the
180
- // callers' try/catch degrades to the same honest skip an unsynthesizable shape gets).
181
- throw new Error(
182
- `codegen-proof: field '${field}': no sample satisfies its own string schema (a .regex()/.length() ` +
183
- `bound none of the ${1 + SUBJECT_CANDIDATES.length + STRING_CANDIDATES.length} candidates fit) — ` +
184
- `loosen the pattern, or prove that directive by hand in test/e2e.mts`,
185
- );
169
+ try {
170
+ return zodSampleString(zt, field);
171
+ } catch {
172
+ throw new Error(
173
+ `codegen-proof: field '${field}': no sample satisfies its own string schema — ` +
174
+ "loosen the pattern or provide a generator-readable lawful example",
175
+ );
176
+ }
186
177
  }
187
178
 
188
179
  // Candidate numbers probed against a field's own schema (in a sensible order) so a `.min()/.max()/
189
180
  // .int()/.positive()` constraint is respected — the number sibling of SUBJECT_CANDIDATES. `1` first
190
181
  // keeps the guestbook golden output stable; the rest cover common bounds (lat/lng, non-negative, etc.).
191
- const NUMBER_CANDIDATES: readonly number[] = [1, 0, -1, 2, 10, 100, 0.5, -90, 90, 180, -180, 1000000];
192
182
  function sampleNumber(zt: z.ZodTypeAny): number {
193
- for (const cand of NUMBER_CANDIDATES) if (zt.safeParse(cand).success) return cand;
194
- return 1; // no candidate fits an exotic bound — the whole-payload safeParse / VO validate names the field
183
+ try { return zodSampleNumber(zt); }
184
+ catch { return 1; } // whole-payload validation names an exotic bound
195
185
  }
196
186
 
197
187
  /** The leaf identifier of a full path (`a.b[0].c` → `c`) — the readable `sample-<leaf>` string base. */
@@ -227,7 +217,7 @@ function sampleOfZod(
227
217
  if (zodKind(zt) === "lazy") {
228
218
  if (visited.has(zt)) {
229
219
  throw new Error(
230
- `codegen-proof: ${where} — field '${path}': recursive z.lazy schema — a REQUIRED self-reference makes a finite sample impossible; make the recursive field \`.optional()\` (proof omits it) or wrap it in an array (proof emits \`[]\`), or prove this directive by hand in test/e2e.mts`,
220
+ `codegen-proof: ${where} — field '${path}': recursive z.lazy schema — a REQUIRED self-reference makes a finite sample impossible; make the recursive field \`.optional()\` (proof omits it) or wrap it in an array (proof emits \`[]\`)`,
231
221
  );
232
222
  }
233
223
  const next = new Set(visited);
@@ -308,7 +298,7 @@ function sampleOfZod(
308
298
  }
309
299
  default:
310
300
  throw new Error(
311
- `codegen-proof: ${where} — field '${path}': cannot synthesize a sample for zod shape '${zodKind(zt)}' — reshape it to a sampleable type (string/number/boolean/enum/array/object/nested valueObject), or prove that directive by hand in test/e2e.mts`,
301
+ `codegen-proof: ${where} — field '${path}': cannot synthesize a sample for zod shape '${zodKind(zt)}' — reshape it to a sampleable type (string/number/boolean/enum/array/object/nested valueObject) or teach the generator that value shape`,
312
302
  );
313
303
  }
314
304
  }
@@ -318,12 +308,27 @@ function sampleOfZod(
318
308
  * optional/defaulted fields omitted, required `…At` strings omitted (auto-stamped
319
309
  * by the generated client), everything else sampled by {@link sampleOfZod}.
320
310
  */
321
- export function synthesizePayload(schema: z.ZodTypeAny, where: string, opts?: { voIncludeOptional?: boolean }): SynthesizedPayload {
311
+ export function synthesizePayload(
312
+ schema: z.ZodTypeAny,
313
+ where: string,
314
+ opts?: { voIncludeOptional?: boolean; example?: unknown },
315
+ ): SynthesizedPayload {
322
316
  if (zodKind(schema) !== "object") {
323
317
  throw new Error(`codegen-proof: ${where} payload is not a zod object — the proof can only synthesize object payloads`);
324
318
  }
325
319
  const autoStamped = autoStampFields(schema);
326
320
  const stamped = new Set(autoStamped);
321
+ if (opts?.example !== undefined) {
322
+ const parsed = schema.safeParse(opts.example);
323
+ if (!parsed.success) {
324
+ throw new Error(
325
+ `codegen-proof: ${where} directive example no longer satisfies its payload schema: ${parsed.error.message}`,
326
+ );
327
+ }
328
+ const value = { ...(parsed.data as Record<string, unknown>) };
329
+ for (const field of stamped) delete value[field];
330
+ return { value, autoStamped };
331
+ }
327
332
  const value: Record<string, unknown> = {};
328
333
  for (const [name, raw] of Object.entries(zodObjectShape(schema))) {
329
334
  const f = raw as z.ZodTypeAny;
@@ -335,50 +340,72 @@ export function synthesizePayload(schema: z.ZodTypeAny, where: string, opts?: {
335
340
  return { value, autoStamped };
336
341
  }
337
342
 
338
- // ── shape discovery (which legs THIS law can prove) ───────────────────────────────
339
-
340
- interface ConcurrencyLeg {
341
- readonly directive: Directive<unknown>;
342
- /** The payload field that carries the target instance id (first required string `…Id`). */
343
- readonly idField: string;
344
- /** The AddWins set field the directive adds to (payload array field name === aggregate set field name). */
345
- readonly setField: string;
343
+ /** Prefer a directive's validated cross-field example, then fall back to the
344
+ * ordinary per-field/VO synthesizer. Keeping this in one helper prevents proof,
345
+ * check and precondition legs from silently choosing different samples. */
346
+ export function synthesizeDirectivePayload(
347
+ directive: Directive<any>,
348
+ where: string,
349
+ opts?: { voIncludeOptional?: boolean },
350
+ ): SynthesizedPayload {
351
+ return synthesizePayload(directive.payloadSchema as z.ZodTypeAny, where, {
352
+ ...opts,
353
+ ...(directive.payloadExample === undefined
354
+ ? {}
355
+ : { example: directive.payloadExample }),
356
+ });
346
357
  }
347
358
 
348
- /**
349
- * The AddWins two-writer leg needs the law to have the shape for it: a `.mutates`
350
- * directive on the created aggregate whose payload carries (a) a required string
351
- * `…Id` field (the instance) and (b) an array-of-string field named exactly like
352
- * one of the aggregate's AddWins set fields (the `addToSet` signature). Absent
353
- * that shape, the proof prints a skip note instead of inventing law.
354
- */
355
- function findConcurrencyLeg(
356
- directives: readonly Directive<unknown>[],
357
- agg: AggregateHandle,
358
- ): ConcurrencyLeg | undefined {
359
- const addWinsSets = Object.entries(agg.fields)
360
- .filter(([, f]) => (f as Field).kind === "set" && ((f as Field).driver as { kind?: string }).kind === "AddWins")
361
- .map(([name]) => name);
362
- if (addWinsSets.length === 0) return undefined;
363
- for (const d of directives) {
364
- if (d.marker !== "mutates" || d.aggregateId !== agg.id) continue;
365
- let shape: Record<string, z.ZodTypeAny>;
366
- try {
367
- shape = zodObjectShape(d.payloadSchema as z.ZodTypeAny);
368
- } catch {
369
- continue;
370
- }
371
- const idField = Object.entries(shape).find(
372
- ([name, f]) => name.length > 2 && name.endsWith("Id") && zodKind(f) === "string",
373
- )?.[0];
374
- if (idField === undefined) continue;
375
- const setField = addWinsSets.find((s) => {
376
- const f = shape[s];
377
- return f !== undefined && zodKind(f) === "array" && zodKind(zodArrayElement(f)) === "string";
378
- });
379
- if (setField !== undefined) return { directive: d, idField, setField };
359
+ /** Concrete aggregate references required by a payload. A reference is not sample data: the generated
360
+ * application proof must create/read the target and carry the returned `NomosRef<T>` forward. Shared
361
+ * contracts deliberately stay out of this map because they require a concrete implementing aggregate. */
362
+ function aggregateReferenceFields(schema: z.ZodTypeAny): Readonly<Record<string, string>> {
363
+ if (zodKind(schema) !== "object") return {};
364
+ const out: Record<string, string> = {};
365
+ for (const [field, raw] of Object.entries(zodObjectShape(schema))) {
366
+ const target = idOfMetaOf(raw as z.ZodTypeAny);
367
+ if (target !== undefined && idOfTargetKindOf(raw as z.ZodTypeAny) !== "contract") out[field] = target;
380
368
  }
381
- return undefined;
369
+ return out;
370
+ }
371
+
372
+ /** Reference fields the business payload may legitimately omit. A validated `.example()` may include an
373
+ * optional predecessor even when a fresh journey has not created one yet; the runner drops that one field
374
+ * instead of inventing a string id or blocking the rest of the business action. */
375
+ function optionalAggregateReferenceFields(schema: z.ZodTypeAny): readonly string[] {
376
+ if (zodKind(schema) !== "object") return [];
377
+ return Object.entries(zodObjectShape(schema))
378
+ .filter(([, raw]) => {
379
+ const field = raw as z.ZodTypeAny;
380
+ const kind = zodKind(field);
381
+ return idOfMetaOf(field) !== undefined && (kind === "optional" || kind === "default");
382
+ })
383
+ .map(([field]) => field)
384
+ .sort();
385
+ }
386
+
387
+ const proofTypeIdent = (type: string): string => type.replace(/[^A-Za-z0-9_$]/g, "_");
388
+ const proofRefSlot = (type: string): string => `proof${proofTypeIdent(type)}Ref`;
389
+ const proofRefGetter = (type: string): string => `requireProof${proofTypeIdent(type)}Ref`;
390
+ const proofResultMember = (type: string): string => {
391
+ const bare = type.split(".").filter(Boolean).at(-1) ?? type;
392
+ return lcFirst(camel(bare.replace(/[^A-Za-z0-9_$]+/g, " ")));
393
+ };
394
+
395
+ /** Emit a typed application payload. Ordinary facts remain literals; every `idOf(Aggregate)` field is an
396
+ * expression returning a real `NomosRef<Aggregate>` created earlier in this generated journey. */
397
+ function typedPayloadLiteral(
398
+ payload: Readonly<Record<string, unknown>>,
399
+ referenceFields: Readonly<Record<string, string>>,
400
+ overrides: Readonly<Record<string, string>> = {},
401
+ ): string {
402
+ const keys = new Set([...Object.keys(payload), ...Object.keys(overrides)]);
403
+ const entries = [...keys].map((field) => {
404
+ const expression = overrides[field]
405
+ ?? (referenceFields[field] !== undefined ? `${proofRefGetter(referenceFields[field]!)}()` : JSON.stringify(payload[field]));
406
+ return `${JSON.stringify(field)}: ${expression}`;
407
+ });
408
+ return `{ ${entries.join(", ")} }`;
382
409
  }
383
410
 
384
411
  // ── authority-conformance discovery (the ONE-ENCODER + gate proof — actorless gated offer is impossible) ──
@@ -396,6 +423,8 @@ export interface AuthorityConformanceLeg {
396
423
  readonly relation: string;
397
424
  /** The synthesized payload the proof drives the gated directive with (auto-stamped `…At` omitted). */
398
425
  readonly payload: Record<string, unknown>;
426
+ /** Payload fields which must receive a previously-created typed aggregate reference. */
427
+ readonly referenceFields?: Readonly<Record<string, string>>;
399
428
  /** Required `…At` fields the runtime stamps at dispatch (mirrors the create leg). */
400
429
  readonly autoStamped: readonly string[];
401
430
  /** When the gated directive is a `.creates` whose own id is kernel-minted, the field to mint at runtime. */
@@ -418,7 +447,7 @@ export function discoverAuthorityConformanceLeg(mod: DomainModule): AuthorityCon
418
447
  if (gated === undefined) return undefined;
419
448
  let synth: SynthesizedPayload;
420
449
  try {
421
- synth = synthesizePayload(gated.payloadSchema as z.ZodTypeAny, `${domain}/${gated.id}`);
450
+ synth = synthesizeDirectivePayload(gated, `${domain}/${gated.id}`);
422
451
  } catch {
423
452
  return undefined; // an exotic payload the synthesizer can't sample → no conformance leg (still gated at the kernel)
424
453
  }
@@ -431,270 +460,12 @@ export function discoverAuthorityConformanceLeg(mod: DomainModule): AuthorityCon
431
460
  directiveId: gated.id,
432
461
  relation: gated.requiresRelationGate!.relation,
433
462
  payload,
463
+ ...(() => { const refs = aggregateReferenceFields(gated.payloadSchema as z.ZodTypeAny); return Object.keys(refs).length > 0 ? { referenceFields: refs } : {}; })(),
434
464
  autoStamped: synth.autoStamped,
435
465
  ...(mintField !== undefined ? { mintField } : {}),
436
466
  };
437
467
  }
438
468
 
439
- /**
440
- * THE AUTHORITY-CONFORMANCE LEG (the one-encoder + gate proof). On the real LOCAL holon, with fetch trapped:
441
- * (a) bind the generated client WITH an actor + drive the gated directive. SPY on `holon.offerDirective` to
442
- * capture the (domain, directiveId, payload, opts) the client passes, RE-ENCODE that through the v2
443
- * envelope shape (the SAME `{ v:2, intent, security:{actor} }` the one encoder emits) and DECODE it back
444
- * to assert `security.actor` IS the bound actor — the produced offer envelope carries the principal.
445
- * (b) bind a SECOND client WITHOUT an actor + call the gated directive — assert it THROWS
446
- * MissingOfferAuthority LOCALLY (before any offerDirective/submit fires; the spy stays untouched).
447
- * Emits nothing when the package has no gated directive (a documented no-op note).
448
- */
449
- function authorityConformanceLegLines(
450
- leg: AuthorityConformanceLeg | undefined,
451
- factory: string,
452
- n: () => number,
453
- ): string[] {
454
- if (leg === undefined) {
455
- return [
456
- `// ${n()}. authority-conformance leg: this law has no gated (\`.requires(...)\`) directive, so there is`,
457
- `// nothing to prove about actorless-gated-offer refusal (an un-gated domain authors openly).`,
458
- `console.log("– authority-conformance leg SKIPPED — no .requires(...) directive (add one to prove the one-encoder threads security.actor + an actorless gated offer can't be generated)");`,
459
- ``,
460
- ];
461
- }
462
- const payloadEntries = leg.mintField !== undefined
463
- ? `{ ...${JSON.stringify(leg.payload)}, ${JSON.stringify(leg.mintField)}: await holon.mint("conformance") }`
464
- : JSON.stringify(leg.payload);
465
- return [
466
- `// ${n()}. AUTHORITY CONFORMANCE (THE ONE ENCODER + the gate): \`${leg.domain}/${leg.directiveId}\` is GATED`,
467
- `// (\`.requires("${leg.relation}")\`). (a) WITH an actor the produced offer envelope must carry`,
468
- `// security.actor; (b) WITHOUT one the generated client THROWS MissingOfferAuthority before any submit.`,
469
- `{`,
470
- ` const realFetch2 = globalThis.fetch;`,
471
- ` globalThis.fetch = (() => { throw new Error("OFFLINE PROOF VIOLATED: authority-conformance touched the network"); }) as typeof fetch;`,
472
- ` try {`,
473
- ` // (a) SPY on offerDirective: capture what the generated client passes WITHOUT admitting a synthetic`,
474
- ` // business write, re-encode the v2 envelope, and assert security.actor IS the actor.`,
475
- ` const ACTOR = "user:proof-conformance";`,
476
- ` let captured: { domain: string; directiveId: string; payload: unknown; opts?: { domainHash?: string; actor?: string } } | undefined;`,
477
- ` holon.offerDirective = (domain, directiveId, payload, opts) => {`,
478
- ` captured = { domain, directiveId, payload, opts };`,
479
- ` return Promise.resolve("0000000000000000000000000000000000000000");`,
480
- ` };`,
481
- ` try {`,
482
- ` await ${factory}(holon, { actor: ACTOR }).${leg.directiveId}(${payloadEntries});`,
483
- ` } finally {`,
484
- ` holon.offerDirective = realOffer;`,
485
- ` }`,
486
- ` if (!captured) fail("authority-conformance: the gated directive did not reach holon.offerDirective");`,
487
- ` const actorOnOffer = captured!.opts?.actor;`,
488
- ` if (actorOnOffer !== ACTOR) fail(\`authority-conformance: the offer did not carry the actor (got \${JSON.stringify(actorOnOffer)})\`);`,
489
- ` // Decode the bytes THE ONE ENCODER actually emits from these args (NOT a hand-rolled copy) — so this`,
490
- ` // leg catches encoder DRIFT (a dropped/renamed/whitespace-normalized security.actor), not merely that`,
491
- ` // the actor reached offerDirective. The v2 wire format lives in exactly one place: encodeIntentOfferBytes.`,
492
- ` const decoded = JSON.parse(new TextDecoder().decode(encodeIntentOfferBytes({ domain: captured!.domain, directiveId: captured!.directiveId, payload: captured!.payload, domainHash: captured!.opts?.domainHash, actor: actorOnOffer })));`,
493
- ` if (decoded?.security?.actor !== ACTOR) fail(\`authority-conformance: THE ONE ENCODER dropped security.actor (\${JSON.stringify(decoded?.security)})\`);`,
494
- ` ok(\`authority conformance (a) — \${${JSON.stringify(`${leg.domain}/${leg.directiveId}`)}} authored WITH an actor carries security.actor through THE ONE ENCODER\`);`,
495
- ``,
496
- ` // (b) the SAME directive with NO actor: the generated client refuses to BUILD the offer — it throws`,
497
- ` // MissingOfferAuthority locally, BEFORE any submit (an actorless gated offer is impossible to make).`,
498
- ` let threw: Error | undefined;`,
499
- ` try {`,
500
- ` await ${factory}(holon).${leg.directiveId}(${payloadEntries});`,
501
- ` } catch (e) { threw = e as Error; }`,
502
- ` if (threw === undefined) fail("authority-conformance: the gated directive with NO actor did NOT throw — an actorless gated offer must be impossible to generate");`,
503
- ` if (threw.name !== "MissingOfferAuthority") fail(\`authority-conformance: expected MissingOfferAuthority, got \${threw.name}: \${threw.message}\`);`,
504
- ` ok(\`authority conformance (b) — \${${JSON.stringify(`${leg.domain}/${leg.directiveId}`)}} with NO actor throws MissingOfferAuthority before any submit (gated offer impossible to generate)\`);`,
505
- ` } finally {`,
506
- ` globalThis.fetch = realFetch2;`,
507
- ` }`,
508
- `}`,
509
- ``,
510
- ];
511
- }
512
-
513
- /**
514
- * THE RELATION-BOOTSTRAP LEG (the seed-then-prove POSITIVE — complements the negative conformance leg). On the
515
- * LOCAL holon with fetch trapped: (1) dispatch the GRANT directive under the proof actor (its subject fields
516
- * overwritten to the actor so the relation seats ON it), then (2) dispatch the GATED directive under the SAME
517
- * actor and assert it SUCCEEDS — proving that once relation R is granted, an actor holding R authors the gated
518
- * write (the exact loop the negative leg can't cover). Emits nothing when no granter is discoverable.
519
- */
520
- /** The canonical set of relation-bootstrap legs for a domain (co2 #2 multi-target): the `relationBootstraps[]`
521
- * array when present, else the singular `relationBootstrap` as a one-element list, else empty. */
522
- function allRelationBootstrapLegs(pl: ProofLegs): readonly RelationBootstrapLeg[] {
523
- return pl.relationBootstraps ?? (pl.relationBootstrap !== undefined ? [pl.relationBootstrap] : []);
524
- }
525
-
526
- /** Emit the seed-then-prove lines for EVERY discovered gated-create authority leg (co2 #2), or — when the
527
- * domain has a gated create but NO seedable path — the single loud gap diagnostic. */
528
- function relationSeedLegsLines(pl: ProofLegs, factory: string, n: () => number, gap: string | undefined): string[] {
529
- const legs = allRelationBootstrapLegs(pl);
530
- if (legs.length === 0) return relationSeedLegLines(undefined, factory, n, gap);
531
- return legs.flatMap((leg) => relationSeedLegLines(leg, factory, n, undefined));
532
- }
533
-
534
- function relationSeedLegLines(
535
- leg: RelationBootstrapLeg | undefined,
536
- factory: string,
537
- n: () => number,
538
- diagnostic?: string,
539
- ): string[] {
540
- if (leg === undefined) {
541
- if (diagnostic === undefined) return [];
542
- // A gated directive exists but no authority could be seeded — say EXACTLY why (a useful failure, not a
543
- // silent skip). The gate is still proven negatively by the conformance leg above.
544
- return [
545
- `// ${n()}. relation-bootstrap leg: this law has a gated directive the proof COULD NOT seed authority for.`,
546
- `console.log(${JSON.stringify(`– relation-bootstrap leg SKIPPED — ${diagnostic}`)});`,
547
- ``,
548
- ];
549
- }
550
- const ACTOR = `"user:proof-conformance"`;
551
- const BARE_ACTOR = `"proof-conformance"`; // the uid without the `user:` prefix — for WRAPPED subject fields
552
- const speculative = leg.seedSpeculative === true;
553
- // A payload literal with subject/founder-conventional fields (+ the routed set) overwritten to the actor —
554
- // so a seat lands ON the actor AND every write-once/author-binding/founder-binding invariant holds. A WRAPPED
555
- // subject field (the plan lifts a bare uid into `user:${field}`) gets the BARE uid — else the re-wrap yields
556
- // a double-prefixed `user:user:<uid>` the gate never stamped.
557
- const actorSeatLit = (payload: Record<string, unknown>, routed: readonly string[], wrapped: readonly string[] = []): string => {
558
- const overwrite = new Set<string>(routed);
559
- const wrappedSet = new Set<string>(wrapped);
560
- const entries = Object.entries(payload).map(([k, v]) =>
561
- wrappedSet.has(k)
562
- ? `${JSON.stringify(k)}: ${BARE_ACTOR}`
563
- : overwrite.has(k) || /^(subject|principal|grantedBy|grantee|member|user|owner|founder)$/i.test(k)
564
- ? `${JSON.stringify(k)}: ${ACTOR}`
565
- : `${JSON.stringify(k)}: ${JSON.stringify(v)}`,
566
- );
567
- return `{ ${entries.join(", ")} }`;
568
- };
569
- const grantPayloadLit = actorSeatLit(leg.grantPayload, [...leg.grantSubjectFields, ...leg.grantGrantedByFields], leg.grantSubjectWrappedFields ?? []);
570
- // The PREREQUISITE-SEED CHAIN dispatches (each as the actor = founder) BEFORE the grant.
571
- const prereqLines = (leg.prerequisiteSeeds ?? []).flatMap((seed) => [
572
- ` // prerequisite: ${leg.domain}/${seed.directiveId} establishes the state the grant's invariant reads (as founder = ACTOR).`,
573
- ` await ${factory}(holon, { actor: ACTOR }).${seed.directiveId}(${actorSeatLit(seed.payload, [])});`,
574
- ` ok(\`relation bootstrap (prerequisite) — ${leg.domain}/${seed.directiveId} established (as founder \${ACTOR}) before the grant\`);`,
575
- ]);
576
- const gatedPayloadLit = leg.gatedMintField !== undefined && leg.gatedAggregateId !== undefined
577
- ? `{ ...${JSON.stringify(leg.gatedPayload)}, ${JSON.stringify(leg.gatedMintField)}: await holon.mint(${JSON.stringify(leg.gatedAggregateId)}) }`
578
- : JSON.stringify(leg.gatedPayload);
579
- const computedNote = leg.grantedRelation !== leg.relation && !speculative
580
- ? ` — a COMPUTED gate: granting "${leg.grantedRelation}" makes the actor satisfy "${leg.relation}" via the rewrite`
581
- : ``;
582
-
583
- if (leg.bornContext !== undefined) {
584
- // LAYER 4 — THE BORN-DOMAIN GENESIS-AUTHORITY PATH (co2 home). R is established ONLY by the birth genesis
585
- // (e.g. birthHome → seedHomeCreator seats creator), and the seed carries an owner-binding PREREQUISITE a
586
- // standalone re-seed can't satisfy. This leg is proven by `githolon proof` (offline, on the local wasm):
587
- // the runner BIRTHS the workspace as the proof actor (= owner), then dispatches the gated directive INSIDE
588
- // the born workspace as that owner, asserting ADMITTED at the real kernel gate (a refusal degrades to a
589
- // diagnostic — never a false green). The LIVE `--live` lane proves the underlying birth via the child-birth
590
- // leg; the gated-directive-in-born-context proof is the offline runner's (birthing a throwaway home per
591
- // gated directive live would leave orphan workspaces).
592
- const bc = leg.bornContext;
593
- return [
594
- `// ${n()}. RELATION BOOTSTRAP — LAYER 4 (born-domain genesis authority): \`${leg.domain}/${leg.gatedDirectiveId}\``,
595
- `// is GATED (\`.requires("${leg.relation}")\`), established ONLY by the birth genesis (\`${bc.birthDirectiveId}\` →`,
596
- `// \`${bc.seatsViaDirectiveId}\` seats "${leg.relation}") — NOT a standalone-replayable seed (its owner-binding`,
597
- `// prerequisite would false-fail). Proven by \`githolon proof\` (offline): birth the workspace as the owner,`,
598
- `// then dispatch \`${leg.gatedDirectiveId}\` INSIDE the born workspace as that owner (real-gate admitted).`,
599
- `console.log("– relation-bootstrap leg (born-context) — \`${leg.domain}/${leg.gatedDirectiveId}\` .requires(\\"${leg.relation}\\") is proven in the BORN workspace by \`githolon proof\` (offline); the birth is proven live by the child-birth leg");`,
600
- ``,
601
- ];
602
- }
603
-
604
- if (speculative) {
605
- // LAYER 3 (seed-path replay). The gate relation is reachable only through ttu/intersection/exclusion — no
606
- // directly-grantable base. We REPLAY the domain's declared seed and let the REAL GATE arbitrate: if the
607
- // gated write is ADMITTED, it is a green positive leg; if REFUSED, it is a DIAGNOSTIC (never a false
608
- // green) — the discovered seed was not the authority path. Step (2) is wrapped so a refusal degrades.
609
- const seats = (leg.seedWritesRelations ?? [leg.grantedRelation]).join(", ");
610
- return [
611
- `// ${n()}. RELATION BOOTSTRAP — LAYER 3 (seed-path replay): \`${leg.domain}/${leg.gatedDirectiveId}\` is GATED`,
612
- `// (\`.requires("${leg.relation}")\`), reachable only via ttu/intersection (no directly-grantable base).`,
613
- `// REPLAY the declared seed \`${leg.domain}/${leg.grantDirectiveId}\` (seats [${seats}]) on the actor, then let`,
614
- `// the REAL gate decide: admitted ⇒ proven; refused ⇒ diagnostic (a speculative seed never false-greens).`,
615
- `{`,
616
- ` const realFetch3 = globalThis.fetch;`,
617
- ` globalThis.fetch = (() => { throw new Error("OFFLINE PROOF VIOLATED: relation-bootstrap touched the network"); }) as typeof fetch;`,
618
- ` try {`,
619
- ` const ACTOR = ${ACTOR};`,
620
- ` let seedReplayed = false;`,
621
- ` try {`,
622
- ` await ${factory}(holon, { actor: ACTOR }).${leg.grantDirectiveId}(${grantPayloadLit});`,
623
- ` seedReplayed = true;`,
624
- ` } catch (e) {`,
625
- ` console.log(\`– relation-bootstrap leg SKIPPED (layer-3 seed-path) — the declared seed ${leg.domain}/${leg.grantDirectiveId} could not be replayed (\${(e as Error)?.message ?? e}); gate ${leg.gatedDirectiveId} stays proven negatively\`);`,
626
- ` }`,
627
- ` if (seedReplayed) {`,
628
- ` try {`,
629
- ` await ${factory}(holon, { actor: ACTOR }).${leg.gatedDirectiveId}(${gatedPayloadLit});`,
630
- ` ok(\`relation bootstrap (seed-path) — ${leg.domain}/${leg.gatedDirectiveId} authored after replaying the declared seed ${leg.grantDirectiveId} (the REAL gate confirmed it establishes authority for "${leg.relation}")\`);`,
631
- ` } catch (e) {`,
632
- ` // ANTI-FALSE-GREEN: the real gate REFUSED — the discovered seed was not the authority path. Do NOT`,
633
- ` // assert a passing leg; emit a diagnostic (the conformance leg still proves the gate has teeth).`,
634
- ` console.log(\`– relation-bootstrap leg SKIPPED (layer-3 seed-path) — replaying ${leg.grantDirectiveId} did NOT authorize ${leg.gatedDirectiveId} .requires("${leg.relation}") on the real gate (\${(e as Error)?.message ?? e}); no seed-path is provable\`);`,
635
- ` }`,
636
- ` }`,
637
- ` } finally {`,
638
- ` globalThis.fetch = realFetch3;`,
639
- ` }`,
640
- `}`,
641
- ``,
642
- ];
643
- }
644
-
645
- const prereqNote = (leg.prerequisiteSeeds ?? []).length > 0
646
- ? ` The grant needs prerequisite seed(s) [${(leg.prerequisiteSeeds ?? []).map((s) => s.directiveId).join(", ")}] run first (as the actor = founder).`
647
- : ``;
648
- // TARGET PRECONDITION SETUPS (co2 #3): the gated establisher(s) for the target's `.requiresExisting`/`.where`
649
- // parent — dispatched AFTER the grant (the actor now holds the relation), BEFORE the target, so its declared
650
- // predicate (e.g. `lifecycle == "active"`) holds against the REAL parent, not a shape-only shell.
651
- const precondLines = (leg.preconditionSetups ?? []).flatMap((s) => {
652
- const lit = s.autoStamped.length > 0
653
- ? `(() => { const p: Record<string, unknown> = { ...${JSON.stringify(s.payload)} }; ${s.autoStamped.map((f) => `p[${JSON.stringify(f)}] = new Date().toISOString();`).join(" ")} return p; })()`
654
- : JSON.stringify(s.payload);
655
- return [
656
- ` // precondition: dispatch the REAL ${leg.domain}/${s.directiveId} (gated by "${s.requiresRelation ?? leg.relation}", already seated) so the target's declared predicate holds against real state.`,
657
- ` await ${factory}(holon, { actor: ACTOR }).${s.directiveId}(${lit});`,
658
- ` ok(\`relation bootstrap (precondition) — ${leg.domain}/${s.directiveId} established before ${leg.gatedDirectiveId} (real parent state, not a shell)\`);`,
659
- ];
660
- });
661
- return [
662
- `// ${n()}. RELATION BOOTSTRAP (seed-then-prove the POSITIVE): \`${leg.domain}/${leg.gatedDirectiveId}\` is GATED`,
663
- `// (\`.requires("${leg.relation}")\`). \`${leg.domain}/${leg.grantDirectiveId}\` GRANTS "${leg.grantedRelation}" (${leg.via})${computedNote}.${prereqNote}`,
664
- `// Grant it to the proof actor, THEN prove the gated write SUCCEEDS under that actor (what the negative`,
665
- `// conformance leg above can't cover — a seeded holder authoring a gated write).`,
666
- `{`,
667
- ` const realFetch3 = globalThis.fetch;`,
668
- ` globalThis.fetch = (() => { throw new Error("OFFLINE PROOF VIOLATED: relation-bootstrap touched the network"); }) as typeof fetch;`,
669
- ` try {`,
670
- ` const ACTOR = ${ACTOR};`,
671
- ...prereqLines,
672
- ` // (1) grant "${leg.grantedRelation}" to ACTOR (the grant folds a writeTuple; subject seated on ACTOR).`,
673
- ` await ${factory}(holon, { actor: ACTOR }).${leg.grantDirectiveId}(${grantPayloadLit});`,
674
- ` ok(\`relation bootstrap (grant) — ${leg.domain}/${leg.grantDirectiveId} granted "${leg.grantedRelation}" to \${ACTOR}${leg.grantedRelation !== leg.relation ? ` (⇒ satisfies "${leg.relation}" via rewrite)` : ``}\`);`,
675
- ...precondLines,
676
- ` // (2) the GATED write now SUCCEEDS under the seeded actor (holds "${leg.relation}"${leg.grantedRelation !== leg.relation ? ` via "${leg.grantedRelation}"` : ``}).`,
677
- ` await ${factory}(holon, { actor: ACTOR }).${leg.gatedDirectiveId}(${gatedPayloadLit});`,
678
- ` ok(\`relation bootstrap (prove) — ${leg.domain}/${leg.gatedDirectiveId} authored under the seeded holder of "${leg.relation}" (gated write SUCCEEDS once granted)\`);`,
679
- ` } finally {`,
680
- ` globalThis.fetch = realFetch3;`,
681
- ` }`,
682
- `}`,
683
- ``,
684
- ];
685
- }
686
-
687
- // ── relation-bootstrap discovery (seed the gate: grant relation R, then prove a .requires(R) write SUCCEEDS) ──
688
- //
689
- // The NEGATIVE conformance leg above proves an ACTORLESS gated offer can't be generated. This POSITIVE leg
690
- // proves the other half: with the relation GRANTED, an actor that holds it authors the gated write SUCCESS-
691
- // fully. It needs a sibling directive that ESTABLISHES the relation (folds a granting `writeTuple`). We find
692
- // it two ways: FIRST a `.grants(R)` producer marker (the static, unambiguous lane — symmetric to `.requires`);
693
- // ELSE plan-probe each sibling for a `writeTuple`/relation-tuple op whose `relation === R` (inference).
694
-
695
- /** A discovered RELATION-BOOTSTRAP leg: a gated (`.requires(R)`) directive plus the sibling directive that
696
- * GRANTS R. The proof dispatches the grant FIRST (its subject/grantedBy set to the seeded proof actor), then
697
- * dispatches the gated directive under that actor and asserts it SUCCEEDS — the seed-then-prove positive. */
698
469
  export interface RelationBootstrapLeg {
699
470
  /** The gated directive's domain. */
700
471
  readonly domain: string;
@@ -709,16 +480,31 @@ export interface RelationBootstrapLeg {
709
480
  readonly grantedRelation: string;
710
481
  /** The synthesized gated-directive payload (auto-stamped `…At` omitted; mintField removed). */
711
482
  readonly gatedPayload: Record<string, unknown>;
483
+ readonly gatedReferenceFields?: Readonly<Record<string, string>>;
484
+ readonly gatedOptionalReferenceFields?: readonly string[];
712
485
  readonly gatedAutoStamped: readonly string[];
486
+ /** Referential marker of the business consequence; distinguishes a fresh create from an idempotent ensure. */
487
+ readonly gatedMarker?: ReferentialMarker;
488
+ /** Application-owned identity field. The generated runner removes it from tenant input, binds it to the
489
+ * connected participant, and authors this action as that same participant. */
490
+ readonly gatedPrincipalField?: string;
713
491
  /** When the gated directive's own id is kernel-minted, the field to mint at runtime. */
714
492
  readonly gatedMintField?: string;
715
- /** The gated create's aggregate id (the mint's type tag) — present when `gatedMintField` is. */
493
+ /** The gated create's aggregate id. Present for every `.creates` target so its returned typed reference
494
+ * can feed later generated business actions; also supplies the mint type tag when applicable. */
716
495
  readonly gatedAggregateId?: string;
496
+ /** Every aggregate type this business action writes, including fan-out/secondary mutations. Used only by
497
+ * the generated proof scheduler to replay the target's dependency slice instead of the whole workspace. */
498
+ readonly gatedWrittenAggregates?: readonly string[];
499
+ /** Aggregate types read by invariants guarding this action. These are state dependencies even when no
500
+ * payload field is a direct ref (for example a composite-key catalogue snapshot). */
501
+ readonly gatedReadAggregates?: readonly string[];
717
502
  /** The granting directive id (the sibling that folds the granting `writeTuple`). */
718
503
  readonly grantDirectiveId: string;
719
504
  /** The synthesized grant payload (auto-stamped `…At` omitted). The SUBJECT fields (below) are overwritten
720
505
  * at runtime with the seeded proof actor so the grant seats authority ON that actor. */
721
506
  readonly grantPayload: Record<string, unknown>;
507
+ readonly grantReferenceFields?: Readonly<Record<string, string>>;
722
508
  readonly grantAutoStamped: readonly string[];
723
509
  /** The grant-payload field(s) whose value the plan routed into the tuple SUBJECT — set to the proof actor
724
510
  * at dispatch so the granted relation lands on the actor the gated write runs as. */
@@ -736,7 +522,7 @@ export interface RelationBootstrapLeg {
736
522
  * the REAL KERNEL GATE is the arbiter of whether it authorizes the write), or `"born-context"` (LAYER 4:
737
523
  * R is established by the domain's BIRTH GENESIS — the gated directive is proven INSIDE the born workspace
738
524
  * as the owner; see {@link BornContextAuthority}). Audit + runner semantics. */
739
- readonly via: "marker" | "inferred" | "computed-base" | "seed-path" | "born-context";
525
+ readonly via: "marker" | "inferred" | "computed-base" | "seed-path" | "born-context" | "unrestricted";
740
526
  /** LAYER-3 ANTI-FALSE-GREEN FLAG. `true` ⇒ this is a SPECULATIVE seed-path leg: codegen could NOT prove
741
527
  * (via rewrite resolution) that replaying `grantDirectiveId` authorizes the gated write — it discovered a
742
528
  * seed that writes relation tuples and is DEFERRING to the real kernel gate. The runner replays the seed,
@@ -766,15 +552,33 @@ export interface RelationBootstrapLeg {
766
552
  * (each as the proof actor = founder, so their own write-once/author-binding invariants hold) BEFORE the
767
553
  * grant — then the grant + the gated write succeed. A non-birth analog of {@link BornContextAuthority}. */
768
554
  readonly prerequisiteSeeds?: readonly PrerequisiteSeed[];
769
- /** THE TARGET'S OWN PRECONDITION SETUPS (co2 #3). The gated create carries a `.requiresExisting`/`.where`
555
+ /** THE TARGET'S OWN PRECONDITION SETUPS (co2 #3). The gated action carries a `.requiresExisting`/`.where`
770
556
  * precondition reading ANOTHER aggregate by a payload-id field with a predicate (e.g. `createClassification
771
557
  * Draft` needs a `ClassificationScheme` at `p.schemeId` with `lifecycle == "active"`). The establishing
772
- * create (`createClassificationScheme`) is itself GATED by the SAME relation this leg already seats, and —
773
- * because the id field synthesizes deterministically to `"sample-<field>"` in BOTH — it writes the parent
774
- * at the exact id the target reads, WITH the real lifecycle its plan sets. The runner dispatches these AFTER
775
- * the grant (the actor holds the relation) and BEFORE the target, satisfying its declared predicate — not a
776
- * shape-only shell. Dependency-ordered. */
558
+ * create (`createClassificationScheme`) is itself GATED by the SAME relation this leg already seats. The
559
+ * runner dispatches it AFTER the grant and BEFORE the target, then replaces the target's typed-reference
560
+ * field with the real record id it established. Source and target payload field names need not coincide. */
777
561
  readonly preconditionSetups?: readonly PreconditionSetup[];
562
+ /** A dynamic cross-workspace business premise. The generated fixture privately builds the source's own
563
+ * business history through its published actions, serves the declared query, seats the target law's
564
+ * hidden trust record and carries the signed answer. Tenant examples still contain only the target
565
+ * business action. */
566
+ readonly sourceTrust?: SourceTrustProofSetup;
567
+ }
568
+
569
+ export interface SourceTrustProofSetup {
570
+ readonly viaDirectiveId: string;
571
+ readonly fromPayload: string;
572
+ readonly queryId: string;
573
+ readonly queryArgs: Readonly<Record<string, string>>;
574
+ readonly copy: Readonly<Record<string, string>>;
575
+ readonly genesisField: string;
576
+ readonly keyHashesField: string;
577
+ readonly sourceDomain: string;
578
+ readonly sourceAggregateId: string;
579
+ readonly sourceQueryKey: readonly string[];
580
+ /** Smallest generated business prefix that establishes a row returned by the source query. */
581
+ readonly sourceJourney: readonly RelationBootstrapLeg[];
778
582
  }
779
583
 
780
584
  /** One target-precondition setup (co2 #3): a REAL create of a parent aggregate the gated target's precondition
@@ -782,9 +586,14 @@ export interface RelationBootstrapLeg {
782
586
  export interface PreconditionSetup {
783
587
  /** The establishing create directive id (e.g. `createClassificationScheme`). */
784
588
  readonly directiveId: string;
785
- /** Its synthesized payload — the id field (`.withId`) is RETAINED and matches the target's (both
786
- * `"sample-<field>"`), so it writes the parent at the exact instance the target's precondition reads. */
589
+ /** Its synthesized payload. The runner observes the real record it establishes and binds the target's
590
+ * typed-reference field to that id; no shared synthesized SQL-style key is required. */
787
591
  readonly payload: Record<string, unknown>;
592
+ /** Aggregate this setup establishes. A capped singleton may already exist because birth genesis created it;
593
+ * the runner then reuses that state instead of replaying one-time ceremony. */
594
+ readonly aggregateType: string;
595
+ readonly reuseIfPresent?: boolean;
596
+ readonly referenceFields?: Readonly<Record<string, string>>;
788
597
  readonly autoStamped: readonly string[];
789
598
  /** The relation the establisher is gated by (informational; the runner dispatches it as the actor already
790
599
  * holding this leg's seated relation — the common case is the SAME relation as the target). */
@@ -799,6 +608,7 @@ export interface PrerequisiteSeed {
799
608
  /** The synthesized payload; founder/subject-conventional fields are set to the proof actor at dispatch so
800
609
  * the seed's own write-once/author-binding invariants pass (founder == the seeding actor). */
801
610
  readonly payload: Record<string, unknown>;
611
+ readonly referenceFields?: Readonly<Record<string, string>>;
802
612
  readonly autoStamped: readonly string[];
803
613
  }
804
614
 
@@ -865,7 +675,7 @@ export function probePlanOps(
865
675
  ): { ops: FieldOp[]; synth: SynthesizedPayload; probePayload: Record<string, unknown> } | undefined {
866
676
  let synth: SynthesizedPayload;
867
677
  try {
868
- synth = synthesizePayload(dir.payloadSchema as z.ZodTypeAny, where);
678
+ synth = synthesizeDirectivePayload(dir, where);
869
679
  } catch {
870
680
  return undefined;
871
681
  }
@@ -1130,7 +940,7 @@ function probeBirthGenesis(
1130
940
  ): { chain: Array<{ domain?: string; directiveId?: string; actor?: unknown }>; synth: SynthesizedPayload } | undefined {
1131
941
  let synth: SynthesizedPayload;
1132
942
  try {
1133
- synth = synthesizePayload(birthDir.payloadSchema as z.ZodTypeAny, where);
943
+ synth = synthesizeDirectivePayload(birthDir, where);
1134
944
  } catch {
1135
945
  return undefined;
1136
946
  }
@@ -1175,8 +985,23 @@ export function discoverBornContextAuthority(
1175
985
  if (probed === undefined) continue;
1176
986
  const { chain, synth } = probed;
1177
987
  // Find the genesis step (in THIS domain) whose directive writeTuples `relation` — that step seats R.
988
+ // Business birth carries the declared founder policy as private metadata, so proof discovery does not
989
+ // have to reverse-engineer a role from synthesized tuple payloads (which can be deliberately opaque).
1178
990
  let seatsVia: string | undefined;
991
+ const businessPolicy = (bd as unknown as {
992
+ businessBirth?: { founderRoles?: readonly string[] };
993
+ }).businessBirth;
994
+ if (businessPolicy?.founderRoles?.includes(relation) === true) {
995
+ seatsVia = chain
996
+ .filter((step) => step?.domain === domain && typeof step.directiveId === "string")
997
+ .map((step) => step.directiveId as string)
998
+ .find((directiveId) =>
999
+ (byId.get(directiveId) as { businessBirthInternal?: unknown } | undefined)
1000
+ ?.businessBirthInternal === true,
1001
+ );
1002
+ }
1179
1003
  for (const step of chain) {
1004
+ if (seatsVia !== undefined) break;
1180
1005
  if (step === null || typeof step !== "object" || step.domain !== domain || typeof step.directiveId !== "string") continue;
1181
1006
  const stepDir = byId.get(step.directiveId);
1182
1007
  if (stepDir === undefined) continue;
@@ -1243,16 +1068,36 @@ function directiveHasPrerequisiteInvariant(mod: DomainModule, directiveId: strin
1243
1068
  /** The AGGREGATE TYPES a directive's plan writes (set/ensure/create ops) — used to find the sibling seed that
1244
1069
  * establishes the state a prerequisite invariant reads. `[]` ⇒ not probeable / writes nothing. */
1245
1070
  function probeWritesAggregateTypes(dir: Directive<unknown>, where: string): Set<string> {
1071
+ const out = new Set<string>([dir.aggregateId]);
1072
+ for (const output of dir.secondaryOutputs ?? []) out.add(output.aggregateId);
1246
1073
  const probed = probePlanOps(dir, where);
1074
+ for (const o of probed?.ops ?? []) if (typeof o.aggregateType === "string" && o.aggregateType.length > 0) out.add(o.aggregateType);
1075
+ return out;
1076
+ }
1077
+
1078
+ /** Aggregate types this directive can make exist when they were absent. A mutation may write every field of
1079
+ * its target but cannot establish it; confusing those ideas made proof generation omit the prerequisite create
1080
+ * for typed `requiresExisting` mutations. Declared and probed secondary outputs keep intent fan-out visible. */
1081
+ function probeEstablishesAggregateTypes(dir: Directive<unknown>, where: string): Set<string> {
1247
1082
  const out = new Set<string>();
1248
- if (probed === undefined) return out;
1249
- for (const o of probed.ops) if (typeof o.aggregateType === "string" && o.aggregateType.length > 0) out.add(o.aggregateType);
1083
+ if (dir.marker === "creates" || dir.marker === "ensures") out.add(dir.aggregateId);
1084
+ for (const output of dir.secondaryOutputs ?? []) {
1085
+ if (output.marker === "creates" || output.marker === "ensures") out.add(output.aggregateId);
1086
+ }
1087
+ const probed = probePlanOps(dir, where);
1088
+ for (const op of probed?.ops ?? []) {
1089
+ const marker = (op as { marker?: string }).marker;
1090
+ if ((marker === "creates" || marker === "ensures") && typeof op.aggregateType === "string" && op.aggregateType.length > 0) {
1091
+ out.add(op.aggregateType);
1092
+ }
1093
+ }
1250
1094
  return out;
1251
1095
  }
1252
1096
 
1253
1097
  /** The aggregate TYPES a workspaceInvariant's declared reads depend on — the state its predicate needs to be
1254
- * established first. A `pre:`-prefixed read id is a PRE-apply self-check (write-once), NOT a cross-step
1255
- * dependency, so it's excluded. Best-effort: an un-callable reads fn yields none. */
1098
+ * established first. `pre:` says which SNAPSHOT the gate reads, not whether the dependency is self- or
1099
+ * cross-aggregate; callers compare these types with the directive's own writes to distinguish those cases.
1100
+ * Best-effort: an un-callable reads fn yields none. */
1256
1101
  function invariantReadAggregateTypes(inv: { reads: (ctx: { intent: Record<string, unknown>; principal?: string }) => Array<{ aggregate: string; id: string }> }): Set<string> {
1257
1102
  const out = new Set<string>();
1258
1103
  let refs: Array<{ aggregate: string; id: string }>;
@@ -1263,7 +1108,6 @@ function invariantReadAggregateTypes(inv: { reads: (ctx: { intent: Record<string
1263
1108
  }
1264
1109
  for (const r of refs) {
1265
1110
  if (r === null || typeof r !== "object") continue;
1266
- if (typeof r.id === "string" && r.id.startsWith("pre:")) continue; // write-once self-check, not a dependency
1267
1111
  if (typeof r.aggregate === "string" && r.aggregate.length > 0) out.add(r.aggregate);
1268
1112
  }
1269
1113
  return out;
@@ -1289,7 +1133,7 @@ export function discoverPrerequisiteChain(mod: DomainModule, granter: Directive<
1289
1133
  const synthSeed = (dir: Directive<unknown>): PrerequisiteSeed | undefined => {
1290
1134
  let synth: SynthesizedPayload;
1291
1135
  try {
1292
- synth = synthesizePayload(dir.payloadSchema as z.ZodTypeAny, `${domain}/${dir.id}`);
1136
+ synth = synthesizeDirectivePayload(dir, `${domain}/${dir.id}`);
1293
1137
  } catch {
1294
1138
  return undefined;
1295
1139
  }
@@ -1297,7 +1141,13 @@ export function discoverPrerequisiteChain(mod: DomainModule, granter: Directive<
1297
1141
  const mintField = agg !== undefined ? mintedCreateField(dir, agg) : undefined;
1298
1142
  const payload: Record<string, unknown> = { ...synth.value };
1299
1143
  if (mintField !== undefined) delete payload[mintField];
1300
- return { directiveId: dir.id, payload, autoStamped: synth.autoStamped };
1144
+ const referenceFields = aggregateReferenceFields(dir.payloadSchema as z.ZodTypeAny);
1145
+ return {
1146
+ directiveId: dir.id,
1147
+ payload,
1148
+ ...(Object.keys(referenceFields).length > 0 ? { referenceFields } : {}),
1149
+ autoStamped: synth.autoStamped,
1150
+ };
1301
1151
  };
1302
1152
  // Resolve `dir`'s prerequisites (a sibling seed per cross-step aggregate dependency), recursively. Returns
1303
1153
  // false when ANY prerequisite has no establishing sibling seed (the whole chain is then unsatisfiable).
@@ -1330,54 +1180,87 @@ export function discoverPrerequisiteChain(mod: DomainModule, granter: Directive<
1330
1180
  }
1331
1181
 
1332
1182
  /**
1333
- * TARGET-PRECONDITION SETUPS (co2 #3). A gated create may carry a `.requiresExisting`/`.where` precondition
1183
+ * TARGET-PRECONDITION SETUPS (co2 #3). A gated action may carry a `.requiresExisting`/`.where` precondition
1334
1184
  * reading a PARENT aggregate by a payload-id field with a predicate (e.g. `createClassificationDraft` needs a
1335
1185
  * `ClassificationScheme` at `p.schemeId` with `lifecycle == "active"`). The proof must ESTABLISH that parent
1336
1186
  * with REAL state — a shape-only shell fails the predicate (`classification-scheme-retired`). For each such
1337
1187
  * precondition we find the parent's own create directive (`createClassificationScheme`, itself gated) and
1338
- * record it as a setup dispatched AFTER the grant / BEFORE the target: because the parent's id field
1339
- * synthesizes to the SAME `"sample-<field>"` the target reads, it writes the parent at the exact instance,
1340
- * WITH the lifecycle its real plan sets. Skips a self-precondition (the target's own aggregate) and any parent
1341
- * with no discoverable create (the predicate then arbitrates at the real gate — never a false green).
1188
+ * record it as a setup dispatched AFTER the grant / BEFORE the target. The runner binds the target's typed
1189
+ * reference to the record this setup really established, so differently named or derived keys are fine. Skip
1190
+ * only a self-precondition the target actually establishes; a mutation still needs a prior create/ensure.
1342
1191
  */
1343
1192
  function discoverPreconditionSetups(mod: DomainModule, gated: Directive<unknown>): PreconditionSetup[] {
1344
1193
  const domain = mod.domain ?? mod.name;
1345
1194
  const invariants = (mod.workspaceInvariants ?? []) as Array<WorkspaceInvariantDecl>;
1346
1195
  const directives = mod.directives as Directive<unknown>[];
1347
- const gatedWrites = probeWritesAggregateTypes(gated, `${domain}/${gated.id}`);
1196
+ let gatedSample: Record<string, unknown> = {};
1197
+ try {
1198
+ gatedSample = { ...synthesizeDirectivePayload(gated, `${domain}/${gated.id}`).value };
1199
+ } catch {
1200
+ // The caller will already diagnose an unsampleable public action. Keep prerequisite discovery best-effort.
1201
+ }
1348
1202
  const setups: PreconditionSetup[] = [];
1349
1203
  const seen = new Set<string>();
1350
1204
  for (const inv of invariants) {
1351
1205
  if (inv.on !== gated.id) continue; // preconditions on THIS target only
1206
+ // An absence/write-once invariant deliberately accepts an empty pre-state; creating a sibling record
1207
+ // would make that action fail. Only seek an establisher when the invariant itself rejects the empty
1208
+ // snapshot, which is the semantic definition of an existing-state prerequisite.
1209
+ let refs: Array<{ name?: string; aggregate: string }> = [];
1210
+ try {
1211
+ refs = inv.reads({ intent: gatedSample, principal: "user:proof-participant", principalVerified: true });
1212
+ const empty = Object.fromEntries(refs.map((ref) => [ref.name ?? ref.aggregate, undefined]));
1213
+ const verdict = inv.assert(empty as never, {
1214
+ intent: gatedSample,
1215
+ principal: "user:proof-participant",
1216
+ principalVerified: true,
1217
+ reads: [],
1218
+ });
1219
+ if ("accept" in verdict && verdict.accept === true) continue;
1220
+ } catch {
1221
+ // A predicate which cannot evaluate an absent snapshot is conservatively an existing-state dependency.
1222
+ }
1352
1223
  for (const aggType of invariantReadAggregateTypes(inv)) {
1353
- if (gatedWrites.has(aggType)) continue; // self-precondition — the target establishes it in its own apply
1354
1224
  // The parent's own ESTABLISHER — a directive that WRITES `aggType` at a DETERMINISTIC (dev-chosen) key:
1355
1225
  // an `.ensures(<aggType>)` keyed upsert (the kernel's sanctioned non-minted-id lane), or a create-once
1356
- // (`.withId`). Its id field synthesizes to the SAME `"sample-<field>"` the target's precondition reads,
1357
- // so it writes the parent at the exact instance WITH the state its real plan sets. A truly MINTED
1358
- // `.creates` (kernel `<Type>_<uuid>`) has NO dev-chosen id to match the target's synthesized id — its
1359
- // raw-id create is refused by the mint gate anyway — so it is NOT a usable establisher here (the real
1360
- // gate then arbitrates the target, never a false green).
1361
- const creator = directives.find((d) => {
1362
- if (d === gated || typeof d?.payloadSchema !== "object" || d.birthsChild === true) return false;
1363
- if (!probeWritesAggregateTypes(d, `${domain}/${d.id}`).has(aggType)) return false;
1364
- const isEnsures = d.marker === "ensures";
1365
- const isCreateOnce = d.marker === "creates" && (d as { createOnceIdField?: unknown }).createOnceIdField !== undefined;
1366
- return isEnsures || isCreateOnce;
1367
- });
1226
+ // (`.withId`). The runner observes its real output and supplies that id to the target. A truly MINTED
1227
+ // `.creates` needs a mint recipe this setup shape does not yet carry, so deterministic ensures/creates
1228
+ // remain the supported establishers and the real gate arbitrates anything else.
1229
+ const creator = directives
1230
+ .map((directive, index) => ({ directive, index }))
1231
+ .filter(({ directive: d }) => {
1232
+ if (d === gated || typeof d?.payloadSchema !== "object" || d.birthsChild === true) return false;
1233
+ if (!probeWritesAggregateTypes(d, `${domain}/${d.id}`).has(aggType)) return false;
1234
+ const isEnsures = d.marker === "ensures";
1235
+ const isCreateOnce = d.marker === "creates" && (d as { createOnceIdField?: unknown }).createOnceIdField !== undefined;
1236
+ return isEnsures || isCreateOnce;
1237
+ })
1238
+ // Prerequisites are business history. Prefer the published intent which establishes it; a private
1239
+ // completion/recovery effect can write the same aggregate but is not a tenant-reachable producer.
1240
+ .sort((left, right) => {
1241
+ const publicRank = (directive: Directive<unknown>): number =>
1242
+ isBusinessIntent(directive) && !directive.id.startsWith("_nms") ? 0 : 1;
1243
+ return publicRank(left.directive) - publicRank(right.directive) || left.index - right.index;
1244
+ })[0]?.directive;
1368
1245
  if (creator === undefined) continue;
1369
1246
  if (seen.has(creator.id)) continue;
1370
1247
  let synth: SynthesizedPayload;
1371
1248
  try {
1372
- synth = synthesizePayload(creator.payloadSchema as z.ZodTypeAny, `${domain}/${creator.id}`);
1249
+ synth = synthesizeDirectivePayload(creator, `${domain}/${creator.id}`);
1373
1250
  } catch {
1374
1251
  continue;
1375
1252
  }
1376
1253
  const payload: Record<string, unknown> = { ...synth.value };
1254
+ const referenceFields = aggregateReferenceFields(creator.payloadSchema as z.ZodTypeAny);
1377
1255
  seen.add(creator.id);
1378
1256
  setups.push({
1379
1257
  directiveId: creator.id,
1380
1258
  payload,
1259
+ aggregateType: aggType,
1260
+ ...(((mod.aggregates as AggregateHandle[]).find((aggregate) => aggregate.id === aggType)?.cap === 1)
1261
+ ? { reuseIfPresent: true }
1262
+ : {}),
1263
+ ...(Object.keys(referenceFields).length > 0 ? { referenceFields } : {}),
1381
1264
  autoStamped: synth.autoStamped,
1382
1265
  ...(creator.requiresRelationGate !== undefined ? { requiresRelation: creator.requiresRelationGate.relation } : {}),
1383
1266
  });
@@ -1398,6 +1281,8 @@ export function discoverRelationBootstrapLeg(mod: DomainModule, gatedOverride?:
1398
1281
  const directives = mod.directives as Directive<unknown>[];
1399
1282
  const isGatedProvable = (d: Directive<unknown> | undefined): boolean =>
1400
1283
  d?.requiresRelationGate !== undefined &&
1284
+ !d.id.startsWith("_nms") &&
1285
+ (d as { businessBirthInternal?: unknown }).businessBirthInternal !== true &&
1401
1286
  typeof d.payloadSchema === "object" &&
1402
1287
  d.birthsChild !== true &&
1403
1288
  d.attestationAuthorizedGate === undefined;
@@ -1420,7 +1305,7 @@ export function discoverRelationBootstrapLeg(mod: DomainModule, gatedOverride?:
1420
1305
  // Synthesize the gated payload (mirror of the conformance leg — mintField removed, auto-stamped omitted).
1421
1306
  let gatedSynth: SynthesizedPayload;
1422
1307
  try {
1423
- gatedSynth = synthesizePayload(gated.payloadSchema as z.ZodTypeAny, `${domain}/${gated.id}`);
1308
+ gatedSynth = synthesizeDirectivePayload(gated, `${domain}/${gated.id}`);
1424
1309
  } catch {
1425
1310
  return undefined;
1426
1311
  }
@@ -1428,6 +1313,67 @@ export function discoverRelationBootstrapLeg(mod: DomainModule, gatedOverride?:
1428
1313
  const gatedMintField = gatedAgg !== undefined ? mintedCreateField(gated, gatedAgg) : undefined;
1429
1314
  const gatedPayload: Record<string, unknown> = { ...gatedSynth.value };
1430
1315
  if (gatedMintField !== undefined) delete gatedPayload[gatedMintField];
1316
+ const gatedReferenceFields = aggregateReferenceFields(gated.payloadSchema as z.ZodTypeAny);
1317
+ const gatedOptionalReferenceFields = optionalAggregateReferenceFields(gated.payloadSchema as z.ZodTypeAny);
1318
+ const gatedCreatesAggregate = gated.marker === "creates" || gated.marker === "ensures"
1319
+ ? gated.aggregateId
1320
+ : undefined;
1321
+ const gatedWrittenAggregates = [...probeWritesAggregateTypes(gated, `${domain}/${gated.id}`)].sort();
1322
+ const gatedReadAggregates = [...new Set(
1323
+ (mod.workspaceInvariants ?? [])
1324
+ .filter((invariant) => invariant.on === gated.id)
1325
+ .flatMap((invariant) => [...invariantReadAggregateTypes(invariant)]),
1326
+ )].sort();
1327
+
1328
+ // A declared business birth is the product's authority path, not merely one possible seed amongst many.
1329
+ // Prove the gated verb in the workspace that `app.birth(...)` actually creates. Otherwise an unrelated
1330
+ // legacy/bootstrap directive can look like a cleaner standalone granter and make the proof test a lane
1331
+ // tenant application code can no longer call (the exact false negative the one-surface work removes).
1332
+ const businessAuthorityRelations = [
1333
+ relation,
1334
+ ...resolveGrantableBaseRelations(
1335
+ mod.relationTypes,
1336
+ gated.requiresRelationGate!.object,
1337
+ relation,
1338
+ ).filter((candidate) => candidate !== relation),
1339
+ ];
1340
+ let businessAuthorityRelation: string | undefined;
1341
+ let businessBornContext: BornContextAuthority | undefined;
1342
+ for (const candidate of businessAuthorityRelations) {
1343
+ const discovered = discoverBornContextAuthority(mod, candidate);
1344
+ if (discovered === undefined) continue;
1345
+ businessAuthorityRelation = candidate;
1346
+ businessBornContext = discovered;
1347
+ break;
1348
+ }
1349
+ if (businessBornContext !== undefined) {
1350
+ const birthDirective = directives.find((d) => d.id === businessBornContext.birthDirectiveId);
1351
+ if ((birthDirective as { businessBirth?: unknown } | undefined)?.businessBirth !== undefined) {
1352
+ return {
1353
+ domain,
1354
+ gatedDirectiveId: gated.id,
1355
+ relation,
1356
+ grantedRelation: businessAuthorityRelation ?? relation,
1357
+ gatedPayload,
1358
+ ...(Object.keys(gatedReferenceFields).length > 0 ? { gatedReferenceFields } : {}),
1359
+ ...(gatedOptionalReferenceFields.length > 0 ? { gatedOptionalReferenceFields } : {}),
1360
+ gatedAutoStamped: gatedSynth.autoStamped,
1361
+ gatedMarker: gated.marker,
1362
+ ...(gatedWrittenAggregates.length > 0 ? { gatedWrittenAggregates } : {}),
1363
+ ...(gatedReadAggregates.length > 0 ? { gatedReadAggregates } : {}),
1364
+ ...(gated.businessPrincipalField !== undefined ? { gatedPrincipalField: gated.businessPrincipalField } : {}),
1365
+ ...(gatedMintField !== undefined ? { gatedMintField } : {}),
1366
+ ...(gatedCreatesAggregate !== undefined ? { gatedAggregateId: gatedCreatesAggregate } : {}),
1367
+ grantDirectiveId: businessBornContext.seatsViaDirectiveId,
1368
+ grantPayload: {},
1369
+ grantAutoStamped: [],
1370
+ grantSubjectFields: [],
1371
+ grantGrantedByFields: [],
1372
+ via: "born-context",
1373
+ bornContext: businessBornContext,
1374
+ };
1375
+ }
1376
+ }
1431
1377
 
1432
1378
  // Find a granter that establishes the actor's authority for the gate relation. Never the gated directive.
1433
1379
  // (1) DIRECT: a `.grants(R)` marker (unambiguous), ELSE a plan-probed `writeTuple(R)`.
@@ -1520,16 +1466,33 @@ export function discoverRelationBootstrapLeg(mod: DomainModule, gatedOverride?:
1520
1466
  const standaloneClean =
1521
1467
  found !== undefined && !seedSpeculative && !directiveHasPrerequisiteInvariant(mod, found.granter.id);
1522
1468
  if (!standaloneClean) {
1523
- const bornContext = discoverBornContextAuthority(mod, relation);
1469
+ // The birth may seat a BASE relation which satisfies this computed gate (homeCreator -> homeAdmin), not
1470
+ // the gate's display name itself. Search the same rewrite-aware candidate set used above; the real born
1471
+ // workspace gate remains the final arbiter, so this cannot manufacture authority.
1472
+ let bornAuthorityRelation: string | undefined;
1473
+ let bornContext: BornContextAuthority | undefined;
1474
+ for (const candidate of businessAuthorityRelations) {
1475
+ const discovered = discoverBornContextAuthority(mod, candidate);
1476
+ if (discovered === undefined) continue;
1477
+ bornAuthorityRelation = candidate;
1478
+ bornContext = discovered;
1479
+ break;
1480
+ }
1524
1481
  if (bornContext !== undefined) {
1525
1482
  return {
1526
1483
  domain,
1527
1484
  gatedDirectiveId: gated.id,
1528
1485
  relation,
1529
- grantedRelation: relation,
1486
+ grantedRelation: bornAuthorityRelation ?? relation,
1530
1487
  gatedPayload,
1488
+ ...(Object.keys(gatedReferenceFields).length > 0 ? { gatedReferenceFields } : {}),
1489
+ ...(gatedOptionalReferenceFields.length > 0 ? { gatedOptionalReferenceFields } : {}),
1531
1490
  gatedAutoStamped: gatedSynth.autoStamped,
1532
- ...(gatedMintField !== undefined ? { gatedMintField, gatedAggregateId: gated.aggregateId } : {}),
1491
+ gatedMarker: gated.marker,
1492
+ ...(gatedWrittenAggregates.length > 0 ? { gatedWrittenAggregates } : {}),
1493
+ ...(gatedReadAggregates.length > 0 ? { gatedReadAggregates } : {}),
1494
+ ...(gatedMintField !== undefined ? { gatedMintField } : {}),
1495
+ ...(gatedCreatesAggregate !== undefined ? { gatedAggregateId: gatedCreatesAggregate } : {}),
1533
1496
  // grant fields are UNUSED for a born-context leg (the runner births + dispatches inside); populate them
1534
1497
  // with the genesis seed's id / empty payload so the shape stays uniform (never dispatched standalone).
1535
1498
  grantDirectiveId: bornContext.seatsViaDirectiveId,
@@ -1573,11 +1536,12 @@ export function discoverRelationBootstrapLeg(mod: DomainModule, gatedOverride?:
1573
1536
  // any field whose name looks like a subject/grantedBy anyway).
1574
1537
  let grantSynth: SynthesizedPayload;
1575
1538
  try {
1576
- grantSynth = synthesizePayload(granter.payloadSchema as z.ZodTypeAny, `${domain}/${granter.id}`);
1539
+ grantSynth = synthesizeDirectivePayload(granter, `${domain}/${granter.id}`);
1577
1540
  } catch {
1578
1541
  return undefined;
1579
1542
  }
1580
1543
  const grantPayload: Record<string, unknown> = { ...grantSynth.value };
1544
+ const grantReferenceFields = aggregateReferenceFields(granter.payloadSchema as z.ZodTypeAny);
1581
1545
  const probed = probePlanOps(granter, `${domain}/${granter.id}`);
1582
1546
  const routed = probed !== undefined ? resolveGrantSubjectFields(probed) : { subjectFields: [], grantedByFields: [], wrappedSubjectFields: [] };
1583
1547
 
@@ -1587,10 +1551,18 @@ export function discoverRelationBootstrapLeg(mod: DomainModule, gatedOverride?:
1587
1551
  relation,
1588
1552
  grantedRelation,
1589
1553
  gatedPayload,
1554
+ ...(Object.keys(gatedReferenceFields).length > 0 ? { gatedReferenceFields } : {}),
1555
+ ...(gatedOptionalReferenceFields.length > 0 ? { gatedOptionalReferenceFields } : {}),
1590
1556
  gatedAutoStamped: gatedSynth.autoStamped,
1591
- ...(gatedMintField !== undefined ? { gatedMintField, gatedAggregateId: gated.aggregateId } : {}),
1557
+ gatedMarker: gated.marker,
1558
+ ...(gatedWrittenAggregates.length > 0 ? { gatedWrittenAggregates } : {}),
1559
+ ...(gatedReadAggregates.length > 0 ? { gatedReadAggregates } : {}),
1560
+ ...(gated.businessPrincipalField !== undefined ? { gatedPrincipalField: gated.businessPrincipalField } : {}),
1561
+ ...(gatedMintField !== undefined ? { gatedMintField } : {}),
1562
+ ...(gatedCreatesAggregate !== undefined ? { gatedAggregateId: gatedCreatesAggregate } : {}),
1592
1563
  grantDirectiveId: granter.id,
1593
1564
  grantPayload,
1565
+ ...(Object.keys(grantReferenceFields).length > 0 ? { grantReferenceFields } : {}),
1594
1566
  grantAutoStamped: grantSynth.autoStamped,
1595
1567
  grantSubjectFields: routed.subjectFields,
1596
1568
  grantGrantedByFields: routed.grantedByFields,
@@ -1604,6 +1576,137 @@ export function discoverRelationBootstrapLeg(mod: DomainModule, gatedOverride?:
1604
1576
  };
1605
1577
  }
1606
1578
 
1579
+ /** A principal-bound action has no grant to bootstrap: its authority is the verified application identity
1580
+ * itself. It still needs a real born business workspace and any declared prerequisite records, so represent
1581
+ * it in the same stateful journey shape while marking the identity field explicitly for the runner. */
1582
+ function discoverPrincipalBoundLeg(
1583
+ mod: DomainModule,
1584
+ target: Directive<unknown>,
1585
+ ): RelationBootstrapLeg | undefined {
1586
+ const principalField = target.businessPrincipalField;
1587
+ if (principalField === undefined || target.requiresRelationGate !== undefined) return undefined;
1588
+ const domain = mod.domain ?? mod.name;
1589
+ let synth: SynthesizedPayload;
1590
+ try {
1591
+ synth = synthesizeDirectivePayload(target, `${domain}/${target.id}`);
1592
+ } catch {
1593
+ return undefined;
1594
+ }
1595
+ const birthDirectives = (mod.directives as Directive<unknown>[]).filter(
1596
+ (directive) => directive.birthsChild === true &&
1597
+ (directive as { businessBirth?: { founderRoles?: readonly string[] } }).businessBirth !== undefined,
1598
+ );
1599
+ let bornContext: BornContextAuthority | undefined;
1600
+ for (const birth of birthDirectives) {
1601
+ const roles = (birth as { businessBirth?: { founderRoles?: readonly string[] } }).businessBirth?.founderRoles ?? [];
1602
+ for (const role of roles) {
1603
+ bornContext = discoverBornContextAuthority(mod, role);
1604
+ if (bornContext !== undefined && bornContext.birthDirectiveId === birth.id) break;
1605
+ }
1606
+ if (bornContext !== undefined) break;
1607
+ }
1608
+ if (bornContext === undefined) return undefined;
1609
+
1610
+ const aggregate = (mod.aggregates as AggregateHandle[]).find((candidate) => candidate.id === target.aggregateId);
1611
+ const mintField = aggregate === undefined ? undefined : mintedCreateField(target, aggregate);
1612
+ const payload: Record<string, unknown> = { ...synth.value };
1613
+ if (mintField !== undefined) delete payload[mintField];
1614
+ const referenceFields = aggregateReferenceFields(target.payloadSchema as z.ZodTypeAny);
1615
+ const optionalReferenceFields = optionalAggregateReferenceFields(target.payloadSchema as z.ZodTypeAny);
1616
+ const establishesAggregate = target.marker === "creates" || target.marker === "ensures"
1617
+ ? target.aggregateId
1618
+ : undefined;
1619
+ const writtenAggregates = [...probeWritesAggregateTypes(target, `${domain}/${target.id}`)].sort();
1620
+ const readAggregates = [...new Set(
1621
+ (mod.workspaceInvariants ?? [])
1622
+ .filter((invariant) => invariant.on === target.id)
1623
+ .flatMap((invariant) => [...invariantReadAggregateTypes(invariant)]),
1624
+ )].sort();
1625
+ const preconditionSetups = discoverPreconditionSetups(mod, target);
1626
+ return {
1627
+ domain,
1628
+ gatedDirectiveId: target.id,
1629
+ relation: "currentPrincipal",
1630
+ grantedRelation: "currentPrincipal",
1631
+ gatedPayload: payload,
1632
+ ...(Object.keys(referenceFields).length > 0 ? { gatedReferenceFields: referenceFields } : {}),
1633
+ ...(optionalReferenceFields.length > 0 ? { gatedOptionalReferenceFields: optionalReferenceFields } : {}),
1634
+ gatedAutoStamped: synth.autoStamped,
1635
+ gatedMarker: target.marker,
1636
+ ...(writtenAggregates.length > 0 ? { gatedWrittenAggregates: writtenAggregates } : {}),
1637
+ ...(readAggregates.length > 0 ? { gatedReadAggregates: readAggregates } : {}),
1638
+ gatedPrincipalField: principalField,
1639
+ ...(mintField !== undefined ? { gatedMintField: mintField } : {}),
1640
+ ...(establishesAggregate !== undefined ? { gatedAggregateId: establishesAggregate } : {}),
1641
+ grantDirectiveId: bornContext.seatsViaDirectiveId,
1642
+ grantPayload: {},
1643
+ grantAutoStamped: [],
1644
+ grantSubjectFields: [],
1645
+ grantGrantedByFields: [],
1646
+ via: "born-context",
1647
+ bornContext,
1648
+ ...(preconditionSetups.length > 0 ? { preconditionSetups } : {}),
1649
+ };
1650
+ }
1651
+
1652
+ /** An ordinary business action may intentionally need no role gate. It is still part of the same generated
1653
+ * stateful application journey: its inputs are typed refs produced by earlier intents, and a business-birth
1654
+ * domain must run it inside that born workspace. Treating it as "not proofable" merely because no authority
1655
+ * ceremony is required left conflict merge policies public but unexecuted. */
1656
+ function discoverUnrestrictedBusinessLeg(
1657
+ mod: DomainModule,
1658
+ target: Directive<unknown>,
1659
+ bornContext?: BornContextAuthority,
1660
+ ): RelationBootstrapLeg | undefined {
1661
+ if (target.requiresRelationGate !== undefined || target.businessPrincipalField !== undefined) return undefined;
1662
+ const domain = mod.domain ?? mod.name;
1663
+ let synth: SynthesizedPayload;
1664
+ try {
1665
+ synth = synthesizeDirectivePayload(target, `${domain}/${target.id}`);
1666
+ } catch {
1667
+ return undefined;
1668
+ }
1669
+ const aggregate = (mod.aggregates as AggregateHandle[]).find((candidate) => candidate.id === target.aggregateId);
1670
+ const mintField = aggregate === undefined ? undefined : mintedCreateField(target, aggregate);
1671
+ const payload: Record<string, unknown> = { ...synth.value };
1672
+ if (mintField !== undefined) delete payload[mintField];
1673
+ const referenceFields = aggregateReferenceFields(target.payloadSchema as z.ZodTypeAny);
1674
+ const optionalReferenceFields = optionalAggregateReferenceFields(target.payloadSchema as z.ZodTypeAny);
1675
+ const establishesAggregate = target.marker === "creates" || target.marker === "ensures"
1676
+ ? target.aggregateId
1677
+ : undefined;
1678
+ const writtenAggregates = [...probeWritesAggregateTypes(target, `${domain}/${target.id}`)].sort();
1679
+ const readAggregates = [...new Set(
1680
+ (mod.workspaceInvariants ?? [])
1681
+ .filter((invariant) => invariant.on === target.id)
1682
+ .flatMap((invariant) => [...invariantReadAggregateTypes(invariant)]),
1683
+ )].sort();
1684
+ const preconditionSetups = discoverPreconditionSetups(mod, target);
1685
+ return {
1686
+ domain,
1687
+ gatedDirectiveId: target.id,
1688
+ relation: "unrestricted",
1689
+ grantedRelation: "unrestricted",
1690
+ gatedPayload: payload,
1691
+ ...(Object.keys(referenceFields).length > 0 ? { gatedReferenceFields: referenceFields } : {}),
1692
+ ...(optionalReferenceFields.length > 0 ? { gatedOptionalReferenceFields: optionalReferenceFields } : {}),
1693
+ gatedAutoStamped: synth.autoStamped,
1694
+ gatedMarker: target.marker,
1695
+ ...(writtenAggregates.length > 0 ? { gatedWrittenAggregates: writtenAggregates } : {}),
1696
+ ...(readAggregates.length > 0 ? { gatedReadAggregates: readAggregates } : {}),
1697
+ ...(mintField !== undefined ? { gatedMintField: mintField } : {}),
1698
+ ...(establishesAggregate !== undefined ? { gatedAggregateId: establishesAggregate } : {}),
1699
+ grantDirectiveId: "",
1700
+ grantPayload: {},
1701
+ grantAutoStamped: [],
1702
+ grantSubjectFields: [],
1703
+ grantGrantedByFields: [],
1704
+ via: bornContext === undefined ? "unrestricted" : "born-context",
1705
+ ...(bornContext === undefined ? {} : { bornContext }),
1706
+ ...(preconditionSetups.length > 0 ? { preconditionSetups } : {}),
1707
+ };
1708
+ }
1709
+
1607
1710
  /**
1608
1711
  * MULTI-TARGET relation-bootstrap discovery (co2 ask #2). The singular {@link discoverRelationBootstrapLeg}
1609
1712
  * proves ONE gated create per domain; this runs TARGET-SPECIFIC discovery for EVERY gated create/write, so a
@@ -1613,20 +1716,48 @@ export function discoverRelationBootstrapLeg(mod: DomainModule, gatedOverride?:
1613
1716
  * discoverable path is simply absent from the result (the taxonomy audit then names ONLY the real gaps).
1614
1717
  * De-duplicated by `gatedDirectiveId` (a target proven once is not re-emitted).
1615
1718
  */
1616
- export function discoverRelationBootstrapLegs(mod: DomainModule): RelationBootstrapLeg[] {
1719
+ export function discoverRelationBootstrapLegs(
1720
+ mod: DomainModule,
1721
+ unrestrictedBornContext?: BornContextAuthority,
1722
+ ): RelationBootstrapLeg[] {
1617
1723
  const directives = mod.directives as Directive<unknown>[];
1618
- const isGatedProvable = (d: Directive<unknown> | undefined): boolean =>
1619
- d?.requiresRelationGate !== undefined &&
1724
+ const isBusinessJourneyProvable = (d: Directive<unknown> | undefined): boolean =>
1725
+ (d?.requiresRelationGate !== undefined || d?.businessPrincipalField !== undefined || isBusinessIntent(d)) &&
1726
+ !d.id.startsWith("_nms") &&
1727
+ (d as { businessBirthInternal?: unknown }).businessBirthInternal !== true &&
1620
1728
  typeof d.payloadSchema === "object" &&
1621
1729
  d.birthsChild !== true &&
1622
1730
  d.attestationAuthorizedGate === undefined;
1623
1731
  const legs: RelationBootstrapLeg[] = [];
1624
1732
  const seen = new Set<string>();
1625
- for (const target of directives.filter(isGatedProvable)) {
1733
+ // This is a generated STATEFUL business journey, not a bag of CRUD probes. Establish root records before
1734
+ // actions that consume typed references, and keep framework-generated clear utilities behind authored
1735
+ // business intents. Stable source order is the final tie-breaker.
1736
+ const targets = directives
1737
+ .map((directive, index) => ({ directive, index }))
1738
+ .filter(({ directive }) => isBusinessJourneyProvable(directive))
1739
+ .sort((a, b) => {
1740
+ const authoredA = isBusinessIntent(a.directive) ? 0 : 1;
1741
+ const authoredB = isBusinessIntent(b.directive) ? 0 : 1;
1742
+ // A declared application language is already the tenant's readable business sequence. Preserve that
1743
+ // order among authored intents; only place compiler-generated utilities behind it.
1744
+ if (authoredA === 0 && authoredB === 0) return a.index - b.index;
1745
+ const markerRank = (directive: Directive<unknown>): number =>
1746
+ directive.marker === "creates" ? 0 : directive.marker === "ensures" ? 1 : 2;
1747
+ const refsA = Object.keys(aggregateReferenceFields(a.directive.payloadSchema as z.ZodTypeAny)).length;
1748
+ const refsB = Object.keys(aggregateReferenceFields(b.directive.payloadSchema as z.ZodTypeAny)).length;
1749
+ return authoredA - authoredB || markerRank(a.directive) - markerRank(b.directive) || refsA - refsB || a.index - b.index;
1750
+ })
1751
+ .map(({ directive }) => directive);
1752
+ for (const target of targets) {
1626
1753
  if (seen.has(target.id)) continue;
1627
1754
  let leg: RelationBootstrapLeg | undefined;
1628
1755
  try {
1629
- leg = discoverRelationBootstrapLeg(mod, target);
1756
+ leg = target.requiresRelationGate !== undefined
1757
+ ? discoverRelationBootstrapLeg(mod, target)
1758
+ : target.businessPrincipalField !== undefined
1759
+ ? discoverPrincipalBoundLeg(mod, target)
1760
+ : discoverUnrestrictedBusinessLeg(mod, target, unrestrictedBornContext);
1630
1761
  } catch {
1631
1762
  leg = undefined;
1632
1763
  }
@@ -1635,7 +1766,97 @@ export function discoverRelationBootstrapLegs(mod: DomainModule): RelationBootst
1635
1766
  seen.add(leg.gatedDirectiveId);
1636
1767
  }
1637
1768
  }
1638
- return legs;
1769
+
1770
+ // Source order is the readable default, but it cannot override the type system: an action accepting a
1771
+ // NomosRef<T> must run after some generated action has actually established T. Build the smallest stable
1772
+ // dependency graph over the discovered business legs. This is not CRUD ordering; an intent may establish
1773
+ // several aggregates, and every declared/probed output participates as a possible producer.
1774
+ const byId = new Map(directives.map((directive, index) => [directive.id, { directive, index }]));
1775
+ const businessOrder = new Map(legs.map((leg, index) => [leg.gatedDirectiveId, index]));
1776
+ const establishes = new Map<string, Set<string>>();
1777
+ const requiredReferences = new Map<string, Set<string>>();
1778
+ for (const leg of legs) {
1779
+ const directive = byId.get(leg.gatedDirectiveId)?.directive;
1780
+ if (directive === undefined) continue;
1781
+ establishes.set(
1782
+ leg.gatedDirectiveId,
1783
+ probeEstablishesAggregateTypes(directive, `${mod.domain ?? mod.name}/${directive.id}`),
1784
+ );
1785
+ const optional = new Set(leg.gatedOptionalReferenceFields ?? []);
1786
+ requiredReferences.set(
1787
+ leg.gatedDirectiveId,
1788
+ new Set(Object.entries(leg.gatedReferenceFields ?? {})
1789
+ .filter(([field]) => !optional.has(field))
1790
+ .map(([, aggregate]) => aggregate)),
1791
+ );
1792
+ }
1793
+ const dependencies = new Map(legs.map((leg) => [leg.gatedDirectiveId, new Set<string>()]));
1794
+ for (const consumer of legs) {
1795
+ for (const aggregate of requiredReferences.get(consumer.gatedDirectiveId) ?? []) {
1796
+ const candidates = legs
1797
+ .filter((producer) =>
1798
+ producer.gatedDirectiveId !== consumer.gatedDirectiveId &&
1799
+ establishes.get(producer.gatedDirectiveId)?.has(aggregate) === true)
1800
+ .sort((a, b) => {
1801
+ const da = byId.get(a.gatedDirectiveId)!;
1802
+ const db = byId.get(b.gatedDirectiveId)!;
1803
+ const markerRank = (directive: Directive<unknown>): number =>
1804
+ directive.marker === "creates" ? 0 : directive.marker === "ensures" ? 1 : 2;
1805
+ const selfReferenceRank = (leg: RelationBootstrapLeg): number =>
1806
+ requiredReferences.get(leg.gatedDirectiveId)?.has(aggregate) === true ? 1 : 0;
1807
+ return selfReferenceRank(a) - selfReferenceRank(b) ||
1808
+ markerRank(da.directive) - markerRank(db.directive) ||
1809
+ (requiredReferences.get(a.gatedDirectiveId)?.size ?? 0) - (requiredReferences.get(b.gatedDirectiveId)?.size ?? 0) ||
1810
+ (businessOrder.get(a.gatedDirectiveId) ?? da.index) - (businessOrder.get(b.gatedDirectiveId) ?? db.index);
1811
+ });
1812
+ const producer = candidates[0];
1813
+ if (producer !== undefined) dependencies.get(consumer.gatedDirectiveId)!.add(producer.gatedDirectiveId);
1814
+ }
1815
+ const consumerDirective = byId.get(consumer.gatedDirectiveId)?.directive;
1816
+ if (consumerDirective?.marker === "mutates" || consumerDirective?.marker === "archives") {
1817
+ // A deterministic/composite-id mutation often has no explicit NomosRef<T> field: the plan derives its
1818
+ // instance id from ordinary business coordinates (site + feature key, listing + version). It still
1819
+ // cannot precede the action that establishes T. Treat the directive's declared target type as a
1820
+ // dependency whenever the business language exposes a positive creator/ensurer for that type.
1821
+ const targetProducer = legs
1822
+ .filter((candidate) => candidate.gatedDirectiveId !== consumer.gatedDirectiveId)
1823
+ .filter((candidate) => {
1824
+ const candidateDirective = byId.get(candidate.gatedDirectiveId)?.directive;
1825
+ return candidateDirective !== undefined &&
1826
+ (candidateDirective.marker === "creates" || candidateDirective.marker === "ensures") &&
1827
+ establishes.get(candidate.gatedDirectiveId)?.has(consumerDirective.aggregateId) === true;
1828
+ })
1829
+ .sort((left, right) => {
1830
+ const leftDirective = byId.get(left.gatedDirectiveId)!.directive;
1831
+ const rightDirective = byId.get(right.gatedDirectiveId)!.directive;
1832
+ const rank = (directive: Directive<unknown>): number => directive.marker === "creates" ? 0 : 1;
1833
+ return rank(leftDirective) - rank(rightDirective) ||
1834
+ (businessOrder.get(left.gatedDirectiveId) ?? 0) - (businessOrder.get(right.gatedDirectiveId) ?? 0);
1835
+ })[0];
1836
+ if (targetProducer !== undefined) {
1837
+ dependencies.get(consumer.gatedDirectiveId)!.add(targetProducer.gatedDirectiveId);
1838
+ }
1839
+ }
1840
+ }
1841
+ const remaining = new Map(legs.map((leg) => [leg.gatedDirectiveId, leg]));
1842
+ const ordered: RelationBootstrapLeg[] = [];
1843
+ while (remaining.size > 0) {
1844
+ const ready = [...remaining.values()]
1845
+ .filter((leg) => [...(dependencies.get(leg.gatedDirectiveId) ?? [])].every((id) => !remaining.has(id)))
1846
+ .sort((a, b) => (businessOrder.get(a.gatedDirectiveId) ?? 0) - (businessOrder.get(b.gatedDirectiveId) ?? 0));
1847
+ if (ready.length === 0) {
1848
+ // A genuine required-reference cycle cannot be linearized. Preserve the deterministic source suffix;
1849
+ // the proof will name the missing real reference rather than silently dropping business actions.
1850
+ ordered.push(...[...remaining.values()].sort((a, b) =>
1851
+ (businessOrder.get(a.gatedDirectiveId) ?? 0) - (businessOrder.get(b.gatedDirectiveId) ?? 0)));
1852
+ break;
1853
+ }
1854
+ for (const leg of ready) {
1855
+ ordered.push(leg);
1856
+ remaining.delete(leg.gatedDirectiveId);
1857
+ }
1858
+ }
1859
+ return ordered;
1639
1860
  }
1640
1861
 
1641
1862
  /** A discovered layer-3 SEED directive: a sibling (non-gated, non-birth) whose plan writes relation tuples,
@@ -1687,7 +1908,7 @@ export function diagnoseRelationBootstrapGap(mod: DomainModule): string | undefi
1687
1908
  const inv = (mod.workspaceInvariants ?? []).find((i) => i.on === prereqGranter.id);
1688
1909
  return `${domain}/${gated.id} is gated by .requires("${relation}") but the proof cannot seed authority: the only granter of "${relation}" is `
1689
1910
  + `${domain}/${prereqGranter.id}, which carries the prerequisite invariant '${inv?.id ?? "?"}' (it reads state an EARLIER step must establish), so a standalone re-seed FALSE-fails — and no \`.births()\` genesis seats "${relation}" to prove it in a born workspace. `
1690
- + `Establish "${relation}" via a birth genesis (a \`.births()\` whose chain runs ${prereqGranter.id} after seeding its prerequisite), or prove ${gated.id} by hand. (The negative conformance leg still proves the gate refuses an actorless offer.)`;
1911
+ + `Establish "${relation}" via a birth genesis (a \`.births()\` whose chain runs ${prereqGranter.id} after seeding its prerequisite) so the generator can produce the positive journey. (The negative conformance leg still proves the gate refuses an actorless offer.)`;
1691
1912
  }
1692
1913
  const bases = resolveGrantableBaseRelations(mod.relationTypes, object, relation).filter((b) => b !== relation);
1693
1914
  const tried = bases.length > 0
@@ -1937,7 +2158,7 @@ export function discoverChildBirthLegOrReason(
1937
2158
  let recipe: { workspace?: unknown; genesisChain?: unknown } | undefined;
1938
2159
  let synth: SynthesizedPayload;
1939
2160
  try {
1940
- synth = synthesizePayload(birthDir.payloadSchema as z.ZodTypeAny, `${parentDomain}/${birthDir.id}`);
2161
+ synth = synthesizeDirectivePayload(birthDir, `${parentDomain}/${birthDir.id}`);
1941
2162
  } catch (e) {
1942
2163
  return { reason: `${who}: the payload could not be synthesized for the compile probe (${(e as Error)?.message ?? e}) — the offline proof needs a sampleable payload (strings/numbers/enums; exotic shapes drop the leg)` };
1943
2164
  }
@@ -2119,7 +2340,7 @@ function discoverSingletonInstanceId(seedDir: Directive<unknown>, ownerMod?: Dom
2119
2340
  const idsFor = (seed: number): string | undefined => {
2120
2341
  let synth: SynthesizedPayload;
2121
2342
  try {
2122
- synth = synthesizePayload(seedDir.payloadSchema as z.ZodTypeAny, `seed/${seedDir.id}`);
2343
+ synth = synthesizeDirectivePayload(seedDir, `seed/${seedDir.id}`);
2123
2344
  } catch {
2124
2345
  return undefined;
2125
2346
  }
@@ -2190,6 +2411,8 @@ export interface ProofLegs {
2190
2411
  readonly payload?: Record<string, unknown>;
2191
2412
  readonly autoStamped?: readonly string[];
2192
2413
  readonly mintField?: string;
2414
+ /** Hidden owned-record sealing coordinates used by the local product proof. Tenant tests never see them. */
2415
+ readonly ownedEncryption?: ProofOwnedEncryption;
2193
2416
  readonly query?: { readonly id: string; readonly params: Record<string, unknown> };
2194
2417
  readonly count?: { readonly id: string; readonly group: string };
2195
2418
  /** BIRTHS DX DIAGNOSTICS: present when this domain declares ≥1 `.births()` directive whose child-birth
@@ -2215,6 +2438,7 @@ export interface ProofLegs {
2215
2438
  readonly payload: Record<string, unknown>;
2216
2439
  readonly autoStamped: readonly string[];
2217
2440
  readonly mintField?: string;
2441
+ readonly ownedEncryption?: ProofOwnedEncryption;
2218
2442
  readonly query?: { readonly id: string; readonly params: Record<string, unknown> };
2219
2443
  readonly count?: { readonly id: string; readonly group: string };
2220
2444
  readonly spatial?: { readonly id: string };
@@ -2237,12 +2461,20 @@ export interface ProofLegs {
2237
2461
  readonly relationBootstraps?: readonly RelationBootstrapLeg[];
2238
2462
  }
2239
2463
 
2464
+ export interface ProofOwnedEncryption {
2465
+ readonly scope: string;
2466
+ readonly recordType: string;
2467
+ readonly fields: Readonly<Record<string, { readonly aggSid: string; readonly fieldSid: string }>>;
2468
+ }
2469
+
2240
2470
  /** Synthesize the standalone-create offline legs for one domain module, or `null` when it has no
2241
2471
  * creating write (nothing to prove standalone — it may still be child-birth-provable / compile-valid).
2242
2472
  * The SINGLE source of the create-leg selection — `generateTsProof` (the .mts marker) and
2243
2473
  * `proofLegsIndex` (the per-domain index) both call this, so the offline lane proves any domain the
2244
2474
  * same way the generated proof proves its primary one. */
2245
- /** A `.creates` directive the proof can DRIVE from a synthesized sample offline WITH NO SEEDED AUTHORITY: not
2475
+ /** An ungated `.creates` or `.ensures` directive the proof can DRIVE from a synthesized sample offline WITH
2476
+ * NO SEEDED AUTHORITY. Ensures matter for singleton/upsert business laws: they still return a typed affected
2477
+ * reference and can be reopened through the same generated application journey. Excludes
2246
2478
  * a `.births()` (a birth is the child-birth lane), not ATTESTATION-AUTHORIZED (needs a signed §3 quote no
2247
2479
  * synthesizer can produce — e.g. the home law's `recordShare`), and NOT AUTHZ-GATED (`.requires(R)` — a
2248
2480
  * gated create dispatched with no seeded authority is REFUSED at the gate; its metadata already says it
@@ -2250,7 +2482,9 @@ export interface ProofLegs {
2250
2482
  * relation-bootstrap leg / the born-child genesis instead). Those are NOT standalone-provable offline; the
2251
2483
  * domain proves via its bootstrap / child-birth / compile-valid legs instead. */
2252
2484
  function isStandaloneCreate(d: Directive<unknown> | undefined): boolean {
2253
- return d?.marker === "creates" && typeof d.payloadSchema === "object"
2485
+ return (d?.marker === "creates" ||
2486
+ (d?.marker === "ensures" && isBusinessIntent(d))) &&
2487
+ typeof d.payloadSchema === "object"
2254
2488
  // Framework lifecycle directives are installed in the certified law so the generated client can
2255
2489
  // drive them behind its managed methods, but they are not tenant vocabulary. Selecting one here
2256
2490
  // makes the generated proof call a method that the public generated client correctly does not expose.
@@ -2265,11 +2499,89 @@ function isStandaloneCreate(d: Directive<unknown> | undefined): boolean {
2265
2499
  && (((d as { declaredForeignReads?: readonly unknown[] }).declaredForeignReads?.length ?? 0) === 0);
2266
2500
  }
2267
2501
 
2268
- /** Does this module carry ≥1 foreign-read directive (a static or dynamic-policy `.readsFrom`)? */
2269
- function hasForeignReadDirective(mod: DomainModule): boolean {
2270
- return (mod.directives as Directive<unknown>[]).some(
2271
- (d) => ((d as { declaredForeignReads?: readonly unknown[] }).declaredForeignReads?.length ?? 0) > 0,
2272
- );
2502
+ /**
2503
+ * A shape-level Create/Ensure is only a standalone business journey when no declared invariant fires on it.
2504
+ * Invariants are arbitrary policy: even a same-aggregate Ensure may require an earlier state (for example,
2505
+ * accepting an invitation requires that invitation to be pending and the current principal to be its
2506
+ * invitee). Treating the marker as CRUD and dispatching it into an empty workspace is a false proof.
2507
+ * Stateful actions belong in a generated prerequisite journey; until one is synthesized they remain named,
2508
+ * not misclassified as independently provable.
2509
+ */
2510
+ function isStandaloneProofSafe(mod: DomainModule, directive: Directive<unknown> | undefined): boolean {
2511
+ return isStandaloneCreate(directive) &&
2512
+ !(mod.workspaceInvariants ?? []).some((invariant) => invariant.on === directive!.id);
2513
+ }
2514
+
2515
+ /** Prefer the business create which demonstrates the richest typed relationship journey. Its prerequisites
2516
+ * are generated automatically, so a join/create that consumes two NomosRefs is a better canonical example
2517
+ * than an isolated leaf create. Stable source order breaks ties. */
2518
+ function orderedStandaloneCreates(mod: DomainModule): Directive<unknown>[] {
2519
+ return (mod.directives as Directive<unknown>[])
2520
+ .map((directive, index) => ({ directive, index }))
2521
+ .filter(({ directive }) => isStandaloneProofSafe(mod, directive))
2522
+ .sort((a, b) => {
2523
+ const refsA = Object.keys(aggregateReferenceFields(a.directive.payloadSchema as z.ZodTypeAny)).length;
2524
+ const refsB = Object.keys(aggregateReferenceFields(b.directive.payloadSchema as z.ZodTypeAny)).length;
2525
+ return refsB - refsA || a.index - b.index;
2526
+ })
2527
+ .map(({ directive }) => directive);
2528
+ }
2529
+
2530
+ interface ProofReferenceSeed {
2531
+ readonly directive: Directive<unknown>;
2532
+ readonly aggregate: AggregateHandle;
2533
+ readonly payload: Record<string, unknown>;
2534
+ readonly referenceFields: Readonly<Record<string, string>>;
2535
+ readonly mintField?: string;
2536
+ }
2537
+
2538
+ /** Build the prerequisite-create graph for one generated business action. SQL-style fake foreign keys are
2539
+ * forbidden: if an action needs `NomosRef<A>`, the generated journey first runs an ungated create for A,
2540
+ * retains the returned reference, and only then invokes the action. Cycles and missing creators fail compile
2541
+ * with the business types named instead of leaking a stringly proof. */
2542
+ function discoverProofReferenceSeeds(mod: DomainModule, target: Directive<unknown>): ProofReferenceSeed[] {
2543
+ const domain = mod.domain ?? mod.name;
2544
+ const directives = mod.directives as Directive<unknown>[];
2545
+ const aggregates = mod.aggregates as AggregateHandle[];
2546
+ const emitted = new Set<string>();
2547
+ const visiting = new Set<string>();
2548
+ const out: ProofReferenceSeed[] = [];
2549
+
2550
+ const visitType = (aggregateId: string): void => {
2551
+ if (emitted.has(aggregateId)) return;
2552
+ if (visiting.has(aggregateId)) {
2553
+ throw new Error(`codegen-proof: ${domain}/${target.id} has a cyclic typed-reference prerequisite through '${aggregateId}'`);
2554
+ }
2555
+ visiting.add(aggregateId);
2556
+ const directive = directives.find((candidate) =>
2557
+ candidate !== target && candidate.aggregateId === aggregateId && isStandaloneProofSafe(mod, candidate));
2558
+ const aggregate = aggregates.find((candidate) => candidate.id === aggregateId);
2559
+ if (directive === undefined || aggregate === undefined) {
2560
+ throw new Error(
2561
+ `codegen-proof: ${domain}/${target.id} needs NomosRef<${aggregateId}> but the law has no ungated ` +
2562
+ `.creates(${aggregateId}) action from which the generated journey can obtain one`,
2563
+ );
2564
+ }
2565
+ const mintField = mintedCreateField(directive, aggregate);
2566
+ const referenceFields: Record<string, string> = { ...aggregateReferenceFields(directive.payloadSchema as z.ZodTypeAny) };
2567
+ if (mintField !== undefined) delete referenceFields[mintField];
2568
+ for (const prerequisite of Object.values(referenceFields)) visitType(prerequisite);
2569
+ const synth = synthesizeDirectivePayload(directive, `${domain}/${directive.id}`);
2570
+ const payload: Record<string, unknown> = { ...synth.value };
2571
+ if (mintField !== undefined) delete payload[mintField];
2572
+ out.push({ directive, aggregate, payload, referenceFields, ...(mintField !== undefined ? { mintField } : {}) });
2573
+ visiting.delete(aggregateId);
2574
+ emitted.add(aggregateId);
2575
+ };
2576
+
2577
+ const targetReferences = { ...aggregateReferenceFields(target.payloadSchema as z.ZodTypeAny) };
2578
+ const targetAggregate = aggregates.find((aggregate) => aggregate.id === target.aggregateId);
2579
+ const targetMintField = targetAggregate === undefined ? undefined : mintedCreateField(target, targetAggregate);
2580
+ if (targetMintField !== undefined) delete targetReferences[targetMintField];
2581
+ for (const aggregateId of Object.values(targetReferences)) {
2582
+ visitType(aggregateId);
2583
+ }
2584
+ return out;
2273
2585
  }
2274
2586
 
2275
2587
  /** Does `v` carry an RFC 7946 geometry object at `segs` (walked into the composite)? */
@@ -2293,9 +2605,11 @@ function createLegFor(
2293
2605
  mod: DomainModule,
2294
2606
  createDir: Directive<unknown>,
2295
2607
  domain: string,
2608
+ domainInterface?: DomainInterface,
2296
2609
  ): {
2297
2610
  directiveId: string; aggregateId: string; payload: Record<string, unknown>;
2298
2611
  autoStamped: readonly string[]; mintField?: string;
2612
+ ownedEncryption?: ProofOwnedEncryption;
2299
2613
  query?: { id: string; params: Record<string, unknown> };
2300
2614
  count?: { id: string; group: string };
2301
2615
  spatial?: { id: string };
@@ -2303,7 +2617,7 @@ function createLegFor(
2303
2617
  const agg = (mod.aggregates as AggregateHandle[]).find((a) => a.id === createDir.aggregateId);
2304
2618
  if (agg === undefined) return null;
2305
2619
  const where = `${domain}/${createDir.id}`;
2306
- let synth = synthesizePayload(createDir.payloadSchema as z.ZodTypeAny, where);
2620
+ let synth = synthesizeDirectivePayload(createDir, where);
2307
2621
  const mintField = mintedCreateField(createDir, agg);
2308
2622
 
2309
2623
  // SPATIAL MEMBERSHIP: probe the plan — does the create set the indexed head field with a geometry
@@ -2327,7 +2641,7 @@ function createLegFor(
2327
2641
  let ops = probeWith(synth);
2328
2642
  let matched = spatials.find((sp) => hits(ops, sp));
2329
2643
  if (matched === undefined) {
2330
- const richer = synthesizePayload(createDir.payloadSchema as z.ZodTypeAny, where, { voIncludeOptional: true });
2644
+ const richer = synthesizeDirectivePayload(createDir, where, { voIncludeOptional: true });
2331
2645
  ops = probeWith(richer);
2332
2646
  matched = spatials.find((sp) => hits(ops, sp));
2333
2647
  if (matched !== undefined) synth = richer; // the geometry-bearing sample becomes the leg's payload
@@ -2343,23 +2657,36 @@ function createLegFor(
2343
2657
  const count = (mod.counts ?? [])
2344
2658
  .map((raw) => finishCount(raw))
2345
2659
  .find((c) => c.of === agg.id && (c as { where?: unknown }).where == null && (c.by == null || baseValue[c.by] !== undefined));
2660
+ const encryption = domainInterface === undefined ? null : domainEncryptionMap(mod, domainInterface);
2661
+ const ownedFields = encryption?.directives[createDir.id];
2662
+ const ownedEncryption = agg.audience?.kind === "owned" && ownedFields !== undefined
2663
+ ? {
2664
+ scope: Object.values(ownedFields)[0]!.scope,
2665
+ recordType: isNamespacedAggregate(agg) ? qualifyReadProjectionType(domain, agg.id) : agg.id,
2666
+ fields: Object.fromEntries(Object.entries(ownedFields).map(([field, slot]) => [
2667
+ field,
2668
+ { aggSid: slot.aggSid, fieldSid: slot.fieldSid },
2669
+ ])),
2670
+ }
2671
+ : undefined;
2346
2672
  return {
2347
2673
  directiveId: createDir.id,
2348
2674
  aggregateId: agg.id,
2349
2675
  payload: baseValue,
2350
2676
  autoStamped: synth.autoStamped,
2351
2677
  ...(mintField !== undefined ? { mintField } : {}),
2678
+ ...(ownedEncryption !== undefined ? { ownedEncryption } : {}),
2352
2679
  ...(query ? { query: { id: query.id, params: Object.fromEntries(query.key.map((k) => [k, baseValue[k]])) } } : {}),
2353
2680
  ...(count ? { count: { id: count.id, group: count.by != null ? String(baseValue[count.by]) : "" } } : {}),
2354
2681
  ...(spatial !== undefined ? { spatial } : {}),
2355
2682
  };
2356
2683
  }
2357
2684
 
2358
- export function proofLegsForModule(mod: DomainModule): ProofLegs | null {
2685
+ export function proofLegsForModule(mod: DomainModule, domainInterface?: DomainInterface): ProofLegs | null {
2359
2686
  const domain = mod.domain ?? mod.name;
2360
- const creates = (mod.directives as Directive<unknown>[]).filter((d) => isStandaloneCreate(d));
2687
+ const creates = orderedStandaloneCreates(mod);
2361
2688
  const legsBuilt = creates
2362
- .map((d) => { try { return createLegFor(mod, d, domain); } catch { return null; } })
2689
+ .map((d) => { try { return createLegFor(mod, d, domain, domainInterface); } catch { return null; } })
2363
2690
  .filter((l): l is NonNullable<typeof l> => l !== null);
2364
2691
  if (legsBuilt.length === 0) return null;
2365
2692
  const [primary, ...extras] = legsBuilt;
@@ -2422,6 +2749,133 @@ function attachBusinessEncryption(
2422
2749
  };
2423
2750
  }
2424
2751
 
2752
+ /** Resolve `.trustsSource(...)` against the package's actual source query and published business language.
2753
+ * The proof recipe contains no raw row seeding: it replays the smallest prefix ending at an action that
2754
+ * establishes the query's returned aggregate. If that business path cannot be found, compilation names the
2755
+ * missing feature instead of generating a target action that can only fail with an opaque attestation error. */
2756
+ function attachSourceTrustProofSetup(
2757
+ leg: RelationBootstrapLeg,
2758
+ target: Directive<unknown>,
2759
+ modules: readonly DomainModule[],
2760
+ ): RelationBootstrapLeg {
2761
+ const trust = target.businessSourceTrust;
2762
+ if (trust === undefined) return leg;
2763
+ const candidates = modules.flatMap((sourceModule) =>
2764
+ ((sourceModule.queries ?? []) as QueryDecl[])
2765
+ .filter((query) => query.id === trust.queryId)
2766
+ .map((query) => ({ sourceModule, query })),
2767
+ );
2768
+ if (candidates.length !== 1) {
2769
+ throw new Error(
2770
+ `${leg.domain}/${leg.gatedDirectiveId}: dynamic source query '${trust.queryId}' resolved to ${candidates.length} package queries; ` +
2771
+ `the generated application needs exactly one source business domain`,
2772
+ );
2773
+ }
2774
+ const { sourceModule, query } = candidates[0]!;
2775
+ const sourceLegs = discoverRelationBootstrapLegs(sourceModule);
2776
+ const sourceDirectives = new Map(
2777
+ (sourceModule.directives as Directive<unknown>[]).map((directive) => [directive.id, directive] as const),
2778
+ );
2779
+ const producerIndex = sourceLegs.findIndex((sourceLeg) => {
2780
+ const directive = sourceDirectives.get(sourceLeg.gatedDirectiveId);
2781
+ return directive !== undefined &&
2782
+ probeEstablishesAggregateTypes(
2783
+ directive,
2784
+ `${sourceModule.domain ?? sourceModule.name}/${directive.id}`,
2785
+ ).has(query.returns);
2786
+ });
2787
+ if (producerIndex < 0) {
2788
+ throw new Error(
2789
+ `${leg.domain}/${leg.gatedDirectiveId}: source query '${trust.queryId}' returns ${query.returns}, but ` +
2790
+ `${sourceModule.domain ?? sourceModule.name} exposes no generated business action that establishes it`,
2791
+ );
2792
+ }
2793
+ const producer = sourceLegs[producerIndex]!;
2794
+ const sourceQueryReturns = new Map(
2795
+ ((sourceModule.queries ?? []) as QueryDecl[]).map((declared) => [declared.id, declared.returns] as const),
2796
+ );
2797
+ // Build the dependency closure, not a source-order prefix. A prefix contains perfectly valid but mutually
2798
+ // exclusive actions (archive before publish, revoke before use) and would turn a business language into one
2799
+ // impossible CRUD script. Dependencies are positive record producers referenced by the action or returned
2800
+ // by its declared reads; born-context roots are already established by the first selected action's birth.
2801
+ const selected = new Set<string>([producer.gatedDirectiveId]);
2802
+ const queue = [producer];
2803
+ while (queue.length > 0) {
2804
+ const consumer = queue.shift()!;
2805
+ const directive = sourceDirectives.get(consumer.gatedDirectiveId);
2806
+ if (directive === undefined) continue;
2807
+ const optionalReferences = new Set(consumer.gatedOptionalReferenceFields ?? []);
2808
+ const neededTypes = new Set([
2809
+ ...Object.entries(consumer.gatedReferenceFields ?? {})
2810
+ .filter(([field]) => !optionalReferences.has(field))
2811
+ .map(([, aggregate]) => aggregate),
2812
+ ...(consumer.gatedDirectiveId === producer.gatedDirectiveId ? (directive.declaredQueryReads ?? []) : []).flatMap((read) => {
2813
+ const returns = sourceQueryReturns.get(read.id);
2814
+ return returns === undefined ? [] : [returns];
2815
+ }),
2816
+ ]);
2817
+ for (const aggregateType of neededTypes) {
2818
+ const alreadySelected = [...selected].some((directiveId) => {
2819
+ if (directiveId === consumer.gatedDirectiveId) return false;
2820
+ const selectedLeg = sourceLegs.find((candidate) => candidate.gatedDirectiveId === directiveId);
2821
+ const selectedDirective = sourceDirectives.get(directiveId);
2822
+ return selectedLeg !== undefined && selectedDirective !== undefined &&
2823
+ (selectedLeg.gatedAggregateId === aggregateType ||
2824
+ probeEstablishesAggregateTypes(
2825
+ selectedDirective,
2826
+ `${sourceModule.domain ?? sourceModule.name}/${selectedDirective.id}`,
2827
+ ).has(aggregateType));
2828
+ });
2829
+ if (alreadySelected) continue;
2830
+ const candidate = sourceLegs
2831
+ .filter((sourceLeg) => sourceLeg.gatedDirectiveId !== consumer.gatedDirectiveId)
2832
+ .map((sourceLeg, index) => ({
2833
+ sourceLeg,
2834
+ index,
2835
+ directive: sourceDirectives.get(sourceLeg.gatedDirectiveId),
2836
+ }))
2837
+ .filter(({ sourceLeg, directive: sourceDirective }) =>
2838
+ sourceDirective !== undefined &&
2839
+ (sourceDirective.marker === "creates" || sourceDirective.marker === "ensures") &&
2840
+ (sourceLeg.gatedAggregateId === aggregateType ||
2841
+ probeEstablishesAggregateTypes(
2842
+ sourceDirective,
2843
+ `${sourceModule.domain ?? sourceModule.name}/${sourceDirective.id}`,
2844
+ ).has(aggregateType)))
2845
+ .sort((left, right) => {
2846
+ const rank = (candidateDirective: Directive<unknown>): number =>
2847
+ candidateDirective.marker === "creates" ? 0 : 1;
2848
+ const primaryRank = (candidate: { sourceLeg: RelationBootstrapLeg }): number =>
2849
+ candidate.sourceLeg.gatedAggregateId === aggregateType ? 0 : 1;
2850
+ return primaryRank(left) - primaryRank(right) ||
2851
+ rank(left.directive!) - rank(right.directive!) ||
2852
+ left.index - right.index;
2853
+ })[0]?.sourceLeg;
2854
+ if (candidate !== undefined && !selected.has(candidate.gatedDirectiveId)) {
2855
+ selected.add(candidate.gatedDirectiveId);
2856
+ queue.push(candidate);
2857
+ }
2858
+ }
2859
+ }
2860
+ const sourceJourney = sourceLegs
2861
+ .filter((sourceLeg) => selected.has(sourceLeg.gatedDirectiveId))
2862
+ .sort((left, right) => {
2863
+ if (left.gatedDirectiveId === producer.gatedDirectiveId) return 1;
2864
+ if (right.gatedDirectiveId === producer.gatedDirectiveId) return -1;
2865
+ return sourceLegs.indexOf(left) - sourceLegs.indexOf(right);
2866
+ });
2867
+ return {
2868
+ ...leg,
2869
+ sourceTrust: {
2870
+ ...trust,
2871
+ sourceDomain: sourceModule.domain ?? sourceModule.name,
2872
+ sourceAggregateId: query.returns,
2873
+ sourceQueryKey: [...query.key],
2874
+ sourceJourney,
2875
+ },
2876
+ };
2877
+ }
2878
+
2425
2879
  /** Build the legs for ONE domain module — every leg it carries (compile-valid always; standalone-provable
2426
2880
  * when it has a `.creates`; child-birth-provable when it has a `.births()`). NEVER null: every compiled
2427
2881
  * domain is at least `compile-valid` (gaps 1+3 — every domain is proof-addressable). */
@@ -2430,6 +2884,7 @@ export function legsForDomain(
2430
2884
  modules: readonly DomainModule[],
2431
2885
  packageInterface?: Readonly<Record<string, DomainInterface>>,
2432
2886
  ): ProofLegs {
2887
+ const executableLaw = mod;
2433
2888
  // Business-birth control declarations are proofed as part of the birth's child genesis, not as
2434
2889
  // tenant-authored standalone/gated actions. Keep the full `modules` below for recipe resolution while
2435
2890
  // removing the presentation-only internals from leg selection and diagnostics.
@@ -2446,7 +2901,7 @@ export function legsForDomain(
2446
2901
  // child-birth-provable), never loses the index.
2447
2902
  let standalone: ProofLegs | null = null;
2448
2903
  try {
2449
- standalone = proofLegsForModule(mod);
2904
+ standalone = proofLegsForModule(mod, packageInterface?.[domain]);
2450
2905
  } catch {
2451
2906
  standalone = null;
2452
2907
  }
@@ -2487,7 +2942,29 @@ export function legsForDomain(
2487
2942
  // MULTI-TARGET (co2 #2): discover one authority leg per gated create/write, not just the first.
2488
2943
  let relationBootstraps: RelationBootstrapLeg[] = [];
2489
2944
  try {
2490
- relationBootstraps = discoverRelationBootstrapLegs(mod);
2945
+ const publicDirectiveIds = new Set(
2946
+ (mod.directives as Directive<unknown>[]).map((directive) => directive.id),
2947
+ );
2948
+ const executableById = new Map(
2949
+ (executableLaw.directives as Directive<unknown>[]).map((directive) => [directive.id, directive] as const),
2950
+ );
2951
+ const unrestrictedBornContext: BornContextAuthority | undefined = childBirthWithSetup === undefined
2952
+ ? undefined
2953
+ : {
2954
+ birthDirectiveId: childBirthWithSetup.birthDirectiveId,
2955
+ birthPayload: childBirthWithSetup.birthPayload,
2956
+ birthAutoStamped: childBirthWithSetup.birthAutoStamped,
2957
+ ...(childBirthWithSetup.birthActorField === undefined ? {} : { ownerField: childBirthWithSetup.birthActorField }),
2958
+ ...(childBirthWithSetup.frameworkHashField === undefined ? {} : { frameworkHashField: childBirthWithSetup.frameworkHashField }),
2959
+ ...(childBirthWithSetup.lawHashField === undefined ? {} : { lawHashField: childBirthWithSetup.lawHashField }),
2960
+ seatsViaDirectiveId: childBirthWithSetup.childSeedDirectiveId ?? "business birth",
2961
+ };
2962
+ relationBootstraps = discoverRelationBootstrapLegs(executableLaw, unrestrictedBornContext)
2963
+ .filter((leg) => publicDirectiveIds.has(leg.gatedDirectiveId))
2964
+ .map((leg) => {
2965
+ const target = executableById.get(leg.gatedDirectiveId);
2966
+ return target === undefined ? leg : attachSourceTrustProofSetup(leg, target, modules);
2967
+ });
2491
2968
  } catch {
2492
2969
  relationBootstraps = [];
2493
2970
  }
@@ -2508,19 +2985,42 @@ export function legsForDomain(
2508
2985
  for (const issue of r.leg?.recipeIssues ?? []) birthDiagnostics.push(`${domain}/${d.id}: ${issue}`);
2509
2986
  }
2510
2987
 
2511
- // PROOF TAXONOMY AUDIT (co2 ask: every creating directive is PROVEN or NAMED-WHY). Walk every `.creates`
2512
- // directive; if it is NOT represented by a proven leg, say exactly why — the synthesis failure names the
2513
- // EXACT unsampleable field path; an attestation/gated create names the lane that DOES prove it.
2988
+ // PROOF TAXONOMY AUDIT. Every PUBLIC business action is executable proof, not merely emitted TypeScript.
2989
+ // This deliberately includes `.ensures` and mutations: silently dropping an unsampleable ensure leaves a
2990
+ // later typed-ref consumer with no producer and turns the framework's omission into an opaque tenant error.
2991
+ // Internal effects remain implementation detail; their published intent is the unit we promise and prove.
2514
2992
  const proofDiagnostics: string[] = [];
2515
- const provenCreateIds = new Set<string>();
2993
+ const provenDirectiveIds = new Set<string>();
2516
2994
  if (standalone !== null) {
2517
- if (standalone.directiveId !== undefined) provenCreateIds.add(standalone.directiveId);
2518
- for (const ec of standalone.extraCreates ?? []) provenCreateIds.add(ec.directiveId);
2995
+ if (standalone.directiveId !== undefined) provenDirectiveIds.add(standalone.directiveId);
2996
+ for (const ec of standalone.extraCreates ?? []) provenDirectiveIds.add(ec.directiveId);
2997
+ }
2998
+ for (const rb of relationBootstraps) provenDirectiveIds.add(rb.gatedDirectiveId);
2999
+ for (const birth of childBirths) provenDirectiveIds.add(birth.birthDirectiveId);
3000
+
3001
+ const publishedIntentIds = new Set((mod.applicationIntents ?? []).map((intent) => intent.id));
3002
+ const diagnosedDirectiveIds = new Set<string>();
3003
+ for (const d of mod.directives as Directive<unknown>[]) {
3004
+ if (!publishedIntentIds.has(d.id) || provenDirectiveIds.has(d.id)) continue;
3005
+ const who = `${domain}/${d.id}`;
3006
+ try {
3007
+ synthesizeDirectivePayload(d, who);
3008
+ proofDiagnostics.push(
3009
+ `${who}: public business action has no generated executable proof — fix its authority, prerequisite, or journey dependency; Nomos will not publish an unexercised tenant method`,
3010
+ );
3011
+ } catch (e) {
3012
+ proofDiagnostics.push(
3013
+ `${who}: public business action could not be generated as an executable example — ${(e as Error)?.message ?? e}`,
3014
+ );
3015
+ }
3016
+ diagnosedDirectiveIds.add(d.id);
2519
3017
  }
2520
- for (const rb of relationBootstraps) provenCreateIds.add(rb.gatedDirectiveId);
3018
+
3019
+ // Retain the lower-level law audit for raw `.creates` effects that are not part of an application language.
3020
+ // Those are framework/law diagnostics; public actions above are a hard executable-surface promise.
2521
3021
  for (const d of mod.directives as Directive<unknown>[]) {
2522
3022
  if (d?.marker !== "creates" || typeof d.payloadSchema !== "object" || d.birthsChild === true) continue;
2523
- if (provenCreateIds.has(d.id)) continue; // proven by some leg — nothing to name
3023
+ if (provenDirectiveIds.has(d.id) || diagnosedDirectiveIds.has(d.id)) continue;
2524
3024
  const who = `${domain}/${d.id}`;
2525
3025
  if (d.attestationAuthorizedGate !== undefined) {
2526
3026
  proofDiagnostics.push(
@@ -2532,15 +3032,22 @@ export function legsForDomain(
2532
3032
  // A gated create with no discoverable authority path (else it would be in provenCreateIds via the
2533
3033
  // relation-bootstrap leg) — name the exact seeding gap (the negative conformance leg still proves the gate).
2534
3034
  const gap = diagnoseRelationBootstrapGap(mod);
2535
- proofDiagnostics.push(gap ?? `${who}: creates ${d.aggregateId} gated by .requires("${d.requiresRelationGate.relation}") — no seedable authority path found; prove it by hand or expose a granter/seed`);
3035
+ proofDiagnostics.push(gap ?? `${who}: creates ${d.aggregateId} gated by .requires("${d.requiresRelationGate.relation}") — no seedable authority path found; expose the business granter/seed so the generated journey can prove it`);
3036
+ continue;
3037
+ }
3038
+ const governingInvariants = (mod.workspaceInvariants ?? []).filter((invariant) => invariant.on === d.id);
3039
+ if (governingInvariants.length > 0) {
3040
+ proofDiagnostics.push(
3041
+ `${who}: creates ${d.aggregateId} under declared policy ${governingInvariants.map((invariant) => `'${invariant.id}'`).join(", ")} — it is state-dependent, so the generator will not pretend it is a standalone CRUD write; add or generate the prerequisite business journey`,
3042
+ );
2536
3043
  continue;
2537
3044
  }
2538
3045
  // An UNGATED standalone create that still isn't proven ⇒ its payload could not be synthesized. Re-run the
2539
3046
  // synthesis to capture the exact-path reason (createLegFor swallowed it to keep the index resilient).
2540
3047
  try {
2541
- synthesizePayload(d.payloadSchema as z.ZodTypeAny, who);
3048
+ synthesizeDirectivePayload(d, who);
2542
3049
  // Synthesis succeeded but the leg was still dropped (e.g. the aggregate isn't composed) — name that.
2543
- proofDiagnostics.push(`${who}: creates ${d.aggregateId} but no offline leg was built (its aggregate '${d.aggregateId}' is not composed in this package, or its create-leg probe failed) — prove it by hand in test/e2e.mts`);
3050
+ proofDiagnostics.push(`${who}: creates ${d.aggregateId} but no generated leg was built (its aggregate '${d.aggregateId}' is not composed in this package, or its create-leg probe failed) — fix the law/generator mismatch; there is no handwritten client-proof lane`);
2544
3051
  } catch (e) {
2545
3052
  proofDiagnostics.push(`${who}: creates ${d.aggregateId} but its payload could not be synthesized for the offline proof — ${(e as Error)?.message ?? e}`);
2546
3053
  }
@@ -2558,6 +3065,7 @@ export function legsForDomain(
2558
3065
  payload: standalone.payload,
2559
3066
  autoStamped: standalone.autoStamped,
2560
3067
  ...(standalone.mintField !== undefined ? { mintField: standalone.mintField } : {}),
3068
+ ...(standalone.ownedEncryption !== undefined ? { ownedEncryption: standalone.ownedEncryption } : {}),
2561
3069
  ...(standalone.query !== undefined ? { query: standalone.query } : {}),
2562
3070
  ...(standalone.count !== undefined ? { count: standalone.count } : {}),
2563
3071
  ...(standalone.spatial !== undefined ? { spatial: standalone.spatial } : {}),
@@ -2615,378 +3123,210 @@ export function proofLegsIndex(
2615
3123
  return { default: def, domains };
2616
3124
  }
2617
3125
 
2618
- // ── shared `.mts` fragments (the v2 contract — G1: no host secret; deploy is OPEN + kernel-gated) ─────────
2619
-
2620
- /**
2621
- * THE LIVE PREAMBLE: `githolon proof --live` has already established the signed session home and deployed
2622
- * this package into it. Generated proof code receives only that ready session and drives the application verb.
2623
- * The old raw create/deploy lane was a second product model and could only create registry/custody orphans.
2624
- */
2625
- function v2IdentityAndCleanupPreamble(opts: TsProofOptions, hashConst: string, n: () => number): string[] {
2626
- void opts;
2627
- void hashConst;
2628
- return [
2629
- `// Nomos prepared an isolated signed application workspace and installed the package before entering generated application code.`,
2630
- `// The application proof supplies business facts only; identity/custody/law selection stay underneath.`,
2631
- `const fail: (m: string) => never = (m) => { throw new Error(m); };`,
2632
- `const ok = (m: string) => console.log("✓ " + m);`,
2633
- `const PRINCIPAL = process.env.NOMOS_PRINCIPAL || "githolon-proof";`,
2634
- `const AUTHOR_SECRET = process.env.NOMOS_AUTHOR_SECRET || "";`,
2635
- ``,
2636
- `let d: any;`,
2637
- `let runError: unknown = null;`,
2638
- `try {`,
2639
- ``,
2640
- `// ${n()}. the one managed entry: an isolated application beneath the logged-in user's durable Nomos home`,
2641
- `if (process.env.NOMOS_PROOF_MANAGED !== "1" || !AUTHOR_SECRET) fail("run this cloud proof through: githolon proof --live");`,
2642
- `ok(\`Nomos application ready — \${WS}\`);`,
2643
- ];
2644
- }
2645
-
2646
- /**
2647
- * The generated cloud proof only owns its application call. Its durable signed home is framework state,
2648
- * so there is no parallel throwaway-provisioning or cleanup protocol to expose here.
2649
- */
2650
- function v2CatchFinally(): string[] {
2651
- return [
2652
- `} catch (e) {`,
2653
- ` runError = e;`,
2654
- ` console.error("✗ " + ((e as Error)?.message ?? e));`,
2655
- `} finally {`,
2656
- ` process.exit(runError ? 1 : 0);`,
2657
- `}`,
2658
- ];
2659
- }
2660
-
2661
- /**
2662
- * THE LIVE CHILD-BIRTH LEG (G3, gap 2): drive the parent `.births()` directive against the cloud workspace,
2663
- * then read the BORN CHILD workspace it spawned (the kernel's offer-effect installs the child law in-chain +
2664
- * folds the child genesis through the child's OWN gate). Verifies the child came up BORN (its read model has
2665
- * the seeded record) — the cloud's offer response surfaces `born: [{workspace, head}]`. The frameworkHash +
2666
- * lawHash are injected from the deployed law (the child install resolves bytes by hash from the parent's
2667
- * custody; a `sample-*` hash would fail). The dispatch rides the gateway offer lane (authenticated principal).
2668
- */
2669
- /**
2670
- * THE LIVE AUTHORITY-CHAIN SEATING for a GATED `.births()` leg (the co2 case). A birth gated by
2671
- * `.requires(R)` needs its actor to HOLD R before the birth admits — and R may itself be reachable only
2672
- * through a RECURSIVE chain of grants (co2: seedPlatformFounder → seedPlatformAdmin [grants co2Admin] →
2673
- * grantCo2EstateCreator [grants co2EstateCreator] → birthEstateWorkspace). This walks the discovered
2674
- * `relationSetup` chain and emits each step as a cloud dispatch under the SAME `birthActor`, seating every
2675
- * relation ON that actor (subject/founder/grantedBy fields overwritten to it) — so one actor plays founder,
2676
- * admin, and creator, ending holding R. Recurses granter-authority-first (deepest prerequisite runs first).
2677
- * `actorVar`/`wsVar` are the runtime var names the birth leg already binds.
2678
- */
2679
- function liveAuthorityChainLines(setup: RelationBootstrapLeg, actorVar: string, wsVar: string): string[] {
2680
- const lines: string[] = [];
2681
- // 1. the granter's OWN authority first (recursive — the deepest prerequisite is seated before its dependents).
2682
- if (setup.granterAuthority !== undefined) {
2683
- lines.push(...liveAuthorityChainLines(setup.granterAuthority, actorVar, wsVar));
2684
- }
2685
- // A runtime dispatch: build the payload literal, overwrite subject/founder/grantedBy/routed fields to the
2686
- // actor (seat the relation ON it), stamp the auto-stamped fields, POST to the parent ws as the actor.
2687
- const dispatch = (
2688
- directiveId: string,
2689
- payload: Record<string, unknown>,
2690
- routed: readonly string[],
2691
- autoStamped: readonly string[],
2692
- label: string,
2693
- ): string[] => {
2694
- const overwrite = new Set<string>(routed);
2695
- const entries = Object.entries(payload).map(([k, v]) =>
2696
- overwrite.has(k) || /^(subject|principal|grantedBy|grantee|member|user|owner|founder)$/i.test(k)
2697
- ? `${JSON.stringify(k)}: ${actorVar}`
2698
- : `${JSON.stringify(k)}: ${JSON.stringify(v)}`,
2699
- );
2700
- return [
2701
- ` {`,
2702
- ` const cp: Record<string, unknown> = { ${entries.join(", ")} };`,
2703
- ...autoStamped.map((f) => ` cp[${JSON.stringify(f)}] = new Date().toISOString();`),
2704
- ` const cr = await fetch(\`\${CLOUD}/v2/workspaces/\${${wsVar}}/${directiveId}\`, { method: "POST", headers: { "content-type": "application/json", "x-nomos-principal": ${actorVar} }, body: JSON.stringify(cp) });`,
2705
- ` const cd = await cr.json();`,
2706
- ` if (!cd.ok) fail(\`authority chain (${label}) ${directiveId} refused: \${JSON.stringify(cd)}\`);`,
2707
- ` ok(\`authority chain — ${directiveId} seated (as \${${actorVar}})\`);`,
2708
- ` }`,
2709
- ];
2710
- };
2711
- // 2. this leg's prerequisite seeds (as the actor = founder).
2712
- for (const seed of setup.prerequisiteSeeds ?? []) {
2713
- lines.push(...dispatch(seed.directiveId, seed.payload, [], seed.autoStamped, "prerequisite"));
2714
- }
2715
- // 3. the grant that seats this leg's relation ON the actor (subject = actor).
2716
- lines.push(
2717
- ...dispatch(
2718
- setup.grantDirectiveId,
2719
- setup.grantPayload,
2720
- [...setup.grantSubjectFields, ...setup.grantGrantedByFields],
2721
- setup.grantAutoStamped,
2722
- "grant",
2723
- ),
2724
- );
2725
- return lines;
2726
- }
2727
-
2728
- function liveBusinessBirthLegLines(cb: ChildBirthLeg, factory: string, n: () => number): string[] {
2729
- const businessPayload = Object.fromEntries(
2730
- Object.entries(cb.birthPayload).filter(([field]) => !["principal", "bornAt", "ownerKeyHash", "birthCert"].includes(field)),
2731
- );
2732
- return [
2733
- `// ${n()}. THE APPLICATION SURFACE: one generated business birth`,
2734
- `{`,
2735
- ` const holon = await connect({ cloud: CLOUD, workspace: WS, clientId: "business-birth-proof", principal: PRINCIPAL, authorSecret: AUTHOR_SECRET });`,
2736
- ` const app = ${factory}(holon, { actor: PRINCIPAL });`,
2737
- ` const facts: Record<string, unknown> = ${JSON.stringify(businessPayload)};`,
2738
- ` const run = Date.now().toString(36) + Math.random().toString(36).slice(2, 8);`,
2739
- ` for (const [field, value] of Object.entries(facts)) {`,
2740
- ` if (typeof value === "string" && value.startsWith("sample-") && value.length > 7) {`,
2741
- ` facts[field] = ("sample-" + run).slice(0, value.length);`,
2742
- ` }`,
2743
- ` }`,
2744
- ` const born = await app.birth(facts as never);`,
2745
- ` const childWs = born.workspace;`,
2746
- ` if (!childWs) fail("app.birth committed without returning the born workspace");`,
2747
- ` ok(\`app.birth(${cb.businessAggregateId}) — business facts became \${childWs}\`);`,
2748
- ` ok("identity, provenance, persistence and recovery verified before app.birth resolved");`,
2749
- ...(cb.childSeedInstanceId !== undefined
2750
- ? [
2751
- ` const restored = await fetch(\`\${CLOUD}/v2/workspaces/\${childWs}/aggregates/\${encodeURIComponent(${JSON.stringify(cb.childSeedInstanceId)})}\`).then((r) => r.json());`,
2752
- ` if (!(restored.rows?.length >= 1)) fail(\`recovered ${cb.businessAggregateId} has no business root: \${JSON.stringify(restored)}\`);`,
2753
- ` ok("business root read back from durable custody");`,
2754
- ]
2755
- : []),
2756
- `}`,
2757
- ``,
2758
- ];
2759
- }
2760
-
2761
- function liveChildBirthLegLines(cb: ChildBirthLeg, opts: TsProofOptions, n: () => number): string[] {
2762
- const hashConst = tsHashConstName(opts.packageName);
2763
- // The birth payload literal: the synthesized values + the REAL hashes onto the discovered fields + the
2764
- // auto-stamped `…At` fields stamped now.
2765
- const lines: string[] = [];
2766
- const setup = cb.parentSetup;
2767
- const actorExpr = (field: string | undefined, payloadVar: string): string | undefined =>
2768
- field !== undefined ? `String(${payloadVar}[${JSON.stringify(field)}] ?? "")` : undefined;
2769
- const birthActorExpr = actorExpr(cb.birthActorField, "birthPayload");
2770
- lines.push(
2771
- `// ${n()}. CHILD BIRTH (G3 — birth is the defined consequence of an offer): drive \`${cb.parentDomain}/${cb.birthDirectiveId}\``,
2772
- `// against the cloud; the kernel's offer-effect installs the child law in-chain + folds the child's`,
2773
- `// genesis (estate/${cb.childSeedDirectiveId}) through the CHILD's own gate, then BORNS the child workspace.`,
2774
- `{`,
2775
- ` const frameworkHashFor = async (workspace: string) => {`,
2776
- ` const st = await (await fetch(\`\${CLOUD}/v2/workspaces/\${workspace}\`)).json().catch(() => ({}));`,
2777
- ` const frameworkHash = st.controller?.domainHash ?? st.controllerHash ?? "";`,
2778
- ` if (!frameworkHash) fail(\`could not resolve the framework controller hash from workspace \${workspace} — needed for the child's in-chain installDomain\`);`,
2779
- ` return frameworkHash;`,
2780
- ` };`,
2781
- ` const birthPayload: Record<string, unknown> = { ...${JSON.stringify(cb.birthPayload)} };`,
2782
- ...(
2783
- birthActorExpr !== undefined && cb.birthRequiresRelation !== undefined
2784
- ? [
2785
- ` const birthActor = ${birthActorExpr};`,
2786
- ` if (!birthActor) fail(${JSON.stringify(`child birth ${cb.parentDomain}/${cb.birthDirectiveId} is gated by .requires("${cb.birthRequiresRelation}") but the proof could not derive an actor from ${cb.birthActorField}`)});`,
2787
- ]
2788
- : [
2789
- ` const birthActor = PRINCIPAL;`,
2790
- ]
2791
- ),
2792
- ...(setup !== undefined
2793
- ? [
2794
- ` // Parent setup: this child birth is gated by authority seeded when the parent workspace is born.`,
2795
- ` const setupPayload: Record<string, unknown> = { ...${JSON.stringify(setup.birthPayload)} };`,
2796
- ...(setup.birthActorField !== undefined && cb.birthActorField !== undefined
2797
- ? [` setupPayload[${JSON.stringify(setup.birthActorField)}] = birthPayload[${JSON.stringify(cb.birthActorField)}];`]
2798
- : []),
2799
- ...(setup.frameworkHashField !== undefined ? [` setupPayload[${JSON.stringify(setup.frameworkHashField)}] = await frameworkHashFor(WS);`] : []),
2800
- ...(setup.lawHashField !== undefined ? [` setupPayload[${JSON.stringify(setup.lawHashField)}] = ${hashConst};`] : []),
2801
- ...setup.birthAutoStamped.map((f) => ` setupPayload[${JSON.stringify(f)}] = new Date().toISOString();`),
2802
- ` const setupActor = ${actorExpr(setup.birthActorField, "setupPayload") ?? "birthActor"} || birthActor;`,
2803
- ` const sr = await fetch(\`\${CLOUD}/v2/workspaces/\${WS}/${setup.birthDirectiveId}\`, { method: "POST", headers: { "content-type": "application/json", "x-nomos-principal": setupActor }, body: JSON.stringify(setupPayload) });`,
2804
- ` const sd = await sr.json();`,
2805
- ` if (!sd.ok) fail(\`parent setup ${setup.parentDomain}/${setup.birthDirectiveId} refused: \${JSON.stringify(sd)}\`);`,
2806
- ` const setupBorn: Array<{ workspace?: string }> = sd.born ?? [];`,
2807
- ` const birthParentWs = setupBorn[0]?.workspace;`,
2808
- ` if (!birthParentWs) fail(\`parent setup admitted but spawned no workspace (born=\${JSON.stringify(setupBorn)})\`);`,
2809
- ` ok(\`parent setup — \${birthParentWs} born by ${setup.parentDomain}/${setup.birthDirectiveId} before gated child birth\`);`,
2810
- ]
2811
- : [
2812
- ` const birthParentWs = WS;`,
2813
- ]),
2814
- ...(cb.frameworkHashField !== undefined
2815
- ? [
2816
- ` // The framework CONTROLLER hash (the bootstrap install-target the child runs as intent 0) — read it`,
2817
- ` // from the workspace's own status (the kernel's controllerHash); the child install resolves the bytes`,
2818
- ` // by hash from the parent's custody, so this MUST be the real framework hash (a guess would fail).`,
2819
- ` birthPayload[${JSON.stringify(cb.frameworkHashField)}] = await frameworkHashFor(birthParentWs);`,
2820
- ]
2821
- : []),
2822
- ` birthPayload[${JSON.stringify(cb.lawHashField ?? "lawHash")}] = ${hashConst};`,
2823
- ...cb.birthAutoStamped.map((f) => ` birthPayload[${JSON.stringify(f)}] = new Date().toISOString();`),
2824
- // GATED BIRTH: seat the FULL authority chain on birthActor before the birth (co2: seedPlatformFounder →
2825
- // seedPlatformAdmin → grantCo2EstateCreator → the birth). Without this the .requires(R) birth is refused.
2826
- ...(cb.relationSetup !== undefined
2827
- ? [
2828
- ` // seat the .requires("${cb.birthRequiresRelation}") authority chain on birthActor before the gated birth:`,
2829
- ...liveAuthorityChainLines(cb.relationSetup, "birthActor", "birthParentWs"),
2830
- ]
2831
- : []),
2832
- ` const br = await fetch(\`\${CLOUD}/v2/workspaces/\${birthParentWs}/${cb.birthDirectiveId}\`, { method: "POST", headers: { "content-type": "application/json", "x-nomos-principal": birthActor }, body: JSON.stringify(birthPayload) });`,
2833
- ` const bd = await br.json();`,
2834
- ` if (!bd.ok) fail(\`child birth offer ${cb.parentDomain}/${cb.birthDirectiveId} refused: \${JSON.stringify(bd)}\`);`,
2835
- ` const born: Array<{ workspace?: string }> = bd.born ?? [];`,
2836
- ` const childWs = born[0]?.workspace;`,
2837
- ` if (!childWs) fail(\`birth admitted but the offer-effect spawned no child (born=\${JSON.stringify(born)})\`);`,
2838
- ` ok(\`child birth — \${childWs} born by ${cb.parentDomain}/${cb.birthDirectiveId} (the offer-effect installed the child law + folded its genesis)\`);`,
2839
- ` // The BORN child runs its OWN law: read the seeded ${cb.childSeedAggregateId ?? "record"} back from the child workspace.`,
2840
- ...(cb.childSeedInstanceId !== undefined
2841
- ? [
2842
- ` const cr = await fetch(\`\${CLOUD}/v2/workspaces/\${childWs}/aggregates/\${encodeURIComponent(${JSON.stringify(cb.childSeedInstanceId)})}\`).then((x) => x.json()).catch(() => ({}));`,
2843
- ` if (!(cr.rows?.length >= 1)) fail(\`the born child did not seed ${cb.childSeedAggregateId ?? "its record"} (${cb.childSeedInstanceId}): \${JSON.stringify(cr)}\`);`,
2844
- ` ok(\`the born child's read model has the genesis seed — ${cb.childSeedDirectiveId} ran inside \${childWs}\`);`,
2845
- ]
2846
- : cb.childQuery !== undefined
2847
- ? [
2848
- ` const cr = await fetch(\`\${CLOUD}/v2/workspaces/\${childWs}/${cb.childQuery.id}?${cb.childQuery.key.map((k) => `${encodeURIComponent(k)}=\${encodeURIComponent(String(birthPayload[${JSON.stringify(k)}] ?? ""))}`).join("&")}\`).then((x) => x.json()).catch(() => ({}));`,
2849
- ` if (!(cr.ok && cr.rows?.length >= 1)) fail(\`the born child's declared query ${cb.childQuery.id} returned nothing: \${JSON.stringify(cr)}\`);`,
2850
- ` ok(\`the born child's declared query ${cb.childQuery.id} returns the genesis seed — ${cb.childSeedDirectiveId} ran inside \${childWs}\`);`,
2851
- ]
2852
- : [
2853
- ` ok(\`the child \${childWs} is born (no declared read on its seed aggregate — declare a query to read it back)\`);`,
2854
- ]),
2855
- `}`,
2856
- ``,
2857
- );
2858
- return lines;
2859
- }
2860
-
2861
3126
  /**
2862
- * THE BIRTH-ONLY PROOF (gap 2): a package whose primary write is a `.births()` directive (no standalone
2863
- * create — the home/estate composable shape). Deploy the parent law, drive the birth, verify the born child.
2864
- * (The offline runner proves the same legs LOCALLY on the vendored wasm — that is the default `githolon
2865
- * proof` lane; this `.mts` is the live `--live` lane.)
3127
+ * The generated file is application documentation, not a kernel conformance harness. Deep authority,
3128
+ * relation, birth-recipe and concurrency legs remain in the metadata-driven local proof runner; the live
3129
+ * TypeScript story uses only the same generated application object tenant code receives.
2866
3130
  */
2867
- function generateBirthOnlyProof(
3131
+ function generateSealedApplicationProof(
2868
3132
  mod: DomainModule,
2869
- modules: readonly DomainModule[],
2870
3133
  opts: TsProofOptions,
2871
3134
  primaryLegs: ProofLegs,
2872
3135
  ): string {
2873
- void modules;
2874
3136
  const domain = mod.domain ?? mod.name;
2875
- const factory = tsClientFactoryName(domain);
2876
- const hashConst = tsHashConstName(opts.packageName);
2877
- const cb = primaryLegs.childBirth;
2878
- if (cb === undefined) {
2879
- throw new Error(
2880
- `domain '${domain}' has a .births() directive but its child-birth leg could not be discovered (the plan did not record a leaf genesis recipe: bootstrap/installDomain → nomos/installDomain → <child>/<seed>) — prove it by hand in test/e2e.mts`,
2881
- );
2882
- }
2883
- const slug =
2884
- opts.packageName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 24) || "domain";
2885
- const legsMarker = JSON.stringify(primaryLegs);
2886
- let step = 0;
2887
- const n = () => ++step;
2888
- const out: string[] = [];
2889
- out.push(
2890
- `// AUTO-GENERATED by nomos-compile — the RUNNABLE PROOF for package "${opts.packageName}",`,
2891
- `// synthesized from the domain's OWN law. This package's primary write is a BIRTH (a .births()`,
2892
- `// directive), so the proof drives the birth end-to-end into the BORN child. Reshape the law,`,
2893
- `// recompile, and this proof reshapes itself — no test rewriting. Run it:`,
2894
- `//`,
2895
- `// npx githolon proof (offline legs on a local holon)`,
2896
- `// npx githolon proof --live (the same application proof in durable Nomos custody)`,
2897
- `//`,
2898
- `// Regenerated on every compile; do not edit.`,
2899
- `// @nomos-proof-legs ${legsMarker}`,
2900
- `import { connect, encodeIntentOfferBytes } from "@githolon/client";`,
2901
- `import { ${factory}, ${hashConst} } from "./${opts.packageName}.client.ts";`,
2902
- `void connect; void encodeIntentOfferBytes; void ${factory};`,
2903
- ``,
2904
- `const CLOUD = (process.env.NOMOS_CLOUD || "https://nomos.captainapp.co.uk").replace(/\\/+$/, "");`,
2905
- `const WS = process.env.NOMOS_WS || ${JSON.stringify(slug + "-proof-")} + Math.random().toString(36).slice(2, 8);`,
2906
- ``,
2907
- ...v2IdentityAndCleanupPreamble(opts, hashConst, n),
2908
- ``,
2909
- ...(cb.businessAggregateId !== undefined
2910
- ? liveBusinessBirthLegLines(cb, factory, n)
2911
- : liveChildBirthLegLines(cb, opts, n)),
2912
- // THE RELATION-BOOTSTRAP LEG (incl. LAYER 4 born-context): a birth-only domain may ALSO carry a gated
2913
- // non-birth directive whose authority is established by the birth genesis (co2 home's updateHomeProfile
2914
- // via birthHome→seedHomeCreator). Emit it so the birth-only proof names it (the born-context proof itself
2915
- // runs in the offline `githolon proof` lane). No-op when the domain has no gated directive.
2916
- ...relationSeedLegsLines(primaryLegs, factory, n, diagnoseRelationBootstrapGap(mod)),
2917
- `console.log(\`\\nALL GREEN — generated proof for "${opts.packageName}": deploy → child birth (\${WS} → the born child) → verified\`);`,
3137
+ const applicationName = tsApplicationName(opts.packageName);
3138
+ const opener = `open${applicationName}`;
3139
+ const marker = JSON.stringify(primaryLegs);
3140
+ const standalone = orderedStandaloneCreates(mod)[0];
3141
+ const businessBirth = primaryLegs.childBirth?.businessAggregateId !== undefined
3142
+ ? primaryLegs.childBirth
3143
+ : undefined;
3144
+ const businessBirthFollowup = businessBirth === undefined
3145
+ ? undefined
3146
+ : (mod.applicationIntents ?? mod.directives).flatMap((candidate) => {
3147
+ const directive = candidate as Directive<unknown>;
3148
+ if (
3149
+ (directive as { businessBirthInternal?: unknown }).businessBirthInternal === true ||
3150
+ (directive as { businessBirth?: unknown }).businessBirth !== undefined ||
3151
+ (directive as { birthsChild?: unknown }).birthsChild === true ||
3152
+ typeof directive.id !== "string" ||
3153
+ typeof directive.aggregateId !== "string" ||
3154
+ Object.keys(aggregateReferenceFields(directive.payloadSchema as z.ZodTypeAny)).length > 0
3155
+ ) return [];
3156
+ const target = (mod.aggregates as AggregateHandle[]).find((aggregate) => aggregate.id === directive.aggregateId);
3157
+ if (target === undefined) return [];
3158
+ try {
3159
+ const synth = synthesizeDirectivePayload(directive, `${domain}/${directive.id}`);
3160
+ const payload = { ...synth.value };
3161
+ const mintField = mintedCreateField(directive, target);
3162
+ if (mintField !== undefined) delete payload[mintField];
3163
+ return [{ directive, target, payload }];
3164
+ } catch {
3165
+ return [];
3166
+ }
3167
+ })[0];
3168
+ const gated = standalone === undefined && businessBirth === undefined && primaryLegs.relationBootstrap !== undefined
3169
+ ? (mod.directives as Directive<unknown>[]).find((directive) => directive.id === primaryLegs.relationBootstrap!.gatedDirectiveId)
3170
+ : undefined;
3171
+ const action = standalone ?? gated;
3172
+ const aggregate = action === undefined
3173
+ ? undefined
3174
+ : (mod.aggregates as AggregateHandle[]).find((candidate) => candidate.id === action.aggregateId);
3175
+ const referenceSeeds = action === undefined ? [] : discoverProofReferenceSeeds(mod, action);
3176
+ const referenceTypes = [...new Set([
3177
+ ...(aggregate === undefined ? [] : [aggregate.id]),
3178
+ ...referenceSeeds.map((seed) => seed.aggregate.id),
3179
+ ...referenceSeeds.flatMap((seed) => Object.values(seed.referenceFields)),
3180
+ ...(action === undefined ? [] : Object.values(aggregateReferenceFields(action.payloadSchema as z.ZodTypeAny))),
3181
+ ])].filter((type) => /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(type)).sort();
3182
+ const typeImports = referenceTypes.length > 0
3183
+ ? `, type NomosRef, ${referenceTypes.map((type) => `type ${type}`).join(", ")}`
3184
+ : "";
3185
+ const refDeclarations = referenceTypes.flatMap((type) => [
3186
+ `let ${proofRefSlot(type)}: NomosRef<${type}> | undefined;`,
3187
+ `const ${proofRefGetter(type)} = (): NomosRef<${type}> => ${proofRefSlot(type)} ?? fail(${JSON.stringify(`generated proof ordering error: NomosRef<${type}> is not available yet`)});`,
3188
+ ]);
3189
+ const out = [
3190
+ `// AUTO-GENERATED by nomos-compile — the canonical application journey for "${opts.packageName}".`,
3191
+ `// Regenerated from the business law; do not edit or maintain a second client example.`,
3192
+ `// The local proof runner executes every deep framework leg without exposing it here.`,
3193
+ `// @nomos-proof-legs ${marker}`,
3194
+ `import { ${opener}, sameRecord${typeImports} } from "./${opts.packageName}.client.mjs";`,
2918
3195
  ``,
2919
- ...v2CatchFinally(),
3196
+ `const fail: (message: string) => never = (message) => { throw new Error(message); };`,
3197
+ `const ok = (message: string) => console.log("✓ " + message);`,
3198
+ `if (process.env.NOMOS_PROOF_MANAGED !== "1") fail("run the live journey through: githolon proof --live");`,
3199
+ `const cloud = (process.env.NOMOS_CLOUD || "https://nomos.captainapp.co.uk").replace(/\\/+$/, "");`,
3200
+ `const applicationName = process.env.NOMOS_APPLICATION || ${JSON.stringify(opts.packageName)};`,
3201
+ `const signIn = async (request: { readonly deviceChallenge?: string } = {}) => {`,
3202
+ ` if (!request.deviceChallenge) return process.env.NOMOS_AUTH_TOKEN || "";`,
3203
+ ` const subject = process.env.NOMOS_PROOF_SUBJECT || "";`,
3204
+ ` if (!subject) fail("the generated blank-user proof has no authority subject");`,
3205
+ ` const response = await fetch(cloud + "/dev/mint-token", {`,
3206
+ ` method: "POST", headers: { "content-type": "application/json" },`,
3207
+ ` body: JSON.stringify({ sub: subject, nonce: request.deviceChallenge }),`,
3208
+ ` });`,
3209
+ ` const body = await response.json() as { token?: string; error?: string };`,
3210
+ ` if (!response.ok || !body.token) fail("the generated application could not attest its private device: " + (body.error || response.status));`,
3211
+ ` return body.token;`,
3212
+ `};`,
3213
+ `const application = await ${opener}({ cloud, application: applicationName, signIn });`,
3214
+ `ok("opened the generated ${applicationName}; identity, custody, recovery and sync stay inside Nomos");`,
3215
+ `const waitUntilSaved = async (): Promise<void> => {`,
3216
+ ` const current = await application.currentStatus();`,
3217
+ ` if (current.phase === "attention") fail(current.message ?? "the application needs attention");`,
3218
+ ` if (current.phase === "current") return;`,
3219
+ ` await new Promise<void>((resolve, reject) => {`,
3220
+ ` const timer = setTimeout(() => { stop(); reject(new Error("the saved application did not become current")); }, 30_000);`,
3221
+ ` const stop = application.watchStatus((status) => {`,
3222
+ ` if (status.phase === "attention") { clearTimeout(timer); stop(); reject(new Error(status.message ?? "the application needs attention")); }`,
3223
+ ` if (status.phase === "current") { clearTimeout(timer); stop(); resolve(); }`,
3224
+ ` });`,
3225
+ ` });`,
3226
+ `};`,
3227
+ ...refDeclarations,
2920
3228
  ``,
2921
- );
2922
- return out.join("\n");
2923
- }
3229
+ ];
2924
3230
 
2925
- /**
2926
- * THE BOOTSTRAP-ONLY PROOF (gated-create isolation): a package whose ONLY creating write is AUTHZ-GATED
2927
- * (`.creates(...).requires(R)` — co2's estate `createSite`). It has no ungated standalone create to dispatch
2928
- * naively (that would be REFUSED at the gate with no seeded authority) and no `.births()` genesis. So the
2929
- * proof deploys the law, connects, and drives the RELATION-BOOTSTRAP leg as its primary write: seed authority
2930
- * (layers 1-3), THEN prove the gated create is ADMITTED — the ordering (seed BEFORE the gated dispatch) is
2931
- * correct by construction. If authority genuinely can't be seeded, the leg emits the loud diagnostic (never a
2932
- * false green). The offline runner proves the same leg locally (`githolon proof`); this `.mts` is `--live`.
2933
- */
2934
- function generateBootstrapOnlyProof(
2935
- mod: DomainModule,
2936
- opts: TsProofOptions,
2937
- primaryLegs: ProofLegs,
2938
- ): string {
2939
- const domain = mod.domain ?? mod.name;
2940
- const factory = tsClientFactoryName(domain);
2941
- const hashConst = tsHashConstName(opts.packageName);
2942
- const rb = primaryLegs.relationBootstrap;
2943
- if (rb === undefined) {
2944
- // Only reached defensively — the caller gates on relationBootstrap !== undefined.
2945
- throw new Error(`domain '${domain}' has a gated create but no relation-bootstrap leg to prove it (no seedable authority)`);
2946
- }
2947
- const slug =
2948
- opts.packageName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 24) || "domain";
2949
- const legsMarker = JSON.stringify(primaryLegs);
2950
- let step = 0;
2951
- const n = () => ++step;
2952
- const out: string[] = [];
3231
+ if (businessBirth !== undefined) {
3232
+ const businessPayload = Object.fromEntries(
3233
+ Object.entries(businessBirth.birthPayload).filter(([field]) => !["principal", "bornAt", "ownerKeyHash", "birthCert"].includes(field)),
3234
+ );
3235
+ out.push(
3236
+ `const facts = ${JSON.stringify(businessPayload)};`,
3237
+ `const born = await application.birth(facts);`,
3238
+ `if (born === undefined) fail("business birth returned no child application");`,
3239
+ `await waitUntilSaved();`,
3240
+ `ok(${JSON.stringify(`birth(${businessBirth.businessAggregateId}) saved through the generated application`)});`,
3241
+ );
3242
+ if (businessBirthFollowup !== undefined) {
3243
+ const { directive, target, payload } = businessBirthFollowup;
3244
+ const resultMember = proofResultMember(target.id);
3245
+ const collection = generatedAggregateCollectionName(target.id);
3246
+ out.push(
3247
+ `const childResult = await born.${directive.id}(${JSON.stringify(payload)});`,
3248
+ `const childReference = childResult.${resultMember};`,
3249
+ `const childRecord = await born.${collection}.find(childReference);`,
3250
+ `if (childRecord === undefined) fail(${JSON.stringify(`the born application could not read its ${target.id} consequence`)});`,
3251
+ `ok(${JSON.stringify(`${directive.id} changed the born ${businessBirth.businessAggregateId} application through generated business code`)});`,
3252
+ );
3253
+ }
3254
+ } else if (action !== undefined && aggregate !== undefined) {
3255
+ for (const seed of referenceSeeds) {
3256
+ const payload = typedPayloadLiteral(seed.payload, seed.referenceFields);
3257
+ const variable = `seed${proofTypeIdent(seed.aggregate.id)}`;
3258
+ out.push(
3259
+ `const ${variable}Result = await application.${seed.directive.id}(${payload});`,
3260
+ `const ${variable}Ref = ${variable}Result.${proofResultMember(seed.aggregate.id)};`,
3261
+ `${proofRefSlot(seed.aggregate.id)} = ${variable}Ref;`,
3262
+ );
3263
+ }
3264
+ const synth = synthesizeDirectivePayload(action, `${domain}/${action.id}`);
3265
+ const refs = aggregateReferenceFields(action.payloadSchema as z.ZodTypeAny);
3266
+ const mintField = mintedCreateField(action, aggregate);
3267
+ const payload = { ...synth.value };
3268
+ if (mintField !== undefined) delete payload[mintField];
3269
+ const payloadLiteral = typedPayloadLiteral(payload, refs);
3270
+ const nullArmLines = nullablePayloadFields(action.payloadSchema as z.ZodTypeAny).flatMap((field) => {
3271
+ const nullPayload = { ...payload, [field]: null };
3272
+ return [
3273
+ `await application.${action.id}(${typedPayloadLiteral(nullPayload, refs)});`,
3274
+ `ok(${JSON.stringify(`NULL-ARM PROOF — ${domain}/${action.id} accepted ${field}=null`)});`,
3275
+ ];
3276
+ });
3277
+ const clearLegs = Object.entries(aggregate.fields as Record<string, Field>)
3278
+ .filter(([, field]) => field.isClearable === true)
3279
+ .map(([field]) => ({
3280
+ field,
3281
+ directiveId: clearDirectiveId(aggregate.id, field),
3282
+ }))
3283
+ .filter(({ directiveId }) => {
3284
+ const directive = (mod.directives as Directive<unknown>[]).find((candidate) => candidate.id === directiveId);
3285
+ return directive !== undefined
3286
+ && (directive as { requiresRelationGate?: unknown }).requiresRelationGate === undefined;
3287
+ });
3288
+ const aggregateCollection = generatedAggregateCollectionName(aggregate.id);
3289
+ const clearWriteLines = clearLegs.flatMap(({ field, directiveId }) => [
3290
+ `await application.${directiveId}({ id: created });`,
3291
+ `ok(${JSON.stringify(`CLEAR-LANE PROOF — ${domain}/${directiveId} accepted the typed ${aggregate.id} reference`)});`,
3292
+ ]);
3293
+ const clearReadLines = clearLegs.flatMap(({ field }) => [
3294
+ `const cleared${proofTypeIdent(field)} = await application.${aggregateCollection}.find(created);`,
3295
+ `if (cleared${proofTypeIdent(field)}?.[${JSON.stringify(field)}] !== null) fail(${JSON.stringify(`CLEAR-LANE PROOF — ${aggregate.id}.${field} did not read back as explicit null`)});`,
3296
+ ]);
3297
+ out.push(
3298
+ `const result = await application.${action.id}(${payloadLiteral});`,
3299
+ `const created = result.${proofResultMember(aggregate.id)};`,
3300
+ `${proofRefSlot(aggregate.id)} = created;`,
3301
+ `ok(${JSON.stringify(`${domain}/${action.id} accepted business facts and returned a typed reference`)});`,
3302
+ ...nullArmLines,
3303
+ ...clearWriteLines,
3304
+ `await waitUntilSaved();`,
3305
+ ...clearReadLines,
3306
+ `const reopened = await ${opener}({ cloud, application: applicationName, signIn });`,
3307
+ `const rows = await reopened.${generatedAggregateCollectionName(aggregate.id)}.all();`,
3308
+ `if (!rows.some((row) => sameRecord(row.ref, created))) fail("a fresh generated application could not read the saved record");`,
3309
+ `ok("a fresh generated application read the saved record after synchronization");`,
3310
+ );
3311
+ } else {
3312
+ out.push(
3313
+ `const status = await application.currentStatus();`,
3314
+ `if (status.phase === "attention") fail(status.message || "the generated application needs attention");`,
3315
+ `ok("the generated application opened and verified its durable local state");`,
3316
+ );
3317
+ }
2953
3318
  out.push(
2954
- `// AUTO-GENERATED by nomos-compile — the RUNNABLE PROOF for package "${opts.packageName}",`,
2955
- `// synthesized from the domain's OWN law. This package's ONLY creating write is AUTHZ-GATED`,
2956
- `// (\`${domain}/${rb.gatedDirectiveId}\` .requires("${rb.relation}")), so the proof SEEDS authority first,`,
2957
- `// then proves the gated create is admitted — never a naive dispatch the gate would refuse. Reshape the`,
2958
- `// law, recompile, and this proof reshapes itself — no test rewriting. Run it:`,
2959
- `//`,
2960
- `// npx githolon proof (offline legs on a local holon)`,
2961
- `// npx githolon proof --live (the same application proof in durable Nomos custody)`,
2962
- `//`,
2963
- `// Regenerated on every compile; do not edit.`,
2964
- `// @nomos-proof-legs ${legsMarker}`,
2965
- `import { readFileSync } from "node:fs";`,
2966
- `import { connect, encodeIntentOfferBytes } from "@githolon/client";`,
2967
- `import { ${factory}, ${hashConst} } from "./${opts.packageName}.client.ts";`,
2968
- `void connect; void encodeIntentOfferBytes; void ${factory};`,
2969
- ``,
2970
- `const CLOUD = (process.env.NOMOS_CLOUD || "https://nomos.captainapp.co.uk").replace(/\\/+$/, "");`,
2971
- `const WS = process.env.NOMOS_WS || ${JSON.stringify(slug + "-proof-")} + Math.random().toString(36).slice(2, 8);`,
2972
- ``,
2973
- ...v2IdentityAndCleanupPreamble(opts, hashConst, n),
2974
- ``,
2975
- `// ${n()}. connect + bind the GENERATED typed client (the relation-bootstrap leg drives it with an actor)`,
2976
- `const holon = await connect({ cloud: CLOUD, workspace: WS, clientId: "proof-1", principal: PRINCIPAL, authorSecret: AUTHOR_SECRET });`,
2977
- `ok(\`web client connected — ${factory} bound (replica \${holon.replica.slice(0, 6)}…)\`);`,
2978
- ``,
2979
- // The SAME relation-bootstrap emitter the standalone proof uses — seed authority, then prove the GATED
2980
- // CREATE is admitted (layers 1-3; a speculative seed-path degrades to a diagnostic, never a false green).
2981
- ...relationSeedLegLines(rb, factory, n),
2982
- `console.log(\`\\nALL GREEN — generated proof for "${opts.packageName}": deploy → seed authority → gated create ${rb.gatedDirectiveId} admitted (\${WS})\`);`,
2983
- ``,
2984
- ...v2CatchFinally(),
3319
+ `console.log(${JSON.stringify(`\nALL GREEN — ${opts.packageName} used only its generated application surface`)});`,
3320
+ `const _proofDisposable = application as unknown as { [Symbol.asyncDispose]?: () => Promise<void> };`,
3321
+ `const _proofDispose = _proofDisposable[Symbol.asyncDispose];`,
3322
+ `if (_proofDispose) await Promise.race([_proofDispose(), new Promise<void>((resolve) => setTimeout(resolve, 1_000))]);`,
3323
+ `process.exit(0);`,
2985
3324
  ``,
2986
3325
  );
2987
3326
  return out.join("\n");
2988
3327
  }
2989
3328
 
3329
+
2990
3330
  export function generateTsProof(modules: readonly DomainModule[], opts: TsProofOptions): string {
2991
3331
  // PRIMARY-DOMAIN SELECTION: a declared BUSINESS birth is always first because `proof --live` promises the
2992
3332
  // product's one `app.birth(facts)` surface, not a convenient auxiliary create from the same law. Without
@@ -2997,7 +3337,7 @@ export function generateTsProof(modules: readonly DomainModule[], opts: TsProofO
2997
3337
  (d) => (d as { businessBirth?: unknown }).businessBirth !== undefined,
2998
3338
  );
2999
3339
  const hasStandaloneCreate = (m: DomainModule): boolean =>
3000
- (m.directives as Directive<unknown>[]).some((d) => isStandaloneCreate(d));
3340
+ orderedStandaloneCreates(m).length > 0;
3001
3341
  const hasBirth = (m: DomainModule): boolean => hasBirthDirective(m);
3002
3342
  const isBootstrapProvable = (m: DomainModule): boolean => {
3003
3343
  try {
@@ -3018,376 +3358,12 @@ export function generateTsProof(modules: readonly DomainModule[], opts: TsProofO
3018
3358
  throw new Error(
3019
3359
  gap !== undefined
3020
3360
  ? `no proof could be synthesized: ${gap}`
3021
- : `no .creates directive in any domain — a generated proof needs one creating write (or a .births() birth directive); add a directive(...).creates(...) (test/e2e.mts remains the hand-authored lane)`,
3361
+ : `no .creates/.ensures directive in any domain — a generated proof needs one business write (or a .births() birth directive); add a business action that creates or ensures a record so the canonical generated journey can exist`,
3022
3362
  );
3023
3363
  }
3024
- const domain = mod.domain ?? mod.name;
3025
- const factory = tsClientFactoryName(domain);
3026
- const hashConst = tsHashConstName(opts.packageName);
3027
3364
  // THE MARKER (since 0.5.0) + the per-domain index are ONE synthesis (`legsForDomain`) — the proof body, its
3028
3365
  // marker, and the index can never describe different directives. The primary domain's legs carry whichever
3029
3366
  // of standalone / child-birth / relation-bootstrap it has.
3030
3367
  const primaryLegs = legsForDomain(mod, modules, opts.interface);
3031
- const childBirth = primaryLegs.childBirth;
3032
-
3033
- // A business-birth domain may also contain `addSite`-style standalone creates. Those are useful secondary
3034
- // verbs, but they must never steal the live acceptance proof from the one public application birth.
3035
- if (childBirth?.businessAggregateId !== undefined) {
3036
- return generateBirthOnlyProof(mod, modules, opts, primaryLegs);
3037
- }
3038
-
3039
- // The standalone-create lane needs an UNGATED create (isStandaloneCreate — never a gated/birth/attestation
3040
- // create, which the gate would refuse dispatched with no seeded authority). Absent one, the primary write
3041
- // is the birth leg (a `.births()` domain) or the relation-bootstrap leg (a gated-create domain).
3042
- const createDir = (mod.directives as Directive<unknown>[]).find((d) => isStandaloneCreate(d));
3043
- if (createDir === undefined) {
3044
- // BIRTH-ONLY PRIMARY: emit a birth-shaped proof (the birth replays genesis, seating authority, then the
3045
- // born child self-validates — a gated child-domain create is proven INSIDE the born child context).
3046
- if (primaryLegs.childBirth !== undefined) return generateBirthOnlyProof(mod, modules, opts, primaryLegs);
3047
- // BOOTSTRAP-ONLY PRIMARY: the only creating write is GATED — deploy, then seed authority + prove the
3048
- // gated create is admitted (the relation-bootstrap leg is its ONLY positive proof).
3049
- if (primaryLegs.relationBootstrap !== undefined) return generateBootstrapOnlyProof(mod, opts, primaryLegs);
3050
- // A gated create with no seedable authority: loud diagnostic (compile skips the proof, law still ships).
3051
- const gap = diagnoseRelationBootstrapGap(mod);
3052
- throw new Error(gap !== undefined ? `no proof could be synthesized for '${domain}': ${gap}` : `domain '${domain}' has no provable creating write`);
3053
- }
3054
- const agg = (mod.aggregates as AggregateHandle[]).find((a) => a.id === createDir.aggregateId);
3055
- if (agg === undefined) {
3056
- throw new Error(
3057
- `directive '${createDir.id}' creates '${createDir.aggregateId}' but no such aggregate is composed — export the aggregate from a listed module`,
3058
- );
3059
- }
3060
- const synth = synthesizePayload(createDir.payloadSchema as z.ZodTypeAny, `${domain}/${createDir.id}`);
3061
-
3062
- // THE MINTED-ID RULE (the gate's `check_create_ids`): a `.creates` payload field
3063
- // that IS the target's own id must be KERNEL-MINTED — a hand-written sample id
3064
- // refuses typed at admission (`NotMinted`). The marker-driven trace names the
3065
- // field (never name-guessed); the generated proof MINTS it at runtime
3066
- // (`holon.mint`) instead of synthesizing a sample, so the proof admits
3067
- // everywhere the law does.
3068
- const mintField = mintedCreateField(createDir, agg);
3069
- const baseValue: Record<string, unknown> = { ...synth.value };
3070
- if (mintField !== undefined) delete baseValue[mintField];
3071
-
3072
- // The first declared query that can READ BACK the create: returns the created
3073
- // aggregate and every key field has a synthesized payload value to probe with
3074
- // (a query keyed on the MINTED field is skipped — its value exists only at runtime).
3075
- const query = ((mod.queries ?? []) as QueryDecl[]).find(
3076
- (q) => q.returns === agg.id && q.key.length > 0 && q.key.every((k) => !k.includes(".") && baseValue[k] !== undefined),
3077
- );
3078
-
3079
- // The first declared count the create moves: counts the created aggregate,
3080
- // unpredicated (a .where can't be evaluated at codegen time), and — when
3081
- // grouped — grouped by a field the synthesized payload carries.
3082
- const count = (mod.counts ?? [])
3083
- .map((raw) => finishCount(raw))
3084
- .find(
3085
- (c) =>
3086
- c.of === agg.id &&
3087
- (c as { where?: unknown }).where == null &&
3088
- (c.by == null || baseValue[c.by] !== undefined),
3089
- );
3090
-
3091
- const concurrency = findConcurrencyLeg(mod.directives as Directive<unknown>[], agg);
3092
-
3093
- // THE AUTHORITY-CONFORMANCE LEG (the one-encoder + gate proof): the first gated (`.requires(...)`) directive
3094
- // in the primary domain, proven locally — actor threads through the one encoder; an actorless gated offer
3095
- // throws MissingOfferAuthority. `undefined` ⇒ a documented no-op (the domain authors openly).
3096
- const conformance = discoverAuthorityConformanceLeg({
3097
- ...mod,
3098
- directives: (mod.directives as Directive<unknown>[]).filter(
3099
- (d) => (d as { businessBirthInternal?: unknown }).businessBirthInternal !== true,
3100
- ),
3101
- });
3102
-
3103
- // THE RELATION-BOOTSTRAP LEG (the seed-then-prove positive): grant relation R to the proof actor, then prove
3104
- // a `.requires(R)`-gated write SUCCEEDS under that actor. `undefined` ⇒ no gated directive or no discoverable
3105
- // granter (the negative conformance leg still runs). Comes from the SAME `legsForDomain` synthesis (marker).
3106
- // Workspace-name slug: any package name → a safe, recognizable ws prefix.
3107
- const slug =
3108
- opts.packageName
3109
- .toLowerCase()
3110
- .replace(/[^a-z0-9]+/g, "-")
3111
- .replace(/^-+|-+$/g, "")
3112
- .slice(0, 24) || "domain";
3113
-
3114
- const payloadLit =
3115
- mintField !== undefined
3116
- ? `{ ...${JSON.stringify(baseValue)}, ${JSON.stringify(mintField)}: __minted }`
3117
- : JSON.stringify(baseValue);
3118
- const queryParamsObj = query ? Object.fromEntries(query.key.map((k) => [k, baseValue[k]])) : undefined;
3119
- const queryParams = queryParamsObj ? JSON.stringify(queryParamsObj) : "";
3120
- // The gateway routes a declared query by its id: GET /v2/workspaces/<ws>/<queryId>?<key>=<val>
3121
- // (the host reads each declared key from the querystring — never a generic /query?params= lane).
3122
- const queryQs =
3123
- query && queryParamsObj
3124
- ? query.key.map((k) => `${encodeURIComponent(k)}=${encodeURIComponent(String(queryParamsObj[k]))}`).join("&")
3125
- : "";
3126
- const listAccessor = `list${agg.id}s`;
3127
-
3128
- // THE MACHINE-READABLE LEGS (parsed by `githolon`'s offline proof runner —
3129
- // cli/src/proof_offline.ts). The ONE leg-synthesis (`legsForDomain`) feeds
3130
- // both this marker and the per-domain `proof-legs.json` index, so they never drift.
3131
- const legsMarker = JSON.stringify(primaryLegs);
3132
-
3133
- let step = 0;
3134
- const n = () => ++step;
3135
- const out: string[] = [];
3136
-
3137
- out.push(
3138
- `// AUTO-GENERATED by nomos-compile — the RUNNABLE PROOF for package "${opts.packageName}",`,
3139
- `// synthesized from the domain's OWN directives/queries/counts. Reshape the law,`,
3140
- `// recompile, and this proof reshapes itself — no test rewriting. Run it:`,
3141
- `//`,
3142
- `// npx githolon proof (or: npx tsx build/${opts.packageName}.proof.mts)`,
3143
- `//`,
3144
- `// The flow mirrors the scaffold's test/e2e.mts (docs/ in a scaffolded app explains`,
3145
- `// every call — start at docs/01-mental-model.md). Regenerated on every compile; do not edit.`,
3146
- `// @nomos-proof-legs ${legsMarker}`,
3147
- `import { connect, encodeIntentOfferBytes } from "@githolon/client";`,
3148
- `import { ${factory}, ${hashConst} } from "./${opts.packageName}.client.ts";`,
3149
- ``,
3150
- `const CLOUD = (process.env.NOMOS_CLOUD || "https://nomos.captainapp.co.uk").replace(/\\/+$/, "");`,
3151
- `const WS = process.env.NOMOS_WS || ${JSON.stringify(slug + "-proof-")} + Math.random().toString(36).slice(2, 8);`,
3152
- ``,
3153
- ...v2IdentityAndCleanupPreamble(opts, hashConst, n),
3154
- ``,
3155
- `// ${n()}. connect + bind the GENERATED typed client`,
3156
- `const holon = await connect({ cloud: CLOUD, workspace: WS, clientId: "proof-1", principal: PRINCIPAL, authorSecret: AUTHOR_SECRET });`,
3157
- `const app = ${factory}(holon);`,
3158
- `ok(\`web client connected — ${factory} bound (replica \${holon.replica.slice(0, 6)}…)\`);`,
3159
- ``,
3160
- `// ${n()}. OFFLINE write — the proof is ENFORCED, not narrated: while we author and`,
3161
- `// read LOCALLY, fetch THROWS. The payload below was SYNTHESIZED from the zod`,
3162
- `// schema of \`${domain}/${createDir.id}\`${synth.autoStamped.length ? ` (${synth.autoStamped.map((s) => `\`${s}\``).join("/")} omitted — the client auto-stamps ISO now())` : ``}.`,
3163
- `const realFetch = globalThis.fetch;`,
3164
- `globalThis.fetch = (() => { throw new Error("OFFLINE PROOF VIOLATED: local authoring touched the network"); }) as typeof fetch;`,
3165
- ``,
3166
- ...(mintField !== undefined
3167
- ? [
3168
- `// the target's own id is KERNEL-MINTED (never hand-written — the gate's`,
3169
- `// check_create_ids refuses sample ids typed): the local wasm mints, the id`,
3170
- `// rides the payload, replay reads the capture.`,
3171
- `const __minted = await holon.mint(${JSON.stringify(agg.id)});`,
3172
- ]
3173
- : []),
3174
- `await app.${createDir.id}(${payloadLit});`,
3175
- `ok("dispatch ${domain}/${createDir.id} — offline write under the pulled law (payload synthesized from YOUR schema${mintField !== undefined ? `; \`${mintField}\` kernel-minted` : ``})");`,
3176
- ``,
3177
- );
3178
-
3179
- if (query) {
3180
- out.push(
3181
- `// ${n()}. the first declared query routes LOCALLY (params from the synthesized payload)`,
3182
- `const rows = await app.${lcFirst(camel(query.id))}(${queryParams});`,
3183
- `if (rows.length !== 1) fail(\`local declared query ${query.id}: \${JSON.stringify(rows)}\`);`,
3184
- `const createdId = rows[0]!.id;`,
3185
- `ok(\`declared query ${query.id} answers locally — ${agg.id} \${createdId}\`);`,
3186
- ``,
3187
- );
3188
- } else {
3189
- out.push(
3190
- `// ${n()}. no declared query reads this create back (declare a query(...) keyed on a`,
3191
- `// payload field to see one proved here) — the type-index probe captures the id.`,
3192
- `const rows = await app.${listAccessor}();`,
3193
- `if (rows.length !== 1) fail(\`local ${listAccessor}: \${JSON.stringify(rows)}\`);`,
3194
- `const createdId = rows[0]!.id;`,
3195
- `console.log("– declared-query leg SKIPPED — no query(...) returns ${agg.id} keyed on a synthesized payload field");`,
3196
- `ok(\`local read answers — ${agg.id} \${createdId}\`);`,
3197
- ``,
3198
- );
3199
- }
3200
-
3201
- if (count) {
3202
- const accessor = lcFirst(camel(count.id));
3203
- const callArg = count.by != null ? JSON.stringify(String(baseValue[count.by])) : "";
3204
- out.push(
3205
- `// ${n()}. the first declared count — the maintained O(1) tally, locally`,
3206
- `const localCount = await app.${accessor}(${callArg});`,
3207
- `if (localCount !== 1) fail(\`local declared count ${count.id}: \${localCount}\`);`,
3208
- `ok("declared count ${count.id}${count.by != null ? `(${callArg.replace(/"/g, "'")})` : `()`} = 1 locally");`,
3209
- ``,
3210
- );
3211
- }
3212
-
3213
- // NULL SEMANTICS BOTH-ARM PROOF (null_semantics.md): the primary dispatch above already proved the
3214
- // VALUE arm (a nullable field synthesizes to a sampled value); here we prove the NULL arm — the law
3215
- // ADMITS an explicit `null` for each nullable field, so it is provably total over null. Each create
3216
- // arm mints a fresh id. Empty for a null-free payload (byte-identical proof).
3217
- const nullArms = nullablePayloadFields(createDir.payloadSchema as z.ZodTypeAny);
3218
- for (const field of nullArms) {
3219
- const armMint = mintField !== undefined ? `, ${JSON.stringify(mintField)}: await holon.mint(${JSON.stringify(agg.id)})` : "";
3220
- out.push(
3221
- `// ${n()}. NULL-ARM PROOF — \`${field}\` is nullable: the law must ADMIT an explicit null (both arms proven).`,
3222
- `try {`,
3223
- ` await app.${createDir.id}({ ...${JSON.stringify(baseValue)}${armMint}, ${JSON.stringify(field)}: null });`,
3224
- ` ok(${JSON.stringify(`null-arm — ${domain}/${createDir.id} admitted with \`${field}\`=null (the law handles the explicit-null arm)`)});`,
3225
- `} catch (e) {`,
3226
- ` fail(\`null-arm ${field}=null was REFUSED — a nullable field's null arm must be admitted: \${(e as Error).message}\`);`,
3227
- `}`,
3228
- ``,
3229
- );
3230
- }
3231
-
3232
- // CLEAR-LANE PROOF (null_semantics.md): a `t.clearable(...)` field's compose-injected clear directive
3233
- // (`clearDirectiveId(agg, field)`) LOWERS to a Set of json null — dispatch it on the created instance
3234
- // and read the field back as null (ExplicitNull). Only UN-GATED clear directives (the proof binds no
3235
- // actor); a gated clear needs authority the negative/positive gate legs already cover. Empty for a
3236
- // clearable-free aggregate (byte-identical proof).
3237
- const clearLegs = Object.entries(agg.fields as Record<string, Field>)
3238
- .filter(([, f]) => f.isClearable === true)
3239
- .map(([field]) => ({ field, dirId: clearDirectiveId(agg.id, field) }))
3240
- .filter(({ dirId }) => {
3241
- const cd = (mod.directives as Directive<unknown>[]).find((d) => d.id === dirId);
3242
- return cd !== undefined && (cd as { requiresRelationGate?: unknown }).requiresRelationGate === undefined;
3243
- });
3244
- for (const { field, dirId } of clearLegs) {
3245
- out.push(
3246
- `// ${n()}. CLEAR-LANE PROOF — \`${field}\` is clearable: \`${dirId}\` lowers to Set(json null); after it,`,
3247
- `// the field reads back null (ExplicitNull), never omitted.`,
3248
- `try {`,
3249
- ` await app.${dirId}({ id: createdId });`,
3250
- `} catch (e) {`,
3251
- ` fail(\`clear-lane ${dirId} was REFUSED — an un-gated clear of a clearable field must be admitted: \${(e as Error).message}\`);`,
3252
- `}`,
3253
- `{`,
3254
- ` const clearedRows = await holon.queryById(createdId) as { data?: Record<string, unknown> }[];`,
3255
- ` const clearedRow = clearedRows[0];`,
3256
- ` if (clearedRow !== undefined && clearedRow.data !== undefined && clearedRow.data[${JSON.stringify(field)}] != null) {`,
3257
- ` fail(\`clear-lane ${field}: expected null after clear, got \${JSON.stringify(clearedRow.data[${JSON.stringify(field)}])}\`);`,
3258
- ` }`,
3259
- ` ok(${JSON.stringify(`clear-lane — ${domain}/${dirId} admitted; \`${field}\` reads back null (ExplicitNull)`)});`,
3260
- `}`,
3261
- ``,
3262
- );
3263
- }
3264
-
3265
- out.push(
3266
- `globalThis.fetch = realFetch;`,
3267
- `ok("offline proof ENFORCED — fetch was trapped: local write/read touched no network");`,
3268
- ``,
3269
- `// ${n()}. sync: push the session branch; edge admission re-verifies and merges to main`,
3270
- `const s = await holon.sync();`,
3271
- `if (!s.admission?.ok) fail(\`sync/admit: \${JSON.stringify(s)}\`);`,
3272
- `const admitted = (s.admission.sessions || []).flatMap((x: { admitted?: unknown[] }) => x.admitted || []);`,
3273
- `if (admitted.length < 1) fail(\`edge admitted \${admitted.length} intent(s): \${JSON.stringify(s.admission)}\`);`,
3274
- `ok(\`synced — edge admission merged \${admitted.length} intent(s) to main\`);`,
3275
- ``,
3276
- );
3277
-
3278
- if (query) {
3279
- out.push(
3280
- `// ${n()}. the CLOUD answers the SAME declared query — routed by the workspace's OWN OpenAPI`,
3281
- `// (GET /v2/workspaces/<ws>/${query.id}?${queryQs}); the host learns the route from the law's spec.`,
3282
- `d = await (await fetch(\`\${CLOUD}/v2/workspaces/\${WS}/${query.id}${queryQs ? `?${queryQs}` : ``}\`)).json();`,
3283
- `if (!(d.ok && d.rows.length === 1 && d.rows[0].id === createdId)) fail(\`cloud declared query: \${JSON.stringify(d)}\`);`,
3284
- `ok("cloud declared query ${query.id} returns the admitted row — full loop closed");`,
3285
- ``,
3286
- );
3287
- } else {
3288
- out.push(
3289
- `// ${n()}. the CLOUD answers the by-id read (edge projection of the admitted write)`,
3290
- `d = await (await fetch(\`\${CLOUD}/v2/workspaces/\${WS}/aggregates/\${encodeURIComponent(createdId)}\`)).json();`,
3291
- `if (!(d.rows?.length === 1 && d.rows[0].id === createdId)) fail(\`cloud by-id read: \${JSON.stringify(d)}\`);`,
3292
- `ok("cloud read returns the admitted row — full loop closed");`,
3293
- ``,
3294
- );
3295
- }
3296
-
3297
- if (count) {
3298
- out.push(
3299
- `// ${n()}. the EDGE maintains the same count (same wasm, same law)`,
3300
- `d = await (await fetch(\`\${CLOUD}/v2/workspaces/\${WS}/${count.id}${count.by != null ? `?group=\${encodeURIComponent(${JSON.stringify(String(baseValue[count.by]))})}` : ``}\`)).json();`,
3301
- `if (!(d.ok && d.count === 1)) fail(\`cloud count ${count.id}: \${JSON.stringify(d)}\`);`,
3302
- `ok("cloud count ${count.id} = 1 — the O(1) maintained read, at the edge too");`,
3303
- ``,
3304
- );
3305
- }
3306
-
3307
- if (concurrency) {
3308
- const { directive: cd, idField, setField } = concurrency;
3309
- const cSynth = synthesizePayload(cd.payloadSchema as z.ZodTypeAny, `${domain}/${cd.id}`);
3310
- const concPayload = (writer: string): string => {
3311
- const entries = Object.entries({ ...cSynth.value, [idField]: 0, [setField]: 0 }).map(([k]) => {
3312
- if (k === idField) return `${JSON.stringify(k)}: createdId`;
3313
- if (k === setField) return `${JSON.stringify(k)}: ${JSON.stringify([`proof-${writer}`])}`;
3314
- return `${JSON.stringify(k)}: ${JSON.stringify(cSynth.value[k])}`;
3315
- });
3316
- return `{ ${entries.join(", ")} }`;
3317
- };
3318
- out.push(
3319
- `// ${n()}. CONCURRENCY — two writers, two clientIds, BLIND to each other: each adds to`,
3320
- `// the AddWins set \`${agg.id}.${setField}\` via \`${domain}/${cd.id}\` offline; admission`,
3321
- `// merges both and the union keeps every add.`,
3322
- `const writerA = await connect({ cloud: CLOUD, workspace: WS, clientId: "proof-a", principal: PRINCIPAL, authorSecret: AUTHOR_SECRET });`,
3323
- `const writerB = await connect({ cloud: CLOUD, workspace: WS, clientId: "proof-b", principal: PRINCIPAL, authorSecret: AUTHOR_SECRET });`,
3324
- `await ${factory}(writerA).${cd.id}(${concPayload("a")});`,
3325
- `await ${factory}(writerB).${cd.id}(${concPayload("b")});`,
3326
- `await writerA.sync();`,
3327
- `await writerB.sync();`,
3328
- `d = await (await fetch(\`\${CLOUD}/v2/workspaces/\${WS}/aggregates/\${encodeURIComponent(createdId)}\`)).json();`,
3329
- `const merged: string[] = d.rows?.[0]?.data?.[${JSON.stringify(setField)}] ?? [];`,
3330
- `if (!(merged.includes("proof-a") && merged.includes("proof-b"))) fail(\`AddWins union lost an add: \${JSON.stringify(merged)}\`);`,
3331
- `ok(\`two blind writers' concurrent adds BOTH survive the merge — ${setField} [\${[...merged].sort().join(", ")}]\`);`,
3332
- ``,
3333
- );
3334
- } else {
3335
- out.push(
3336
- `// ${n()}. concurrency leg: this law has no addToSet-capable .mutates directive on an`,
3337
- `// AddWins set field, so there is nothing honest to race.`,
3338
- `console.log("– concurrency leg SKIPPED — add a .mutates directive carrying an array field named like an AddWins set (the addToSet shape) to see two blind writers merge");`,
3339
- ``,
3340
- );
3341
- }
3342
-
3343
- // THE ATTESTED / DYNAMIC-POLICY FOREIGN-READ LEG — named, honestly SKIPPED here. A `.readsFrom(...)`
3344
- // directive's plan reads a SIGNED cross-workspace attestation; proving it needs a SECOND source
3345
- // workspace, its read-attestor key, and a served+signed envelope — none of which the single-workspace,
3346
- // client-driven offline proof plane can mint (the client has no `attestedRead` serving op). The full
3347
- // offline two-workspace proof (birth a scratch source → seed a row → enrol its genesis → attested read
3348
- // through the policy edge → admitted, plus the wrong-genesis/unenrolled negative + revocation +
3349
- // verify_chain) lives in the bench harness against the real wasm.
3350
- if (hasForeignReadDirective(mod)) {
3351
- out.push(
3352
- `// ${n()}. attested foreign-read leg: a .readsFrom(...) directive reads a SIGNED cross-workspace`,
3353
- `// attestation — proving it needs a second SOURCE workspace + its attestor key, which this`,
3354
- `// single-workspace client proof cannot mint. Proven in the two-workspace bench smoke.`,
3355
- `console.log("– attested foreign-read leg SKIPPED — a .readsFrom(...) attested/policy read is proven in the two-workspace bench harness (bench/scale/{attested_reads.test,dynamic_attested_reads.smoke}.mjs), not this single-workspace offline proof");`,
3356
- ``,
3357
- );
3358
- }
3359
-
3360
- // THE AUTHORITY-CONFORMANCE LEG (the one-encoder + gate proof): runs on the LOCAL holon (fetch re-trapped),
3361
- // proving the generated client threads security.actor through THE ONE ENCODER and that an actorless gated
3362
- // offer is impossible to GENERATE (throws MissingOfferAuthority before any submit). No-op when un-gated.
3363
- out.push(...authorityConformanceLegLines(conformance, factory, n));
3364
-
3365
- // THE RELATION-BOOTSTRAP LEG (seed-then-prove the POSITIVE): grant relation R (or a rewrite base of it) to
3366
- // the proof actor, then prove the gated write SUCCEEDS under that actor. Runs on the LOCAL holon (fetch
3367
- // re-trapped). When no granter is discoverable but a gated directive exists, emits a CLEAR diagnostic naming
3368
- // exactly what's missing (the negative conformance leg still covers the gate).
3369
- out.push(...relationSeedLegsLines(primaryLegs, factory, n, diagnoseRelationBootstrapGap(mod)));
3370
-
3371
- // THE CHILD-BIRTH LEG (G3, gap 2): when the primary domain has a `.births()` directive, prove the birth
3372
- // END-TO-END against the cloud — drive the parent birth offer, then read the BORN child workspace it spawns.
3373
- if (childBirth !== undefined) {
3374
- out.push(...liveChildBirthLegLines(childBirth, opts, n));
3375
- }
3376
-
3377
- out.push(
3378
- `// ${n()}. CONVERGENCE: the original instance adopts canonical main in place — no reconnect`,
3379
- `await holon.pull();`,
3380
- `const head = await holon.head();`,
3381
- `const refsAdv = await (await fetch(\`\${CLOUD}/v2/workspaces/\${WS}/git/info/refs?service=git-upload-pack\`)).text();`,
3382
- `const remoteMain = (refsAdv.match(/([0-9a-f]{40}) refs\\/heads\\/main/) || [])[1];`,
3383
- `if (head !== remoteMain) fail(\`not converged in place: local \${head?.slice(0, 10)} vs main \${remoteMain?.slice(0, 10)}\`);`,
3384
- `ok("converged in place — local head == canonical main");`,
3385
- ``,
3386
- `console.log(\`\\nALL GREEN — generated proof for "${opts.packageName}": deploy → offline write → local reads → admission → cloud reads${concurrency ? ` → AddWins merge` : ``}${childBirth !== undefined ? ` → child birth` : ``} → convergence (\${WS})\`);`,
3387
- ``,
3388
- ...v2CatchFinally(),
3389
- ``,
3390
- );
3391
-
3392
- return out.join("\n");
3368
+ return generateSealedApplicationProof(mod, opts, primaryLegs);
3393
3369
  }