@githolon/dsl 0.108.3 → 0.108.6

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 (44) hide show
  1. package/dart/CHANGELOG.md +10 -0
  2. package/dart/lib/src/application_framework_calls.dart +21 -0
  3. package/dart/lib/src/dev_cloud.dart +67 -0
  4. package/dart/lib/src/nms_test_environment.dart +1 -1
  5. package/dart/lib/src/runner/node-entry.mjs +372 -106
  6. package/dart/lib/src/runner/offline-install.mjs +171 -11
  7. package/dart/lib/src/session_bound.dart +58 -30
  8. package/dart/lib/src/test_harness.dart +60 -98
  9. package/dart/lib/src/webview_bridge.dart +212 -32
  10. package/dart/pubspec.lock +1 -1
  11. package/dart/pubspec.yaml +2 -2
  12. package/dart/test/node_runner_transport_test.dart +5 -5
  13. package/dart/test/webview_bridge_test.dart +6 -0
  14. package/dart_types/CHANGELOG.md +4 -0
  15. package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +428 -2
  16. package/dart_types/pubspec.yaml +1 -1
  17. package/package.json +1 -1
  18. package/runtime/generated-application-host.js +314 -82
  19. package/src/application_topology.ts +120 -28
  20. package/src/births.ts +27 -0
  21. package/src/codegen_call_usda.ts +9 -4
  22. package/src/codegen_dart_application.ts +146 -37
  23. package/src/codegen_dart_client.ts +225 -160
  24. package/src/codegen_dart_framework_calls.ts +89 -4
  25. package/src/codegen_ts.ts +135 -60
  26. package/src/compile_package_main.ts +3544 -1460
  27. package/src/directive.ts +320 -118
  28. package/src/fields.ts +2 -3
  29. package/src/framework/application_home.ts +3 -0
  30. package/src/framework/auth_provider_law.ts +20 -16
  31. package/src/framework/genesis.ts +32 -1
  32. package/src/framework/home.ts +45 -8
  33. package/src/framework/signing_identity.ts +78 -0
  34. package/src/framework/workspaces.ts +9 -1
  35. package/src/framework_call_dart_enums.ts +33 -0
  36. package/src/framework_call_definitions.ts +11 -2
  37. package/src/index.ts +12 -0
  38. package/src/intent.ts +525 -194
  39. package/src/law_graph.ts +32 -4
  40. package/src/law_graph_usda.ts +3 -0
  41. package/src/package_config.ts +16 -1
  42. package/src/read.ts +33 -11
  43. package/src/wire.ts +1 -0
  44. package/src/wire_encode.ts +3 -3
package/src/directive.ts CHANGED
@@ -23,7 +23,11 @@ import type { PlannedOp } from "./ops.js";
23
23
  import type { Ports } from "./ctx.js";
24
24
  import type { RelationDecl } from "./relation.js";
25
25
  import type { QueryDecl } from "./query.js";
26
- import { normalizeActivity, type ActivityInput, type ActivityDescriptor } from "./activity.js";
26
+ import {
27
+ normalizeActivity,
28
+ type ActivityInput,
29
+ type ActivityDescriptor,
30
+ } from "./activity.js";
27
31
  import { idOfMetaOf } from "./value_object.js";
28
32
  import { BIRTH_METER_QUERIES } from "./birth_meter.js";
29
33
  import { zodDef, zodKind, zodObjectShape } from "./zod_introspection.js";
@@ -128,29 +132,52 @@ function payloadIdSelector<P>(selector: PayloadIdSelector<P>): {
128
132
  optional: false,
129
133
  };
130
134
  return {
131
- field: (payload) => resolveInvariantReadId(readId, payload as Record<string, unknown>) ?? "",
135
+ field: (payload) =>
136
+ resolveInvariantReadId(readId, payload as Record<string, unknown>) ??
137
+ "",
132
138
  path: [selector],
133
139
  readId,
134
140
  };
135
141
  }
136
142
  if (Array.isArray(selector)) {
137
- const readId: InvariantReadId = { source: "template", parts: [...selector], optional: false };
143
+ const readId: InvariantReadId = {
144
+ source: "template",
145
+ parts: [...selector],
146
+ optional: false,
147
+ };
138
148
  return {
139
- field: (payload) => resolveInvariantReadId(readId, payload as Record<string, unknown>) ?? "",
149
+ field: (payload) =>
150
+ resolveInvariantReadId(readId, payload as Record<string, unknown>) ??
151
+ "",
140
152
  readId,
141
153
  };
142
154
  }
