@githolon/dsl 0.102.5 → 0.103.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 (131) hide show
  1. package/compile_package.mjs +43 -2
  2. package/compile_proof.d.mts +47 -0
  3. package/compile_proof.mjs +343 -0
  4. package/dart/CHANGELOG.md +7 -0
  5. package/dart/lib/src/dev_cloud.dart +8 -8
  6. package/dart/lib/src/nms_generated_runtime.dart +2 -0
  7. package/dart/lib/src/runner/node-entry.mjs +5504 -1236
  8. package/dart/lib/src/runner/offline-install.mjs +4578 -528
  9. package/dart/lib/src/test_harness.dart +206 -152
  10. package/dart/lib/src/webview_bridge.dart +196 -89
  11. package/dart/pubspec.lock +1 -1
  12. package/dart/pubspec.yaml +2 -2
  13. package/dart/test/acquire_session_credentials_test.dart +4 -3
  14. package/dart/test/adv_realm_interference_test.dart +7 -6
  15. package/dart/test/cloud_bound_topology_test.dart +3 -3
  16. package/dart/test/cluster_births_test.dart +4 -3
  17. package/dart/test/cluster_device_keyed_acceptance_test.dart +10 -16
  18. package/dart/test/cluster_local_autosync_test.dart +3 -2
  19. package/dart/test/cluster_scale_test.dart +3 -2
  20. package/dart/test/dlq_session_surface_test.dart +7 -6
  21. package/dart/test/first_app_gauntlet_test.dart +14 -21
  22. package/dart/test/fixtures/wedge/fake-install.mjs +1 -1
  23. package/dart/test/four_layer_nested_topology_test.dart +4 -4
  24. package/dart/test/harness_phase_timeout_test.dart +2 -2
  25. package/dart/test/local_sync_inert_test.dart +1 -1
  26. package/dart/test/parent_signer_recovery_test.dart +2 -2
  27. package/dart/test/sealing_client_test.dart +4 -3
  28. package/dart/test/session_bound_test.dart +8 -7
  29. package/dart/test/test_harness_test.dart +13 -12
  30. package/dart/test/vo_read_typing_test.dart +4 -3
  31. package/dart/test/watch_after_offer_stall_test.dart +4 -3
  32. package/dart/test/webview_bridge_test.dart +102 -5
  33. package/dart_types/CHANGELOG.md +5 -0
  34. package/dart_types/lib/nomos_types.dart +9 -0
  35. package/dart_types/lib/src/nomos_ref.dart +20 -0
  36. package/dart_types/lib/src/optional_ref.dart +85 -0
  37. package/dart_types/lib/src/sha256_digest.dart +41 -0
  38. package/dart_types/lib/src/versioned_nomos_ref.dart +81 -0
  39. package/dart_types/pubspec.yaml +1 -1
  40. package/dart_types/test/optional_ref_test.dart +44 -0
  41. package/dart_types/test/sha256_digest_test.dart +18 -0
  42. package/package.json +9 -5
  43. package/runtime/generated-application-host.js +5365 -1105
  44. package/src/aggregate.ts +18 -0
  45. package/src/application_composition.ts +6 -32
  46. package/src/attested_core.ts +6 -3
  47. package/src/birth_meter.ts +1 -0
  48. package/src/birth_meter_ensure.ts +28 -2
  49. package/src/births.ts +1 -1
  50. package/src/build_package.ts +162 -538
  51. package/src/business_birth.ts +19 -3
  52. package/src/canonical_json.ts +21 -0
  53. package/src/check_package_main.ts +73 -33
  54. package/src/clear_directive.ts +19 -8
  55. package/src/codegen_dart.ts +305 -22
  56. package/src/codegen_dart_application.ts +844 -292
  57. package/src/codegen_dart_client.ts +1084 -407
  58. package/src/codegen_dart_scenario.ts +12 -12
  59. package/src/codegen_proof.ts +169 -39
  60. package/src/codegen_provider_dart.ts +17 -1
  61. package/src/codegen_ts.ts +298 -106
  62. package/src/compat_manifest.ts +2 -2
  63. package/src/compat_package_main.ts +8 -12
  64. package/src/compile_package_main.ts +1858 -590
  65. package/src/compose.ts +1 -1
  66. package/src/directive.ts +208 -15
  67. package/src/engine_entry.ts +165 -111
  68. package/src/evolve_preview.ts +29 -69
  69. package/src/extremum.ts +1 -1
  70. package/src/fields.ts +183 -4
  71. package/src/flow_gate.ts +75 -2
  72. package/src/framework/application_home.ts +2 -0
  73. package/src/framework/auth_provider_law.ts +2 -2
  74. package/src/framework/birth_meter.ts +7 -19
  75. package/src/framework/bootstrap.ts +0 -2
  76. package/src/framework/business_corrections.ts +9 -5
  77. package/src/framework/domain_lifecycle.ts +15 -29
  78. package/src/framework/encryption_scope.ts +2 -1
  79. package/src/framework/framework_aggregates.ts +2 -0
  80. package/src/framework/genesis.ts +16 -14
  81. package/src/framework/home.ts +20 -14
  82. package/src/framework/owned_custody.ts +9 -3
  83. package/src/framework/platform_admin.ts +3 -3
  84. package/src/framework/relations.ts +21 -13
  85. package/src/framework/signing_identity.ts +45 -40
  86. package/src/framework/workspace_invariant.ts +245 -0
  87. package/src/framework/workspaces.ts +23 -29
  88. package/src/index.ts +36 -16
  89. package/src/intent.ts +178 -6
  90. package/src/law_check.ts +32 -11
  91. package/src/law_graph.ts +2902 -0
  92. package/src/law_graph_usda.ts +1799 -0
  93. package/src/law_identity.ts +435 -0
  94. package/src/law_value_type.ts +230 -0
  95. package/src/lsp_server.ts +58 -29
  96. package/src/ops.ts +7 -0
  97. package/src/package_config.ts +141 -0
  98. package/src/package_dependencies.ts +108 -0
  99. package/src/package_dependency_usage.ts +150 -0
  100. package/src/package_source_imports.ts +71 -0
  101. package/src/plan_source_slice.ts +335 -0
  102. package/src/point_guard.ts +192 -0
  103. package/src/precondition.ts +44 -9
  104. package/src/read_projection_namespace.ts +1 -1
  105. package/src/runtime_zod.ts +44 -0
  106. package/src/secondary_ensure.ts +67 -14
  107. package/src/shape_compat.ts +1 -1
  108. package/src/stable_id_identity_bridge.ts +149 -0
  109. package/src/stable_id_lockfile.ts +140 -6
  110. package/src/stable_ids.ts +1 -1
  111. package/src/stable_ids_for_module.ts +348 -0
  112. package/src/stable_ids_types.ts +1 -1
  113. package/src/sum.ts +1 -1
  114. package/src/usd_state.ts +1 -1
  115. package/src/usda_relationship_integrity.ts +66 -0
  116. package/src/usda_text.ts +18 -0
  117. package/src/usdz.ts +78 -0
  118. package/src/value_object.ts +95 -0
  119. package/src/wire.ts +19 -0
  120. package/src/wire_encode.ts +22 -0
  121. package/src/workspace_sharding.ts +52 -36
  122. package/src/workspace_sharing.ts +28 -4
  123. package/src/zod_introspection.ts +1 -1
  124. package/dart/test/cluster_attested_test.dart +0 -201
  125. package/src/compile_engine.ts +0 -595
  126. package/src/manifest.ts +0 -1476
  127. package/src/read_projection_composition.ts +0 -117
  128. package/src/read_projection_manifest.ts +0 -115
  129. package/src/relation_composition.ts +0 -286
  130. package/src/usd.ts +0 -1967
  131. package/src/usd_layers.ts +0 -1776
package/src/intent.ts CHANGED
@@ -18,7 +18,12 @@ import type { Ports } from "./ctx.js";
18
18
  import type { PlannedOp } from "./ops.js";
19
19
  import type { Field } from "./fields.js";
20
20
  import type { AggregateHandle } from "./aggregate.js";
21
- import type { WorkspaceInvariantDecl } from "./framework/workspace_invariant.js";
21
+ import type {
22
+ InvariantReadBinding,
23
+ InvariantReadId,
24
+ InvariantReadIdPart,
25
+ WorkspaceInvariantDecl,
26
+ } from "./framework/workspace_invariant.js";
22
27
  import { businessBirthConsequence, type BusinessBirthDirective } from "./business_birth.js";
23
28
  import type { BusinessBirthDecl } from "./births.js";
24
29
  import type { WorkspaceSharingPolicy } from "./workspace_sharing.js";
@@ -31,6 +36,132 @@ export interface IntentStep<I = unknown, P = unknown> {
31
36
  readonly payload: (facts: I) => P;
32
37
  }
33
38
 
39
+ const PAYLOAD_TRACE_PATH = Symbol("nomos.intent.payload-trace-path");
40
+
41
+ type PayloadTrace = {
42
+ readonly [PAYLOAD_TRACE_PATH]: readonly string[];
43
+ };
44
+
45
+ /**
46
+ * An inert symbolic business payload used only while compiling application-language
47
+ * composition. A private payload mapping may carry a public field through unchanged;
48
+ * in that case the trace proves the exact public path without parsing JavaScript source.
49
+ * Any computation/coercion loses the trace and therefore cannot be miscompiled as a
50
+ * native read recipe.
51
+ */
52
+ function payloadTrace(path: readonly string[] = []): PayloadTrace {
53
+ const target = Object.create(null) as PayloadTrace;
54
+ return new Proxy(target, {
55
+ get(_target, property) {
56
+ if (property === PAYLOAD_TRACE_PATH) return path;
57
+ if (property === "then") return undefined;
58
+ if (property === Symbol.toPrimitive || property === "toString" || property === "valueOf") {
59
+ return () => {
60
+ throw new Error("computed application-language payload field is not a direct path");
61
+ };
62
+ }
63
+ return payloadTrace([...path, String(property)]);
64
+ },
65
+ });
66
+ }
67
+
68
+ function tracedPath(value: unknown): readonly string[] | undefined {
69
+ if (value === null || typeof value !== "object") return undefined;
70
+ const path = (value as Partial<PayloadTrace>)[PAYLOAD_TRACE_PATH];
71
+ return Array.isArray(path) ? path : undefined;
72
+ }
73
+
74
+ function valueAtPath(value: unknown, path: readonly string[]): unknown {
75
+ let current = value;
76
+ for (const part of path) {
77
+ if (current === null || (typeof current !== "object" && typeof current !== "function")) {
78
+ return undefined;
79
+ }
80
+ current = (current as Record<string, unknown>)[part];
81
+ }
82
+ return current;
83
+ }
84
+
85
+ function remapPayloadPath(
86
+ mapped: unknown,
87
+ privatePath: readonly string[],
88
+ ): readonly string[] | undefined {
89
+ return tracedPath(valueAtPath(mapped, privatePath));
90
+ }
91
+
92
+ function remapStepPayloadPath(
93
+ step: IntentStep<any, any>,
94
+ privatePath: readonly string[],
95
+ ): readonly string[] | undefined {
96
+ try {
97
+ return remapPayloadPath(step.payload(payloadTrace()), privatePath);
98
+ } catch {
99
+ return undefined;
100
+ }
101
+ }
102
+
103
+ function remapReadPart(
104
+ part: InvariantReadIdPart,
105
+ mapped: unknown,
106
+ ): InvariantReadIdPart | undefined {
107
+ if (part.source !== "payload") return part;
108
+ const path = remapPayloadPath(mapped, part.path);
109
+ return path === undefined ? undefined : { ...part, path };
110
+ }
111
+
112
+ function remapReadId(id: InvariantReadId, mapped: unknown): InvariantReadId | undefined {
113
+ if (id.source === "literal") return id;
114
+ if (id.source === "payload") {
115
+ const path = remapPayloadPath(mapped, id.path);
116
+ return path === undefined ? undefined : { ...id, path };
117
+ }
118
+ const parts: InvariantReadIdPart[] = [];
119
+ for (const part of id.parts) {
120
+ const remapped = remapReadPart(part, mapped);
121
+ if (remapped === undefined) return undefined;
122
+ parts.push(remapped);
123
+ }
124
+ return { ...id, parts };
125
+ }
126
+
127
+ /** Rewrite a private effect's typed point-read recipe onto its public business facts.
128
+ * Returns undefined unless every payload dependency is structurally proven. */
129
+ function remapNativeReads(
130
+ reads: readonly InvariantReadBinding[],
131
+ step: IntentStep<any, any>,
132
+ ): readonly InvariantReadBinding[] | undefined {
133
+ const needsPayload = reads.some((read) =>
134
+ read.eachPayloadPath !== undefined ||
135
+ read.id.source === "payload" ||
136
+ (read.id.source === "template" && read.id.parts.some((part) => part.source === "payload"))
137
+ );
138
+ if (!needsPayload) return reads;
139
+
140
+ let mapped: unknown;
141
+ try {
142
+ mapped = step.payload(payloadTrace());
143
+ } catch {
144
+ return undefined;
145
+ }
146
+
147
+ const out: InvariantReadBinding[] = [];
148
+ for (const read of reads) {
149
+ const eachPayloadPath = read.eachPayloadPath === undefined
150
+ ? undefined
151
+ : remapPayloadPath(mapped, read.eachPayloadPath);
152
+ if (read.eachPayloadPath !== undefined && eachPayloadPath === undefined) return undefined;
153
+
154
+ const id = remapReadId(read.id, mapped);
155
+ if (id === undefined) return undefined;
156
+ out.push({
157
+ ...read,
158
+ ...(eachPayloadPath === undefined ? {} : { eachPayloadPath }),
159
+ id,
160
+ });
161
+ }
162
+ return out;
163
+ }
164
+
34
165
  export interface BusinessIntent<I = unknown> extends Directive<I> {
35
166
  readonly [INTENT_BRAND]: true;
36
167
  readonly steps: readonly IntentStep<I, any>[];
@@ -235,10 +366,33 @@ class IntentBuilder<I> {
235
366
  }
236
367
 
237
368
  const preconditions: PreconditionDescriptor[] = this.steps.flatMap((step) =>
238
- (step.directive.preconditions ?? []).map((condition) => ({
239
- ...condition,
240
- idField: (facts: unknown) => condition.idField(step.payload(facts as I)),
241
- })),
369
+ (step.directive.preconditions ?? []).map((condition) => {
370
+ const {
371
+ idPayloadPath: privateIdPayloadPath,
372
+ readId: privateReadId,
373
+ ...rest
374
+ } = condition;
375
+ const publicIdPayloadPath = privateIdPayloadPath === undefined
376
+ ? undefined
377
+ : remapStepPayloadPath(step, privateIdPayloadPath);
378
+ let publicReadId: InvariantReadId | undefined;
379
+ if (privateReadId !== undefined) {
380
+ try {
381
+ publicReadId = remapReadId(
382
+ privateReadId,
383
+ step.payload(payloadTrace() as unknown as I),
384
+ );
385
+ } catch {
386
+ publicReadId = undefined;
387
+ }
388
+ }
389
+ return {
390
+ ...rest,
391
+ ...(publicIdPayloadPath === undefined ? {} : { idPayloadPath: publicIdPayloadPath }),
392
+ ...(publicReadId === undefined ? {} : { readId: publicReadId }),
393
+ idField: (facts: unknown) => condition.idField(step.payload(facts as I)),
394
+ };
395
+ }),
242
396
  );
243
397
  const queryReads = dedupeBy(
244
398
  this.steps.flatMap((step) => step.directive.declaredQueryReads ?? []),
@@ -289,6 +443,14 @@ class IntentBuilder<I> {
289
443
  },
290
444
  marker: primary.marker as ReferentialMarker,
291
445
  aggregateId: primary.aggregateId,
446
+ // Keep the typed local target on the lowered public intent. A narrow
447
+ // runtime plan may retain only this intent export; without the handle the
448
+ // engine cannot rebuild its aggregate registry entry and silently drops
449
+ // compound intents that also birth a child.
450
+ ...(primary.aggregate === undefined ? {} : { aggregate: primary.aggregate }),
451
+ ...(primary.outputCardinality !== undefined
452
+ ? { outputCardinality: primary.outputCardinality }
453
+ : {}),
292
454
  ...(secondaryOutputs.length > 0 ? { secondaryOutputs } : {}),
293
455
  payloadSchema: (birthSteps[0]?.directive.payloadSchema ?? this.contractDeclaration.accepts) as unknown as z.ZodType<I>,
294
456
  plan,
@@ -571,10 +733,20 @@ export function remapWorkspaceInvariantsForLanguage(
571
733
  // still validates every mapped consequence before it can commit.
572
734
  return (parsed.success ? parsed.data : mapped) as Record<string, unknown>;
573
735
  };
736
+ // Never carry a private payload path blindly onto a public intent. Prove the
737
+ // mapping structurally with inert path values; otherwise leave the selector
738
+ // compiler-visible so the native-only gate can name the exact unmapped law.
739
+ const remappedNativeReads = invariant.__nomosReadBindings === undefined
740
+ ? undefined
741
+ : remapNativeReads(invariant.__nomosReadBindings, use.step);
742
+ const { __nomosReadBindings: _privateReads, ...withoutPrivateReads } = invariant;
574
743
  out.push({
575
- ...invariant,
744
+ ...withoutPrivateReads,
576
745
  id: `${use.intent.id}__${invariant.id}`,
577
746
  on: use.intent.id,
747
+ ...(remappedNativeReads === undefined
748
+ ? {}
749
+ : { __nomosReadBindings: remappedNativeReads }),
578
750
  reads: (ctx) => invariant.reads({ ...ctx, intent: mapFacts(ctx.intent) }),
579
751
  assert: (snapshots, ctx) => invariant.assert(
580
752
  snapshots,
package/src/law_check.ts CHANGED
@@ -443,7 +443,9 @@ function unreadPayloadFindings(domain: string, dir: Directive<unknown>, probe: P
443
443
  // ROUTING lane consumes (the plan may pass it straight to read(…, {from}) without a tracked property
444
444
  // read on the sampled path) — a declared trust-edge field is never a dead field.
445
445
  for (const e of (dir as { declaredForeignReads?: ForeignReadEdge[] }).declaredForeignReads ?? []) {
446
- if ("fromPayload" in e && typeof e.fromPayload === "string") gateConsumed.add(e.fromPayload);
446
+ if ("fromPayload" in e && typeof e.fromPayload === "string") {
447
+ gateConsumed.add(e.fromPayload.split(".")[0]!);
448
+ }
447
449
  }
448
450
  const out: Finding[] = [];
449
451
  for (const f of requiredPayloadFields(dir.payloadSchema as z.ZodTypeAny)) {
@@ -1077,10 +1079,14 @@ function topLevelPortReadFindings(mod: DomainModule, portReadingDomains: Readonl
1077
1079
  // (b) a trustPolicy whose allow-list aggregate has no directive writing it → WARN (unpopulatable);
1078
1080
  // (c) a query declared BOTH as a local .reads() premise AND a foreign policy read → REFUSE (laundering).
1079
1081
 
1080
- /** The FOREIGN query ids a directive's plan actually reads (`read(q, …, { from })`) on the one probe
1081
- * sample — `undefined` when the plan can't be probed (unsynthesizable payload / it threw). A clean re-run
1082
- * under a read port that answers both lanes; every side-effect sink is drained (never leaks). */
1083
- function foreignReadsPerformed(dir: Directive<unknown>, where: string): Set<string> | undefined {
1082
+ /** The local and FOREIGN query ids a directive's plan actually reads on the one probe sample —
1083
+ * `undefined` when the plan can't be probed (unsynthesizable payload / it threw). This semantic
1084
+ * check is deliberately independent of bundle layout: moving the DSL runtime into an authenticated
1085
+ * shared USDA base must never make an undeclared read disappear from author-time diagnostics. */
1086
+ function readsPerformed(
1087
+ dir: Directive<unknown>,
1088
+ where: string,
1089
+ ): { readonly local: Set<string>; readonly foreign: Set<string> } | undefined {
1084
1090
  let synth: SynthesizedPayload;
1085
1091
  try {
1086
1092
  synth = synthesizeDirectivePayload(dir, where);
@@ -1089,7 +1095,8 @@ function foreignReadsPerformed(dir: Directive<unknown>, where: string): Set<stri
1089
1095
  }
1090
1096
  const payload: Record<string, unknown> = { ...synth.value };
1091
1097
  for (const f of synth.autoStamped) payload[f] = "2026-01-01T00:00:00Z";
1092
- const performed = new Set<string>();
1098
+ const local = new Set<string>();
1099
+ const foreign = new Set<string>();
1093
1100
  let ok = true;
1094
1101
  withBirthProbeGlobals(() => {
1095
1102
  const g = globalThis as unknown as { nomos: Record<string, unknown> };
@@ -1107,7 +1114,8 @@ function foreignReadsPerformed(dir: Directive<unknown>, where: string): Set<stri
1107
1114
  try {
1108
1115
  dir.plan(payload as never, deterministicPorts({ physical: 1, replica: 1, principal: "principal:probe" }));
1109
1116
  for (const r of __drainReads()) {
1110
- if ((r as { attestation?: unknown }).attestation !== undefined) performed.add(r.queryId);
1117
+ if ((r as { attestation?: unknown }).attestation !== undefined) foreign.add(r.queryId);
1118
+ else local.add(r.queryId);
1111
1119
  }
1112
1120
  } catch {
1113
1121
  ok = false;
@@ -1117,7 +1125,7 @@ function foreignReadsPerformed(dir: Directive<unknown>, where: string): Set<stri
1117
1125
  g.nomos.read = prevRead;
1118
1126
  }
1119
1127
  });
1120
- return ok ? performed : undefined;
1128
+ return ok ? { local, foreign } : undefined;
1121
1129
  }
1122
1130
 
1123
1131
  function attestedReadFindings(mod: DomainModule): Finding[] {
@@ -1158,10 +1166,23 @@ function attestedReadFindings(mod: DomainModule): Finding[] {
1158
1166
  }
1159
1167
  }
1160
1168
 
1161
- // (a) an undeclared foreign read — the plan routes read(q, …, { from }) with no trust edge for q.
1162
- const performed = foreignReadsPerformed(dir, `${domain}/${dir.id}`);
1169
+ const performed = readsPerformed(dir, `${domain}/${dir.id}`);
1163
1170
  if (performed !== undefined) {
1164
- for (const qid of performed) {
1171
+ // An ordinary captured read is a declared premise, not an incidental function call. Catch it
1172
+ // against the directive itself so package slicing/runtime-base changes cannot hide the error.
1173
+ for (const qid of performed.local) {
1174
+ if (!localQueryIds.has(qid)) {
1175
+ findings.push({
1176
+ domain,
1177
+ directiveId: dir.id,
1178
+ level: "refuse",
1179
+ what: `directive '${dir.id}' references read() for query '${qid}', but NO directive declares a captured-read query for that premise`,
1180
+ fix: `declare the read on this directive: .reads(theQueryDecl) (the same QueryDecl passed to read())`,
1181
+ });
1182
+ }
1183
+ }
1184
+ // (a) an undeclared foreign read — the plan routes read(q, …, { from }) with no trust edge for q.
1185
+ for (const qid of performed.foreign) {
1165
1186
  if (!declaredQueryIds.has(qid)) {
1166
1187
  findings.push({
1167
1188
  domain,