143
- if (typeof selector === "object" && selector !== null && "source" in selector) {
155
+ if (
156
+ typeof selector === "object" &&
157
+ selector !== null &&
158
+ "source" in selector
159
+ ) {
144
160
  if (selector.source === "item") {
145
- throw new Error("directive precondition ids cannot use item-relative read parts");
161
+ throw new Error(
162
+ "directive precondition ids cannot use item-relative read parts"
163
+ );
146
164
  }
147
- const readId: InvariantReadId = selector.source === "literal"
148
- ? selector
149
- : selector.transform === "none"
150
- ? { source: "payload", path: selector.path, prefix: "", suffix: "", optional: false }
165
+ const readId: InvariantReadId =
166
+ selector.source === "literal"
167
+ ? selector
168
+ : selector.transform === "none"
169
+ ? {
170
+ source: "payload",
171
+ path: selector.path,
172
+ prefix: "",
173
+ suffix: "",
174
+ optional: false,
175
+ }
151
176
  : { source: "template", parts: [selector], optional: false };
152
177
  return {
153
- field: (payload) => resolveInvariantReadId(readId, payload as Record<string, unknown>) ?? "",
178
+ field: (payload) =>
179
+ resolveInvariantReadId(readId, payload as Record<string, unknown>) ??
180
+ "",
154
181
  ...(readId.source === "payload" ? { path: readId.path } : {}),
155
182
  readId,
156
183
  };
@@ -215,6 +242,15 @@ export interface BusinessSourceTrust {
215
242
  /** Hidden trust payload fields populated from custody identity; v2 leaves the signing-key set empty. */
216
243
  readonly genesisField: string;
217
244
  readonly keyHashesField: string;
245
+ /**
246
+ * Optional indexed business query proving that this source is already seated.
247
+ * Generated clients use the declared query before authoring the hidden trust
248
+ * directive, so an idempotent prerequisite does not become a new commit on
249
+ * every business action.
250
+ */
251
+ readonly satisfiedByQueryId?: string;
252
+ /** Satisfaction-query key -> business payload field. */
253
+ readonly satisfiedByQueryArgs?: Readonly<Record<string, string>>;
218
254
  }
219
255
 
220
256
  export interface Directive<P = unknown> {
@@ -320,7 +356,10 @@ export interface Directive<P = unknown> {
320
356
  readonly object: string;
321
357
  /** PER-RECORD (§6): when set, the gate object is `<recordType>:<payload[idField]>` (the static
322
358
  * `object` is the fallback). `undefined` ⇒ the static object — era-ruled, byte-identical replay. */
323
- readonly objectFrom?: { readonly recordType: string; readonly idField: string };
359
+ readonly objectFrom?: {
360
+ readonly recordType: string;
361
+ readonly idField: string;
362
+ };
324
363
  };
325
364
  /**
326
365
  * Admit this directive when it is the exact target call carried by a verified,
@@ -330,6 +369,9 @@ export interface Directive<P = unknown> {
330
369
  * check remains the authorization decision.
331
370
  */
332
371
  readonly acceptsWorkspaceEffectGate?: true;
372
+ /** Recovery-only workspace-effect door. The carried source must prove it is this workspace's
373
+ * exact K_root-rooted birth parent; no Zanzibar relation or host assertion substitutes for it. */
374
+ readonly acceptsVerifiedBirthParentRecoveryGate?: true;
333
375
  /**
334
376
  * CROSS-CUSTODY ATTESTATION-AUTHORIZED (home_holons §3/§5). When `true`, this directive's authorization
335
377
  * is a carried §3 SIGNED QUOTE (the asserter's pubkey + a signature over the edge), NOT an author block —
@@ -572,6 +614,8 @@ export interface RequirableDirective<P> extends Directive<P> {
572
614
  copy?: Readonly<Record<string, string>>;
573
615
  genesisField?: string;
574
616
  keyHashesField?: string;
617
+ satisfiedBy?: QueryDecl;
618
+ satisfiedByArgs?: Readonly<Record<string, string>>;
575
619
  }): RequirableDirective<P>;
576
620
  /** Declare that this action can affect several records of its primary aggregate. */
577
621
  affectsMany(): RequirableDirective<P>;
@@ -585,9 +629,18 @@ export interface RequirableDirective<P> extends Directive<P> {
585
629
  * The compiler checks observable marked plan outputs against this certified effect signature; an
586
630
  * undeclared secondary output is a compile error rather than a runtime-only projection surprise.
587
631
  */
588
- alsoWrites(aggregate: AggregateHandle, marker: ReferentialMarker): RequirableDirective<P>;
589
- alsoWritesMany(aggregate: AggregateHandle, marker: ReferentialMarker): RequirableDirective<P>;
590
- alsoWritesOptional(aggregate: AggregateHandle, marker: ReferentialMarker): RequirableDirective<P>;
632
+ alsoWrites(
633
+ aggregate: AggregateHandle,
634
+ marker: ReferentialMarker
635
+ ): RequirableDirective<P>;
636
+ alsoWritesMany(
637
+ aggregate: AggregateHandle,
638
+ marker: ReferentialMarker
639
+ ): RequirableDirective<P>;
640
+ alsoWritesOptional(
641
+ aggregate: AggregateHandle,
642
+ marker: ReferentialMarker
643
+ ): RequirableDirective<P>;
591
644
  alsoEnsures(aggregate: AggregateHandle): RequirableDirective<P>;
592
645
  alsoCreates(aggregate: AggregateHandle): RequirableDirective<P>;
593
646
  alsoEnsuresMany(aggregate: AggregateHandle): RequirableDirective<P>;
@@ -607,7 +660,10 @@ export interface RequirableDirective<P> extends Directive<P> {
607
660
  */
608
661
  requires(
609
662
  relation: string,
610
- opts?: { object?: string; objectFrom?: { recordType: string; idField: string } },
663
+ opts?: {
664
+ object?: string;
665
+ objectFrom?: { recordType: string; idField: string };
666
+ }
611
667
  ): RequirableDirective<P>;
612
668
  /** Declare this exact call shape as an admissible signed parent-workspace effect. */
613
669
  acceptsWorkspaceEffect(): RequirableDirective<P>;
@@ -617,7 +673,10 @@ export interface RequirableDirective<P> extends Directive<P> {
617
673
  * gate verifies the quote + pins the principal to the attestation key, and the bailiff delivers it
618
674
  * host-free. Framework-only (the home law's `recordShare`). Returns a NEW requirable directive.
619
675
  */
620
- attestationAuthorized(owner: { ownerObject: string; ownerField: string }): RequirableDirective<P>;
676
+ attestationAuthorized(owner: {
677
+ ownerObject: string;
678
+ ownerField: string;
679
+ }): RequirableDirective<P>;
621
680
  /**
622
681
  * Declare this directive a DELEGATED-AUTHORITY delivery (`delegated_authority_births.md`): its write folds
623
682
  * the delegated `relation` tuple ONLY behind a carried `DelegationCert` P signed — lowered into the
@@ -625,14 +684,20 @@ export interface RequirableDirective<P> extends Directive<P> {
625
684
  * `subjectField`/`certField` default to `"subject"`/`"delegationCert"`. Chain `.delegatedFrom(parent)` to
626
685
  * bind the grantor to this workspace's parent key. Returns a NEW requirable directive.
627
686
  */
628
- delegatedRole(relation: string, opts?: { subjectField?: string; certField?: string }): RequirableDirective<P>;
687
+ delegatedRole(
688
+ relation: string,
689
+ opts?: { subjectField?: string; certField?: string }
690
+ ): RequirableDirective<P>;
629
691
  /**
630
692
  * `.delegatedFrom(parent)` — bind the delegating grantor to THIS workspace's parent key (the platform P
631
693
  * that bore this home): the `DelegationCert`'s grantor key MUST equal the base64 key at
632
694
  * `parentKeyObject.parentKeyField` (e.g. the birth-cert `birth-attestation:self`.`parentKey`, or a seeded
633
695
  * `platform-key:self`.`grantorKey`). Refines the `.delegatedRole()` gate. Returns a NEW requirable directive.
634
696
  */
635
- delegatedFrom(parent: { parentKeyObject: string; parentKeyField: string }): RequirableDirective<P>;
697
+ delegatedFrom(parent: {
698
+ parentKeyObject: string;
699
+ parentKeyField: string;
700
+ }): RequirableDirective<P>;
636
701
  /**
637
702
  * Declare this directive a KEYLESS VERIFIED-FIRST-DEVICE bootstrap (keyless_verified_onboard.md): its
638
703
  * authorization is a carried, device-bound IdP `idpToken` re-verified against the workspace AuthProvider —
@@ -675,7 +740,10 @@ export interface RequirableDirective<P> extends Directive<P> {
675
740
  * …)` declaration (signature / accepted key + genesis / bounds / freshness). Callable multiple
676
741
  * times; deduped by `(queryId, from)`. Purely additive (the era rule).
677
742
  */
678
- readsFrom(sourceWorkspace: string, query: { id: string }): RequirableDirective<P>;
743
+ readsFrom(
744
+ sourceWorkspace: string,
745
+ query: { id: string }
746
+ ): RequirableDirective<P>;
679
747
  /**
680
748
  * Declare ONE DYNAMIC (payload-routed) foreign read (dynamic_source_attested_reads.md): the plan may
681
749
  * `read(theQuery, args, { from: payload.<field> })` — the routed workspace is chosen at runtime by the
@@ -686,7 +754,7 @@ export interface RequirableDirective<P> extends Directive<P> {
686
754
  readsFrom(
687
755
  source: FromPayloadRef,
688
756
  query: { id: string },
689
- opts: { policy: TrustPolicyDecl },
757
+ opts: { policy: TrustPolicyDecl }
690
758
  ): RequirableDirective<P>;
691
759
  /**
692
760
  * Declare ONE entry of the directive's EMIT boundary: an `eventType` its `plan` may
@@ -792,14 +860,16 @@ class DirectivePayloadStep<Id extends string> {
792
860
  constructor(
793
861
  private readonly id: Id,
794
862
  private readonly marker: ReferentialMarker,
795
- private readonly aggregate: AggregateHandle,
863
+ private readonly aggregate: AggregateHandle
796
864
  ) {}
797
- payload<S extends z.ZodTypeAny>(schema: S): DirectivePlanStep<Id, z.infer<S>> {
865
+ payload<S extends z.ZodTypeAny>(
866
+ schema: S
867
+ ): DirectivePlanStep<Id, z.infer<S>> {
798
868
  return new DirectivePlanStep(
799
869
  this.id,
800
870
  this.marker,
801
871
  this.aggregate,
802
- schema as z.ZodType<z.infer<S>>,
872
+ schema as z.ZodType<z.infer<S>>
803
873
  );
804
874
  }
805
875
  }
@@ -820,13 +890,13 @@ class DirectivePlanStep<Id extends string, P> {
820
890
  private readonly payloadSchema: z.ZodType<P>,
821
891
  private readonly createOnceIdField?: (payload: unknown) => string,
822
892
  private readonly preconditions: PreconditionDescriptor[] = [],
823
- private readonly targetField?: string,
893
+ private readonly targetField?: string
824
894
  ) {}
825
895
 
826
896
  /** Non-destructive copy carrying one more precondition (and/or the create-once id field). */
827
897
  private with(
828
898
  desc?: PreconditionDescriptor,
829
- createOnceIdField?: (payload: unknown) => string,
899
+ createOnceIdField?: (payload: unknown) => string
830
900
  ): DirectivePlanStep<Id, P> {
831
901
  return new DirectivePlanStep(
832
902
  this.id,
@@ -835,7 +905,7 @@ class DirectivePlanStep<Id extends string, P> {
835
905
  this.payloadSchema,
836
906
  createOnceIdField ?? this.createOnceIdField,
837
907
  desc !== undefined ? [...this.preconditions, desc] : this.preconditions,
838
- this.targetField,
908
+ this.targetField
839
909
  );
840
910
  }
841
911
 
@@ -845,10 +915,12 @@ class DirectivePlanStep<Id extends string, P> {
845
915
  * Use this only when the payload carries more than one reference to the same
846
916
  * aggregate and the compiler cannot choose without domain knowledge.
847
917
  */
848
- target<K extends Extract<keyof P, string>>(field: K): DirectivePlanStep<Id, P> {
918
+ target<K extends Extract<keyof P, string>>(
919
+ field: K
920
+ ): DirectivePlanStep<Id, P> {
849
921
  if (this.marker !== "mutates" && this.marker !== "archives") {
850
922
  throw new Error(
851
- `directive('${this.id}').target(...) is only valid on .mutates(...) or .archives(...)`,
923
+ `directive('${this.id}').target(...) is only valid on .mutates(...) or .archives(...)`
852
924
  );
853
925
  }
854
926
  const shape = zodObjectShape(this.payloadSchema);
@@ -856,7 +928,11 @@ class DirectivePlanStep<Id extends string, P> {
856
928
  const actual = schema === undefined ? undefined : idOfMetaOf(schema);
857
929
  if (actual !== this.aggregate.id) {
858
930
  throw new Error(
859
- `directive('${this.id}').target('${field}') must name an idOf(${shortName(this.aggregate.id)}) payload field`,
931
+ `directive('${
932
+ this.id
933
+ }').target('${field}') must name an idOf(${shortName(
934
+ this.aggregate.id
935
+ )}) payload field`
860
936
  );
861
937
  }
862
938
  return new DirectivePlanStep(
@@ -866,7 +942,7 @@ class DirectivePlanStep<Id extends string, P> {
866
942
  this.payloadSchema,
867
943
  this.createOnceIdField,
868
944
  this.preconditions,
869
- field,
945
+ field
870
946
  );
871
947
  }
872
948
 
@@ -881,7 +957,7 @@ class DirectivePlanStep<Id extends string, P> {
881
957
  if (this.marker !== "creates") {
882
958
  throw new Error(
883
959
  `directive('${this.id}').withId(...) is only valid on a .creates(...) directive — it fixes the ` +
884
- `CREATED aggregate's caller-supplied id (a .${this.marker} directive targets an existing id).`,
960
+ `CREATED aggregate's caller-supplied id (a .${this.marker} directive targets an existing id).`
885
961
  );
886
962
  }
887
963
  const selected = payloadIdSelector(idSelector);
@@ -891,13 +967,15 @@ class DirectivePlanStep<Id extends string, P> {
891
967
  aggregateId: this.aggregate.id,
892
968
  fieldNames: Object.keys(this.aggregate.fields).sort(),
893
969
  idField,
894
- ...(selected.path === undefined ? {} : { idPayloadPath: selected.path }),
970
+ ...(selected.path === undefined
971
+ ? {}
972
+ : { idPayloadPath: selected.path }),
895
973
  ...(selected.readId === undefined ? {} : { readId: selected.readId }),
896
974
  kind: "absent",
897
975
  predicate: (row) => row === undefined,
898
976
  rejectCode: `${shortName(this.aggregate.id)}-exists`,
899
977
  },
900
- idField,
978
+ idField
901
979
  );
902
980
  }
903
981
 
@@ -909,7 +987,7 @@ class DirectivePlanStep<Id extends string, P> {
909
987
  requiresExisting<F extends Record<string, Field>>(
910
988
  aggregate: AggregateHandle<string, F>,
911
989
  idSelector: PayloadIdSelector<P>,
912
- rejectCode?: string,
990
+ rejectCode?: string
913
991
  ): DirectivePlanStep<Id, P> {
914
992
  const selected = payloadIdSelector(idSelector);
915
993
  return this.with({
@@ -935,7 +1013,7 @@ class DirectivePlanStep<Id extends string, P> {
935
1013
  aggregate: AggregateHandle<string, F>,
936
1014
  idSelector: PayloadIdSelector<P>,
937
1015
  predicate: (row: ReadModelRow<F> | undefined) => boolean,
938
- rejectCode: string,
1016
+ rejectCode: string
939
1017
  ): DirectivePlanStep<Id, P> {
940
1018
  const selected = payloadIdSelector(idSelector);
941
1019
  return this.with({
@@ -945,7 +1023,9 @@ class DirectivePlanStep<Id extends string, P> {
945
1023
  ...(selected.path === undefined ? {} : { idPayloadPath: selected.path }),
946
1024
  ...(selected.readId === undefined ? {} : { readId: selected.readId }),
947
1025
  kind: "predicate",
948
- predicate: predicate as (row: Record<string, unknown> | undefined) => boolean,
1026
+ predicate: predicate as (
1027
+ row: Record<string, unknown> | undefined
1028
+ ) => boolean,
949
1029
  rejectCode,
950
1030
  });
951
1031
  }
@@ -963,7 +1043,7 @@ class DirectivePlanStep<Id extends string, P> {
963
1043
  precondition<F extends Record<string, Field>>(
964
1044
  aggregate: AggregateHandle<string, F>,
965
1045
  build: (ctx: PointGuardContext<P, F>) => PointGuardDeclaration,
966
- rejectCode: string,
1046
+ rejectCode: string
967
1047
  ): DirectivePlanStep<Id, P> {
968
1048
  const pointGuard = buildPointGuard(aggregate, build, rejectCode);
969
1049
  return this.with({
@@ -986,7 +1066,8 @@ class DirectivePlanStep<Id extends string, P> {
986
1066
  optional: false,
987
1067
  },
988
1068
  kind: "predicate",
989
- predicate: (row) => evaluatePointGuard(pointGuard.predicate, row, undefined),
1069
+ predicate: (row) =>
1070
+ evaluatePointGuard(pointGuard.predicate, row, undefined),
990
1071
  rejectCode,
991
1072
  pointGuard,
992
1073
  });
@@ -1002,18 +1083,18 @@ class DirectivePlanStep<Id extends string, P> {
1002
1083
  const trimmed = reason.trim();
1003
1084
  if (trimmed.length === 0) {
1004
1085
  throw new Error(
1005
- `directive('${this.id}').declassify(reason) needs a non-empty human reason — it is the audit record for an intended private-state refusal.`,
1086
+ `directive('${this.id}').declassify(reason) needs a non-empty human reason — it is the audit record for an intended private-state refusal.`
1006
1087
  );
1007
1088
  }
1008
1089
  if (this.preconditions.length === 0) {
1009
1090
  throw new Error(
1010
- `directive('${this.id}').declassify(reason) must follow .requiresExisting(...), .where(...), or .withId(...).`,
1091
+ `directive('${this.id}').declassify(reason) must follow .requiresExisting(...), .where(...), or .withId(...).`
1011
1092
  );
1012
1093
  }
1013
1094
  const last = this.preconditions[this.preconditions.length - 1]!;
1014
1095
  if (last.declassify !== undefined) {
1015
1096
  throw new Error(
1016
- `directive('${this.id}') already declassifies its most recent precondition — declare each policy once, beside its condition.`,
1097
+ `directive('${this.id}') already declassifies its most recent precondition — declare each policy once, beside its condition.`
1017
1098
  );
1018
1099
  }
1019
1100
  return new DirectivePlanStep(
@@ -1022,11 +1103,8 @@ class DirectivePlanStep<Id extends string, P> {
1022
1103
  this.aggregate,
1023
1104
  this.payloadSchema,
1024
1105
  this.createOnceIdField,
1025
- [
1026
- ...this.preconditions.slice(0, -1),
1027
- { ...last, declassify: trimmed },
1028
- ],
1029
- this.targetField,
1106
+ [...this.preconditions.slice(0, -1), { ...last, declassify: trimmed }],
1107
+ this.targetField
1030
1108
  );
1031
1109
  }
1032
1110
 
@@ -1037,11 +1115,15 @@ class DirectivePlanStep<Id extends string, P> {
1037
1115
  const candidates = Object.entries(shape)
1038
1116
  .filter(([, schema]) => idOfMetaOf(schema) === this.aggregate.id)
1039
1117
  .map(([field]) => field);
1040
- const field = this.targetField ?? (candidates.length === 1 ? candidates[0] : undefined);
1118
+ const field =
1119
+ this.targetField ??
1120
+ (candidates.length === 1 ? candidates[0] : undefined);
1041
1121
  if (this.targetField === undefined && candidates.length > 1) {
1042
1122
  throw new Error(
1043
- `directive('${this.id}') has several idOf(${shortName(this.aggregate.id)}) payload fields; ` +
1044
- `select the mutation target with .target('field') before .plan(...)`,
1123
+ `directive('${this.id}') has several idOf(${shortName(
1124
+ this.aggregate.id
1125
+ )}) payload fields; ` +
1126
+ `select the mutation target with .target('field') before .plan(...)`
1045
1127
  );
1046
1128
  }
1047
1129
  if (field !== undefined) {
@@ -1063,9 +1145,13 @@ class DirectivePlanStep<Id extends string, P> {
1063
1145
  declaredHostCapabilities: [],
1064
1146
  // `.withId(...)` — record the caller-supplied-id extractor (codegen/authoring hint). The `absent`
1065
1147
  // create-once guard is already in `preconditions` (seeded by `.withId`). Omit-when-absent.
1066
- ...(this.createOnceIdField !== undefined ? { createOnceIdField: this.createOnceIdField } : {}),
1148
+ ...(this.createOnceIdField !== undefined
1149
+ ? { createOnceIdField: this.createOnceIdField }
1150
+ : {}),
1067
1151
  // Omit-when-empty so a directive with no precondition is byte-identical (the era rule).
1068
- ...(this.preconditions.length > 0 ? { preconditions: this.preconditions } : {}),
1152
+ ...(this.preconditions.length > 0
1153
+ ? { preconditions: this.preconditions }
1154
+ : {}),
1069
1155
  });
1070
1156
  }
1071
1157
  }
@@ -1090,7 +1176,7 @@ function shortName(aggregateId: string): string {
1090
1176
  */
1091
1177
  export function recordObject(
1092
1178
  agg: AggregateHandle,
1093
- idField: string,
1179
+ idField: string
1094
1180
  ): { recordType: string; idField: string } {
1095
1181
  return { recordType: agg.id, idField };
1096
1182
  }
@@ -1105,7 +1191,7 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
1105
1191
  const alsoWrites = (
1106
1192
  aggregate: AggregateHandle,
1107
1193
  marker: ReferentialMarker,
1108
- cardinality: "one" | "many" | "optional" = "one",
1194
+ cardinality: "one" | "many" | "optional" = "one"
1109
1195
  ): RequirableDirective<P> => {
1110
1196
  // Dedup by (marker, aggregateId) + the primary target — declaring the same output twice is a no-op, and
1111
1197
  // re-declaring the primary aggregate is ignored (it is already the marker target). Sorted at emit time.
@@ -1120,9 +1206,10 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
1120
1206
  // different marker is a distinct lawful consequence: a `.mutates(A)` directive
1121
1207
  // may deliberately emit an Archive for A and must retain `.alsoArchives(A)` in
1122
1208
  // its typed effect signature.
1123
- const isPrimary = aggregate.id === base.aggregateId && marker === base.marker;
1209
+ const isPrimary =
1210
+ aggregate.id === base.aggregateId && marker === base.marker;
1124
1211
  const existing = (base.secondaryOutputs ?? []).find(
1125
- (s) => s.marker === marker && s.aggregateId === aggregate.id,
1212
+ (s) => s.marker === marker && s.aggregateId === aggregate.id
1126
1213
  );
1127
1214
  if (
1128
1215
  isPrimary ||
@@ -1137,16 +1224,20 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
1137
1224
  return makeRequirable({
1138
1225
  ...base,
1139
1226
  secondaryOutputs: (base.secondaryOutputs ?? []).map((output) =>
1140
- output === existing ? next : output,
1227
+ output === existing ? next : output
1141
1228
  ),
1142
1229
  });
1143
1230
  }
1144
- return makeRequirable({ ...base, secondaryOutputs: [...(base.secondaryOutputs ?? []), next] });
1231
+ return makeRequirable({
1232
+ ...base,
1233
+ secondaryOutputs: [...(base.secondaryOutputs ?? []), next],
1234
+ });
1145
1235
  };
1146
1236
  return {
1147
1237
  ...base,
1148
1238
  affectsMany: () => makeRequirable({ ...base, outputCardinality: "many" }),
1149
- affectsOptional: () => makeRequirable({ ...base, outputCardinality: "optional" }),
1239
+ affectsOptional: () =>
1240
+ makeRequirable({ ...base, outputCardinality: "optional" }),
1150
1241
  example(payload: P): RequirableDirective<P> {
1151
1242
  if (isRuntimeLaw()) {
1152
1243
  // The Node authoring pass already proved this example. Executable law retains it as proof
@@ -1154,46 +1245,57 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
1154
1245
  return makeRequirable({ ...base, payloadExample: payload });
1155
1246
  }
1156
1247
  const parsed = base.payloadSchema.safeParse(payload);
1157
- if (!parsed.success) throw new Error(
1158
- `directive('${base.id}').example(...) must satisfy its payload schema: ${parsed.error.message}`,
1159
- );
1248
+ if (!parsed.success)
1249
+ throw new Error(
1250
+ `directive('${base.id}').example(...) must satisfy its payload schema: ${parsed.error.message}`
1251
+ );
1160
1252
  return makeRequirable({ ...base, payloadExample: parsed.data });
1161
1253
  },
1162
1254
  fromCurrentPrincipal(field: string): RequirableDirective<P> {
1163
1255
  const name = field.trim();
1164
1256
  if (name.length === 0) {
1165
- throw new Error("directive.fromCurrentPrincipal(field): field must be a non-empty payload field name");
1257
+ throw new Error(
1258
+ "directive.fromCurrentPrincipal(field): field must be a non-empty payload field name"
1259
+ );
1166
1260
  }
1167
1261
  if (zodKind(base.payloadSchema) !== "object") {
1168
1262
  throw new Error(
1169
- `directive('${base.id}').fromCurrentPrincipal('${name}') needs an object payload schema`,
1263
+ `directive('${base.id}').fromCurrentPrincipal('${name}') needs an object payload schema`
1170
1264
  );
1171
1265
  }
1172
1266
  const principalSchema = zodObjectShape(base.payloadSchema)[name];
1173
1267
  if (principalSchema === undefined) {
1174
1268
  throw new Error(
1175
- `directive('${base.id}').fromCurrentPrincipal('${name}') names no payload field`,
1269
+ `directive('${base.id}').fromCurrentPrincipal('${name}') names no payload field`
1176
1270
  );
1177
1271
  }
1178
1272
  let principalValue = principalSchema;
1179
- while (zodKind(principalValue) === "optional" || zodKind(principalValue) === "default") {
1273
+ while (
1274
+ zodKind(principalValue) === "optional" ||
1275
+ zodKind(principalValue) === "default"
1276
+ ) {
1180
1277
  principalValue = zodDef(principalValue).innerType!;
1181
1278
  }
1182
1279
  if (zodKind(principalValue) !== "string") {
1183
1280
  throw new Error(
1184
- `directive('${base.id}').fromCurrentPrincipal('${name}') must bind a string payload field`,
1281
+ `directive('${base.id}').fromCurrentPrincipal('${name}') must bind a string payload field`
1185
1282
  );
1186
1283
  }
1187
- if (base.businessPrincipalField !== undefined && base.businessPrincipalField !== name) {
1284
+ if (
1285
+ base.businessPrincipalField !== undefined &&
1286
+ base.businessPrincipalField !== name
1287
+ ) {
1188
1288
  throw new Error(
1189
- `directive('${base.id}').fromCurrentPrincipal(...) may bind only one identity field`,
1289
+ `directive('${base.id}').fromCurrentPrincipal(...) may bind only one identity field`
1190
1290
  );
1191
1291
  }
1192
1292
  return makeRequirable({ ...base, businessPrincipalField: name });
1193
1293
  },
1194
1294
  fromRecord(field: string, opts?: { as?: string }): RequirableDirective<P> {
1195
1295
  if (typeof field !== "string" || field.length === 0) {
1196
- throw new Error("directive.fromRecord(field): field must be a non-empty payload field name");
1296
+ throw new Error(
1297
+ "directive.fromRecord(field): field must be a non-empty payload field name"
1298
+ );
1197
1299
  }
1198
1300
  const prior = base.businessRecordInputs ?? [];
1199
1301
  const next: BusinessRecordInput = {
@@ -1202,30 +1304,33 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
1202
1304
  };
1203
1305
  return makeRequirable({
1204
1306
  ...base,
1205
- businessRecordInputs: [...prior.filter((candidate) => candidate.field !== field), next],
1307
+ businessRecordInputs: [
1308
+ ...prior.filter((candidate) => candidate.field !== field),
1309
+ next,
1310
+ ],
1206
1311
  });
1207
1312
  },
1208
1313
  trustsSource(opts): RequirableDirective<P> {
1209
1314
  if (base.businessSourceTrust !== undefined) {
1210
1315
  throw new Error(
1211
- `directive('${base.id}').trustsSource(...) may be declared only once`,
1316
+ `directive('${base.id}').trustsSource(...) may be declared only once`
1212
1317
  );
1213
1318
  }
1214
1319
  const fromPayload = opts.fromPayload.trim();
1215
1320
  if (fromPayload.length === 0 || opts.query.id.trim().length === 0) {
1216
1321
  throw new Error(
1217
- `directive('${base.id}').trustsSource(...) needs a source payload field and query`,
1322
+ `directive('${base.id}').trustsSource(...) needs a source payload field and query`
1218
1323
  );
1219
1324
  }
1220
1325
  const matchingRead = (base.declaredForeignReads ?? []).some(
1221
1326
  (edge) =>
1222
1327
  !("from" in edge) &&
1223
1328
  edge.fromPayload === fromPayload &&
1224
- edge.queryId === opts.query.id,
1329
+ edge.queryId === opts.query.id
1225
1330
  );
1226
1331
  if (!matchingRead) {
1227
1332
  throw new Error(
1228
- `directive('${base.id}').trustsSource(...) must follow its matching dynamic .readsFrom(...) declaration`,
1333
+ `directive('${base.id}').trustsSource(...) must follow its matching dynamic .readsFrom(...) declaration`
1229
1334
  );
1230
1335
  }
1231
1336
  const via = opts.via as Directive<unknown> & {
@@ -1233,7 +1338,15 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
1233
1338
  };
1234
1339
  if (via.businessBirthInternal !== true) {
1235
1340
  throw new Error(
1236
- `directive('${base.id}').trustsSource(...): the trust directive must be wrapped in nomosImplementationDetail(...) so tenant code cannot call it`,
1341
+ `directive('${base.id}').trustsSource(...): the trust directive must be wrapped in nomosImplementationDetail(...) so tenant code cannot call it`
1342
+ );
1343
+ }
1344
+ if (
1345
+ (opts.satisfiedBy === undefined) !==
1346
+ (opts.satisfiedByArgs === undefined)
1347
+ ) {
1348
+ throw new Error(
1349
+ `directive('${base.id}').trustsSource(...): satisfiedBy and satisfiedByArgs must be declared together`
1237
1350
  );
1238
1351
  }
1239
1352
  return makeRequirable({
@@ -1246,16 +1359,26 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
1246
1359
  copy: { ...(opts.copy ?? {}) },
1247
1360
  genesisField: opts.genesisField ?? "sourceGenesis",
1248
1361
  keyHashesField: opts.keyHashesField ?? "sourceKeyHashes",
1362
+ ...(opts.satisfiedBy === undefined
1363
+ ? {}
1364
+ : {
1365
+ satisfiedByQueryId: opts.satisfiedBy.id,
1366
+ satisfiedByQueryArgs: { ...(opts.satisfiedByArgs ?? {}) },
1367
+ }),
1249
1368
  },
1250
1369
  });
1251
1370
  },
1252
1371
  alsoWrites,
1253
1372
  alsoWritesMany: (aggregate: AggregateHandle, marker: ReferentialMarker) =>
1254
1373
  alsoWrites(aggregate, marker, "many"),
1255
- alsoWritesOptional: (aggregate: AggregateHandle, marker: ReferentialMarker) =>
1256
- alsoWrites(aggregate, marker, "optional"),
1257
- alsoEnsures: (aggregate: AggregateHandle) => alsoWrites(aggregate, "ensures"),
1258
- alsoCreates: (aggregate: AggregateHandle) => alsoWrites(aggregate, "creates"),
1374
+ alsoWritesOptional: (
1375
+ aggregate: AggregateHandle,
1376
+ marker: ReferentialMarker
1377
+ ) => alsoWrites(aggregate, marker, "optional"),
1378
+ alsoEnsures: (aggregate: AggregateHandle) =>
1379
+ alsoWrites(aggregate, "ensures"),
1380
+ alsoCreates: (aggregate: AggregateHandle) =>
1381
+ alsoWrites(aggregate, "creates"),
1259
1382
  alsoEnsuresMany: (aggregate: AggregateHandle) =>
1260
1383
  alsoWrites(aggregate, "ensures", "many"),
1261
1384
  alsoCreatesMany: (aggregate: AggregateHandle) =>
@@ -1264,8 +1387,10 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
1264
1387
  alsoWrites(aggregate, "ensures", "optional"),
1265
1388
  alsoCreatesOptional: (aggregate: AggregateHandle) =>
1266
1389
  alsoWrites(aggregate, "creates", "optional"),
1267
- alsoMutates: (aggregate: AggregateHandle) => alsoWrites(aggregate, "mutates"),
1268
- alsoArchives: (aggregate: AggregateHandle) => alsoWrites(aggregate, "archives"),
1390
+ alsoMutates: (aggregate: AggregateHandle) =>
1391
+ alsoWrites(aggregate, "mutates"),
1392
+ alsoArchives: (aggregate: AggregateHandle) =>
1393
+ alsoWrites(aggregate, "archives"),
1269
1394
  alsoMutatesMany: (aggregate: AggregateHandle) =>
1270
1395
  alsoWrites(aggregate, "mutates", "many"),
1271
1396
  alsoArchivesMany: (aggregate: AggregateHandle) =>
@@ -1276,7 +1401,10 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
1276
1401
  alsoWrites(aggregate, "archives", "optional"),
1277
1402
  requires(
1278
1403
  relation: string,
1279
- opts?: { object?: string; objectFrom?: { recordType: string; idField: string } },
1404
+ opts?: {
1405
+ object?: string;
1406
+ objectFrom?: { recordType: string; idField: string };
1407
+ }
1280
1408
  ): RequirableDirective<P> {
1281
1409
  // THE ONE write-authz declaration (full-native Zanzibar, no mixed systems): the captured author
1282
1410
  // must HOLD `relation` on the object for the one gate to admit. Default object is self-relative
@@ -1289,14 +1417,19 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
1289
1417
  requiresRelationGate: {
1290
1418
  relation,
1291
1419
  object: opts?.object ?? "workspace:self",
1292
- ...(opts?.objectFrom !== undefined ? { objectFrom: opts.objectFrom } : {}),
1420
+ ...(opts?.objectFrom !== undefined
1421
+ ? { objectFrom: opts.objectFrom }
1422
+ : {}),
1293
1423
  },
1294
1424
  });
1295
1425
  },
1296
1426
  acceptsWorkspaceEffect(): RequirableDirective<P> {
1297
1427
  return makeRequirable({ ...base, acceptsWorkspaceEffectGate: true });
1298
1428
  },
1299
- attestationAuthorized(owner: { ownerObject: string; ownerField: string }): RequirableDirective<P> {
1429
+ attestationAuthorized(owner: {
1430
+ ownerObject: string;
1431
+ ownerField: string;
1432
+ }): RequirableDirective<P> {
1300
1433
  // CROSS-CUSTODY ATTESTATION-AUTHORIZED (home_holons §3/§5): this directive's authorization is a
1301
1434
  // carried §3 signed quote, not an author block — lowered into the `nomosAttestationGate` era key, so
1302
1435
  // the one gate verifies the quote (binding its subject to the LAW-DECLARED `owner`), pins the principal
@@ -1319,13 +1452,22 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
1319
1452
  },
1320
1453
  });
1321
1454
  },
1322
- delegatedRole(relation: string, opts?: { subjectField?: string; certField?: string }): RequirableDirective<P> {
1455
+ delegatedRole(
1456
+ relation: string,
1457
+ opts?: { subjectField?: string; certField?: string }
1458
+ ): RequirableDirective<P> {
1323
1459
  // DELEGATED-AUTHORITY DELIVERY (delegated_authority_births.md): this directive's write folds the
1324
1460
  // delegated `relation` tuple ONLY behind a carried DelegationCert — lowered into the `nomosDelegationGate`
1325
1461
  // era key, so the one gate re-verifies P's grant to K_root OFFLINE on every peer. Field names default to
1326
1462
  // the framework convention here (the kernel reads them from the law's declaration, hardcoding nothing).
1327
- const prior = (base as { delegatedRoleGate?: { parentKeyObject?: string; parentKeyField?: string } })
1328
- .delegatedRoleGate;
1463
+ const prior = (
1464
+ base as {
1465
+ delegatedRoleGate?: {
1466
+ parentKeyObject?: string;
1467
+ parentKeyField?: string;
1468
+ };
1469
+ }
1470
+ ).delegatedRoleGate;
1329
1471
  return makeRequirable({
1330
1472
  ...base,
1331
1473
  delegatedRoleGate: {
@@ -1337,14 +1479,25 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
1337
1479
  },
1338
1480
  });
1339
1481
  },
1340
- delegatedFrom(parent: { parentKeyObject: string; parentKeyField: string }): RequirableDirective<P> {
1482
+ delegatedFrom(parent: {
1483
+ parentKeyObject: string;
1484
+ parentKeyField: string;
1485
+ }): RequirableDirective<P> {
1341
1486
  // .delegatedFrom(parent): bind the grantor to this workspace's parent key (the platform P). Refines the
1342
1487
  // .delegatedRole() gate (a preceding .delegatedRole() supplies relation/fields; this adds the binding).
1343
- const g = (base as { delegatedRoleGate?: {
1344
- relation: string; subjectField: string; certField: string;
1345
- } }).delegatedRoleGate;
1488
+ const g = (
1489
+ base as {
1490
+ delegatedRoleGate?: {
1491
+ relation: string;
1492
+ subjectField: string;
1493
+ certField: string;
1494
+ };
1495
+ }
1496
+ ).delegatedRoleGate;
1346
1497
  if (g === undefined) {
1347
- throw new Error("directive.delegatedFrom(): call .delegatedRole(relation) before .delegatedFrom(parent)");
1498
+ throw new Error(
1499
+ "directive.delegatedFrom(): call .delegatedRole(relation) before .delegatedFrom(parent)"
1500
+ );
1348
1501
  }
1349
1502
  return makeRequirable({
1350
1503
  ...base,
@@ -1391,17 +1544,27 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
1391
1544
  // captured-read lane (#58). Both accumulate, dedup (ref types by value, queries
1392
1545
  // by id — later decl wins), sort — only the SET is the contract.
1393
1546
  const refTypes = reads.filter((r): r is string => typeof r === "string");
1394
- const queryDecls = reads.filter((r): r is QueryDecl => typeof r !== "string");
1547
+ const queryDecls = reads.filter(
1548
+ (r): r is QueryDecl => typeof r !== "string"
1549
+ );
1395
1550
  const merged = [...new Set([...base.declaredReads, ...refTypes])].sort();
1396
- const byId = new Map<string, QueryDecl>((base.declaredQueryReads ?? []).map((q) => [q.id, q]));
1551
+ const byId = new Map<string, QueryDecl>(
1552
+ (base.declaredQueryReads ?? []).map((q) => [q.id, q])
1553
+ );
1397
1554
  for (const q of queryDecls) byId.set(q.id, q);
1398
- const mergedQueries = [...byId.values()].sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
1399
- return makeRequirable({ ...base, declaredReads: merged, declaredQueryReads: mergedQueries });
1555
+ const mergedQueries = [...byId.values()].sort((a, b) =>
1556
+ a.id < b.id ? -1 : a.id > b.id ? 1 : 0
1557
+ );
1558
+ return makeRequirable({
1559
+ ...base,
1560
+ declaredReads: merged,
1561
+ declaredQueryReads: mergedQueries,
1562
+ });
1400
1563
  },
1401
1564
  readsFrom(
1402
1565
  source: string | FromPayloadRef,
1403
1566
  query: { id: string },
1404
- opts?: { policy: TrustPolicyDecl },
1567
+ opts?: { policy: TrustPolicyDecl }
1405
1568
  ): RequirableDirective<P> {
1406
1569
  // ATTESTED CROSS-WORKSPACE READ (slice B + dynamic policies): accumulate a STATIC (queryId, from)
1407
1570
  // edge OR a DYNAMIC (queryId, policy, fromPayload) edge, dedup by canonical key, sort (only the
@@ -1413,16 +1576,20 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
1413
1576
  throw new Error(
1414
1577
  `readsFrom(fromPayload('${source.payloadField}'), '${query.id}'): a payload-routed foreign ` +
1415
1578
  `read REQUIRES a trust policy — pass { policy: <trustPolicy(...) decl> } (the acceptable ` +
1416
- `sources are LAW-STATE, so the runtime-named workspace is judged against a folded allow-list).`,
1579
+ `sources are LAW-STATE, so the runtime-named workspace is judged against a folded allow-list).`
1417
1580
  );
1418
1581
  }
1419
1582
  if (!isTrustPolicyDecl(policy)) {
1420
1583
  throw new Error(
1421
1584
  `readsFrom(fromPayload('${source.payloadField}'), '${query.id}'): { policy } must be a ` +
1422
- `trustPolicy(...) declaration.`,
1585
+ `trustPolicy(...) declaration.`
1423
1586
  );
1424
1587
  }
1425
- entry = { queryId: query.id, policy: policy.policyId, fromPayload: source.payloadField };
1588
+ entry = {
1589
+ queryId: query.id,
1590
+ policy: policy.policyId,
1591
+ fromPayload: source.payloadField,
1592
+ };
1426
1593
  if (policy.monotone === true) __registerMonotoneForeignQuery(query.id);
1427
1594
  } else {
1428
1595
  entry = { queryId: query.id, from: source };
@@ -1432,19 +1599,27 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
1432
1599
  ? `0\\0${e.from}\\0${e.queryId}`
1433
1600
  : `1\\0${e.policy}\\0${e.fromPayload}\\0${e.queryId}`;
1434
1601
  const prior = base.declaredForeignReads ?? [];
1435
- const byKey = new Map<string, ForeignReadEdge>(prior.map((e) => [canon(e), e]));
1602
+ const byKey = new Map<string, ForeignReadEdge>(
1603
+ prior.map((e) => [canon(e), e])
1604
+ );
1436
1605
  byKey.set(canon(entry), entry);
1437
- const merged = [...byKey.values()].sort((a, b) => (canon(a) < canon(b) ? -1 : canon(a) > canon(b) ? 1 : 0));
1606
+ const merged = [...byKey.values()].sort((a, b) =>
1607
+ canon(a) < canon(b) ? -1 : canon(a) > canon(b) ? 1 : 0
1608
+ );
1438
1609
  // Every admitted foreign read advances the reader-local source frontier in-band.
1439
1610
  // This is a framework consequence of `.readsFrom`, so make it part of the typed
1440
1611
  // effect signature here; tenant authors must not know the bookkeeping aggregate.
1441
- return makeRequirable({ ...base, declaredForeignReads: merged })
1442
- .alsoEnsures(NomosSourceFrontier);
1612
+ return makeRequirable({
1613
+ ...base,
1614
+ declaredForeignReads: merged,
1615
+ }).alsoEnsures(NomosSourceFrontier);
1443
1616
  },
1444
1617
  emits(eventType: string, opts?: { max?: number }): RequirableDirective<P> {
1445
1618
  // Accumulate one event type onto any prior emits; a `max` bound is recorded only
1446
1619
  // when supplied (so `{}` vs `{max}` is a real contract difference).
1447
- const merged: Record<string, { max?: number }> = { ...base.declaredEmits };
1620
+ const merged: Record<string, { max?: number }> = {
1621
+ ...base.declaredEmits,
1622
+ };
1448
1623
  merged[eventType] = opts?.max !== undefined ? { max: opts.max } : {};
1449
1624
  return makeRequirable({ ...base, declaredEmits: merged });
1450
1625
  },
@@ -1457,20 +1632,35 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
1457
1632
  // .creates target + any .alsoCreates). Non-law, additive — stored like `description`.
1458
1633
  const createdIds = [
1459
1634
  ...(base.marker === "creates" ? [base.aggregateId] : []),
1460
- ...(base.secondaryOutputs ?? []).filter((o) => o.marker === "creates").map((o) => o.aggregateId),
1635
+ ...(base.secondaryOutputs ?? [])
1636
+ .filter((o) => o.marker === "creates")
1637
+ .map((o) => o.aggregateId),
1461
1638
  ];
1462
- return makeRequirable({ ...base, activityDescriptor: normalizeActivity(base.id, input, base.payloadSchema, createdIds) });
1639
+ return makeRequirable({
1640
+ ...base,
1641
+ activityDescriptor: normalizeActivity(
1642
+ base.id,
1643
+ input,
1644
+ base.payloadSchema,
1645
+ createdIds
1646
+ ),
1647
+ });
1463
1648
  },
1464
1649
  declaresRelation(rel: RelationDecl): RequirableDirective<P> {
1465
1650
  // Accumulate onto any prior relations — additive, non-destructive. A relation lands in
1466
1651
  // the manifest keyed by its `proposes` directive (cross_workspace.md §3.2.1).
1467
- return makeRequirable({ ...base, declaredRelations: [...base.declaredRelations, rel] });
1652
+ return makeRequirable({
1653
+ ...base,
1654
+ declaredRelations: [...base.declaredRelations, rel],
1655
+ });
1468
1656
  },
1469
1657
  requiresHostCapability(...portIds: string[]): RequirableDirective<P> {
1470
1658
  // Accumulate onto any prior host-capability ports, dedup, sort — order is incidental to
1471
1659
  // the HOST/PORT contract; only the SET of required port ids matters. DISTINCT symbol from
1472
1660
  // the AUTHZ `requiresCapability` (the two axes never conflate).
1473
- const merged = [...new Set([...base.declaredHostCapabilities, ...portIds])].sort();
1661
+ const merged = [
1662
+ ...new Set([...base.declaredHostCapabilities, ...portIds]),
1663
+ ].sort();
1474
1664
  return makeRequirable({ ...base, declaredHostCapabilities: merged });
1475
1665
  },
1476
1666
  births(): RequirableDirective<P> {
@@ -1482,10 +1672,18 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
1482
1672
  // `nomosReadGate` era key carries them by construction and the meter reads the `.births()` dispatch
1483
1673
  // auto-captures (see `executeDirectiveToIntent`) CAS-verify on every lane. The era is the bundle:
1484
1674
  // recompiling under this DSL is what arms the meter (every pre-era bundle replays byte-green).
1485
- const byId = new Map<string, QueryDecl>((base.declaredQueryReads ?? []).map((q) => [q.id, q]));
1675
+ const byId = new Map<string, QueryDecl>(
1676
+ (base.declaredQueryReads ?? []).map((q) => [q.id, q])
1677
+ );
1486
1678
  for (const q of BIRTH_METER_QUERIES) byId.set(q.id, q);
1487
- const mergedQueries = [...byId.values()].sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
1488
- return makeRequirable({ ...base, birthsChild: true, declaredQueryReads: mergedQueries });
1679
+ const mergedQueries = [...byId.values()].sort((a, b) =>
1680
+ a.id < b.id ? -1 : a.id > b.id ? 1 : 0
1681
+ );
1682
+ return makeRequirable({
1683
+ ...base,
1684
+ birthsChild: true,
1685
+ declaredQueryReads: mergedQueries,
1686
+ });
1489
1687
  },
1490
1688
  resolves(field: string): RequirableDirective<P> {
1491
1689
  // THE DESIGNATED SURFACED RESOLVER: record which Surfaced field this directive resolves. Field
@@ -1494,13 +1692,13 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
1494
1692
  if (typeof field !== "string" || field.length === 0) {
1495
1693
  throw new Error(
1496
1694
  `directive('${base.id}').resolves(field) needs a non-empty field name — the Surfaced field ` +
1497
- `this directive is the designated resolver of (e.g. .resolves("title")).`,
1695
+ `this directive is the designated resolver of (e.g. .resolves("title")).`
1498
1696
  );
1499
1697
  }
1500
1698
  if (base.resolvesField !== undefined && base.resolvesField !== field) {
1501
1699
  throw new Error(
1502
1700
  `directive('${base.id}').resolves("${field}"): already .resolves("${base.resolvesField}") — ` +
1503
- `a directive designates AT MOST ONE Surfaced field (write a second directive for the other).`,
1701
+ `a directive designates AT MOST ONE Surfaced field (write a second directive for the other).`
1504
1702
  );
1505
1703
  }
1506
1704
  return makeRequirable({ ...base, resolvesField: field });
@@ -1509,13 +1707,17 @@ function makeRequirable<P>(base: Directive<P>): RequirableDirective<P> {
1509
1707
  // PROOF-TOOLING PRODUCER MARKER (symmetric to `.requires`): record that this directive establishes
1510
1708
  // `relation` (its plan folds a granting `writeTuple`). NO kernel/manifest effect — a pure static hint
1511
1709
  // the proof generator's relation-bootstrap leg reads. Accumulate + dedup; additive + non-destructive.
1512
- const merged = [...new Set([...(base.grantsRelation ?? []), relation])].sort();
1710
+ const merged = [
1711
+ ...new Set([...(base.grantsRelation ?? []), relation]),
1712
+ ].sort();
1513
1713
  return makeRequirable({ ...base, grantsRelation: merged });
1514
1714
  },
1515
1715
  };
1516
1716
  }
1517
1717
 
1518
- export function directive<const Id extends string>(id: Id): DirectiveMarkerStep<Id> {
1718
+ export function directive<const Id extends string>(
1719
+ id: Id
1720
+ ): DirectiveMarkerStep<Id> {
1519
1721
  return new DirectiveMarkerStep(id);
1520
1722
  }
1521
1723
 
@@ -1525,7 +1727,7 @@ export function directive<const Id extends string>(id: Id): DirectiveMarkerStep<
1525
1727
  * framework lowering and temporary migration law, never a second application lane.
1526
1728
  */
1527
1729
  export function nomosImplementationDetail<T extends object>(
1528
- declaration: T,
1730
+ declaration: T
1529
1731
  ): T & { readonly businessBirthInternal: true } {
1530
1732
  return { ...declaration, businessBirthInternal: true };
1531
1733
  }