@githolon/dsl 0.103.7 → 0.103.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dart/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 0.64.7
2
+
3
+ - Bound generated application startup and referenced-workspace opens, preserving typed custody failures and
4
+ retryable custody while keeping law adoption inside the generated lifecycle.
5
+ - Preserve compound action output contracts through generated clients.
6
+
1
7
  ## 0.64.6
2
8
 
3
9
  - Publish the complete generated-application runtime already present in the coordinated source release,
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // <define:__NOMOS_KERNEL_RELEASE__>
4
- var define_NOMOS_KERNEL_RELEASE_default = { production: { hash: "79df1f00d23ed0f5dbcbf24071edf6e1667137d844248a40b456e13f4a85d176", version: "kernel-79df1f00", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience"], protocol: 1 }, testMint: { hash: "9eac1a5907116c8c7adbd89799d513e4463ef2f127cb14367e05576096fcc228", version: "kernel-9eac1a59", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience"], protocol: 1 } };
4
+ var define_NOMOS_KERNEL_RELEASE_default = { production: { hash: "171bd538ffccfbf248b2b25962d44676cf78466d5da2dfa32c8618ba5f38bf45", version: "kernel-171bd538", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience"], protocol: 1 }, testMint: { hash: "8b521aba87dd4dd54a81db9c3571c79ec5d0c600f84ca3796379fc5ba098068b", version: "kernel-8b521aba", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience"], protocol: 1 } };
5
5
 
6
6
  // runner/node-entry.ts
7
7
  import { createInterface } from "node:readline";
@@ -2345,7 +2345,7 @@ function recommendedActionSentence(action) {
2345
2345
  case "recompileClient":
2346
2346
  return "recompile the client (githolon compile / npx nomos-compile) against the deployed law";
2347
2347
  case "redeployLaw":
2348
- return "redeploy the package (POST /v2/workspaces/<ws>/domains) so the workspace runs the client's law";
2348
+ return "let the generated application prove, stage and govern adoption of its packaged law";
2349
2349
  case "reauth":
2350
2350
  return "re-authenticate (acquire a fresh auth-provider token) and reconnect";
2351
2351
  case "quarantineLocalSnapshotAndReclone":
@@ -8498,7 +8498,7 @@ function lawStatusOf(installed, clientHash) {
8498
8498
  function lawDriftMessage({ what, workspace, clientHash, installed }) {
8499
8499
  const short = (h) => `${String(h).slice(0, 12)}\u2026`;
8500
8500
  const runs = installed.length ? `runs law ${installed.slice(0, 6).map(short).join(", ")}${installed.length > 6 ? ` (+${installed.length - 6} more)` : ""}` : "has NO active law installed";
8501
- return `${what}: this client was generated under law ${short(clientHash)}, but workspace '${workspace}' ${runs} \u2014 the client and the workspace have drifted (or this domain was never deployed here). Recompile (githolon compile / npx nomos-compile) and redeploy the package (POST /v2/workspaces/${workspace}/domains), or regenerate the client against the deployed law (GET /v2/workspaces/${workspace}/domains names the hashes it runs). [law-drift]`;
8501
+ return `${what}: this client was generated under law ${short(clientHash)}, but workspace '${workspace}' ${runs} \u2014 the client and the workspace have drifted (or this domain was never installed here). The generated application will now prove, stage and govern adoption of its packaged model; if adoption is refused it surfaces a typed model decision instead of requiring application code to deploy law. [law-drift]`;
8502
8502
  }
8503
8503
  function birthOutcomeFailure(birthOutcomes) {
8504
8504
  if (!Array.isArray(birthOutcomes)) return null;
@@ -8736,7 +8736,12 @@ ${String(commit).toLowerCase()}`;
8736
8736
  remoteMain = await resolveBranchHead().catch(() => null);
8737
8737
  } else {
8738
8738
  await writeSkeleton();
8739
- remoteMain = await fetchRemoteHead();
8739
+ const _remoteStatus = span("receive", "boot: fetch remote status", "cloud-status");
8740
+ try {
8741
+ remoteMain = await fetchRemoteHead();
8742
+ } finally {
8743
+ _remoteStatus.end();
8744
+ }
8740
8745
  if (!remoteMain) {
8741
8746
  _bootLedger.end();
8742
8747
  if (!allowUnborn) throw new Error(`workspace '${workspace}' has no ledger main \u2014 create it first (POST /v2/workspaces/${workspace})`);
@@ -8759,6 +8764,10 @@ ${String(commit).toLowerCase()}`;
8759
8764
  let cloudLedgerCache = null;
8760
8765
  const watchTicks = /* @__PURE__ */ new Set();
8761
8766
  const watchStops = /* @__PURE__ */ new Set();
8767
+ let installedLawRowsCache;
8768
+ const invalidateInstalledLawRows = () => {
8769
+ installedLawRowsCache = void 0;
8770
+ };
8762
8771
  let _disposed = false;
8763
8772
  const nudgeWatches = () => {
8764
8773
  try {
@@ -9025,25 +9034,29 @@ ${String(commit).toLowerCase()}`;
9025
9034
  }
9026
9035
  };
9027
9036
  const installRowsInner = () => {
9037
+ if (installedLawRowsCache !== void 0) return installedLawRowsCache;
9028
9038
  try {
9029
9039
  const answer = JSON.parse(call("query", { queryBytes: qBytes({ op: "installedLaw" }) }));
9030
- if (Array.isArray(answer?.domains)) return answer.domains.map((domain) => ({
9031
- id: domain.installationId,
9032
- data: {
9033
- "spec.domainHash": domain.domainHash,
9034
- "spec.packageHash": domain.packageHash,
9035
- "spec.policyAggregate": domain.policyId,
9036
- "spec.installedBy": domain.installedBy,
9037
- "spec.authorityScope": domain.authorityScope,
9038
- "spec.supersedes": domain.supersedes,
9039
- "spec.lawClosureIdentity": domain.lawClosureIdentity,
9040
- "spec.dependencies": Array.isArray(domain.dependencies) ? domain.dependencies : [],
9041
- "spec.domainKeys": Array.isArray(domain.domainKeys) ? domain.domainKeys : [],
9042
- "status.phase": domain.phase,
9043
- "status.supersededBy": domain.supersededBy,
9044
- "metadata.generation": domain.generation
9045
- }
9046
- }));
9040
+ if (Array.isArray(answer?.domains)) {
9041
+ installedLawRowsCache = answer.domains.map((domain) => ({
9042
+ id: domain.installationId,
9043
+ data: {
9044
+ "spec.domainHash": domain.domainHash,
9045
+ "spec.packageHash": domain.packageHash,
9046
+ "spec.policyAggregate": domain.policyId,
9047
+ "spec.installedBy": domain.installedBy,
9048
+ "spec.authorityScope": domain.authorityScope,
9049
+ "spec.supersedes": domain.supersedes,
9050
+ "spec.lawClosureIdentity": domain.lawClosureIdentity,
9051
+ "spec.dependencies": Array.isArray(domain.dependencies) ? domain.dependencies : [],
9052
+ "spec.domainKeys": Array.isArray(domain.domainKeys) ? domain.domainKeys : [],
9053
+ "status.phase": domain.phase,
9054
+ "status.supersededBy": domain.supersededBy,
9055
+ "metadata.generation": domain.generation
9056
+ }
9057
+ }));
9058
+ return installedLawRowsCache;
9059
+ }
9047
9060
  if (typeof process !== "undefined" && process.env?.NOMOS_DEBUG_RAW) {
9048
9061
  console.error("[nomos] installedLaw meta-read returned no domains; using legacy projection fallback", answer);
9049
9062
  }
@@ -9053,10 +9066,11 @@ ${String(commit).toLowerCase()}`;
9053
9066
  }
9054
9067
  }
9055
9068
  try {
9056
- return JSON.parse(call("query", { queryBytes: qBytes({ kind: "query", queryId: "aggregatesByType", paramsJson: JSON.stringify({ __type: "DomainInstallation" }) }) })) || [];
9069
+ installedLawRowsCache = JSON.parse(call("query", { queryBytes: qBytes({ kind: "query", queryId: "aggregatesByType", paramsJson: JSON.stringify({ __type: "DomainInstallation" }) }) })) || [];
9057
9070
  } catch {
9058
- return null;
9071
+ installedLawRowsCache = null;
9059
9072
  }
9073
+ return installedLawRowsCache;
9060
9074
  };
9061
9075
  const installedLawInner = () => {
9062
9076
  const rows = installRowsInner();
@@ -9226,6 +9240,7 @@ ${String(commit).toLowerCase()}`;
9226
9240
  }
9227
9241
  }
9228
9242
  }
9243
+ invalidateInstalledLawRows();
9229
9244
  nudgeWatches();
9230
9245
  return {
9231
9246
  upToDate: false,
@@ -9857,6 +9872,9 @@ ${String(commit).toLowerCase()}`;
9857
9872
  created = Array.isArray(res.created) ? res.created : [];
9858
9873
  affected = Array.isArray(res.affected) ? res.affected : [];
9859
9874
  }
9875
+ if ((domain === "nomos" || domain === "bootstrap") && ["installDomain", "stageDomain", "promoteDomain", "rollbackDomain"].includes(directiveId)) {
9876
+ invalidateInstalledLawRows();
9877
+ }
9860
9878
  scheduleMaintenanceSoon();
9861
9879
  nudgeWatchesSoon();
9862
9880
  const bornFailure = birthOutcomeFailure(res.birthOutcomes);
@@ -9880,7 +9898,7 @@ ${String(commit).toLowerCase()}`;
9880
9898
  if (!domain.trim() || !candidateHash.trim()) {
9881
9899
  return { ok: false, stage: "preflight", error: "the generated model identity is missing" };
9882
9900
  }
9883
- const candidateInstallation = installRowsInner().find(
9901
+ const candidateInstallation = (installRowsInner() ?? []).find(
9884
9902
  (row) => row?.id === `domain-installation:${candidateHash}`
9885
9903
  );
9886
9904
  const candidatePhase = String(candidateInstallation?.data?.["status.phase"] ?? "");
@@ -6,7 +6,7 @@ var __export = (target, all) => {
6
6
  };
7
7
 
8
8
  // <define:__NOMOS_KERNEL_RELEASE__>
9
- var define_NOMOS_KERNEL_RELEASE_default = { production: { hash: "79df1f00d23ed0f5dbcbf24071edf6e1667137d844248a40b456e13f4a85d176", version: "kernel-79df1f00", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience"], protocol: 1 }, testMint: { hash: "9eac1a5907116c8c7adbd89799d513e4463ef2f127cb14367e05576096fcc228", version: "kernel-9eac1a59", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience"], protocol: 1 } };
9
+ var define_NOMOS_KERNEL_RELEASE_default = { production: { hash: "171bd538ffccfbf248b2b25962d44676cf78466d5da2dfa32c8618ba5f38bf45", version: "kernel-171bd538", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience"], protocol: 1 }, testMint: { hash: "8b521aba87dd4dd54a81db9c3571c79ec5d0c600f84ca3796379fc5ba098068b", version: "kernel-8b521aba", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience"], protocol: 1 } };
10
10
 
11
11
  // runner/offline-install.ts
12
12
  import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync } from "node:fs";
package/dart/pubspec.lock CHANGED
@@ -191,7 +191,7 @@ packages:
191
191
  path: "../dart_types"
192
192
  relative: true
193
193
  source: path
194
- version: "0.8.3"
194
+ version: "0.8.4"
195
195
  package_config:
196
196
  dependency: "direct main"
197
197
  description:
package/dart/pubspec.yaml CHANGED
@@ -7,7 +7,7 @@ repository: https://github.com/Captain-App/nomos2
7
7
  description: >-
8
8
  Nomos 2 Dart client — generated domain values, intent payloads and application
9
9
  lifecycle types over the typed Nomos kernel protocol and USDA custody model.
10
- version: 0.64.6
10
+ version: 0.64.7
11
11
 
12
12
  environment:
13
13
  sdk: ^3.5.0
@@ -16,7 +16,7 @@ dependencies:
16
16
  # The pure-data core (wire types, offer codec, NomosReads, schema validation, error
17
17
  # info). nomos_client depends on and re-exports it, so existing imports are unchanged.
18
18
  # For local monorepo dev, pubspec_overrides.yaml points this at ../dart_types.
19
- nomos_types: ^0.8.3
19
+ nomos_types: ^0.8.4
20
20
  json_schema: ^5.2.2
21
21
  crypto: ^3.0.0
22
22
  package_config: ^2.1.0
@@ -92,6 +92,16 @@ void main() {
92
92
  expect(a.recommendedAction, NomosRecommendedAction.reauth);
93
93
  });
94
94
 
95
+ test('law adoption advice keeps cloud deployment inside generated runtime',
96
+ () {
97
+ final advice =
98
+ NomosRecommendedAction.sentence(NomosRecommendedAction.redeployLaw);
99
+ expect(advice, contains('generated application'));
100
+ expect(advice, contains('govern adoption'));
101
+ expect(advice, isNot(contains('POST')));
102
+ expect(advice, isNot(contains('/v2/workspaces')));
103
+ });
104
+
95
105
  test('load.* mints LoadError carrying the artifact + source URL', () {
96
106
  final e = nomosErrorFromInfo(info('nomos.load.wasm_fetch_failed', attrs: {
97
107
  'nomos.load.artifact': 'holon.wasm',
@@ -1,3 +1,8 @@
1
+ ## 0.8.4
2
+
3
+ - Expose bounded generated-startup and referenced-workspace custody failures as typed data so applications
4
+ can render and retry the exact kernel refusal instead of remaining on an indefinite loading surface.
5
+
1
6
  ## 0.8.3
2
7
 
3
8
  - Add the typed `GitObjectId` value used to identify immutable custody objects without falling back to
@@ -51,7 +51,9 @@ class NomosRecommendedAction {
51
51
  /// Regenerate the typed client against the deployed law (`githolon compile` / `npx nomos-compile`).
52
52
  static const recompileClient = 'recompileClient';
53
53
 
54
- /// Redeploy the client's law package to the workspace (`POST /v2/workspaces/<ws>/domains`).
54
+ /// Ask the generated application to govern adoption of its packaged law.
55
+ /// The stable value retains its original spelling for wire compatibility;
56
+ /// application code must not implement deployment itself.
55
57
  static const redeployLaw = 'redeployLaw';
56
58
 
57
59
  /// Re-acquire a fresh auth-provider token and reconnect.
@@ -98,7 +100,7 @@ class NomosRecommendedAction {
98
100
  case recompileClient:
99
101
  return 'recompile the client (githolon compile / npx nomos-compile) against the deployed law';
100
102
  case redeployLaw:
101
- return 'redeploy the package (POST /v2/workspaces/<ws>/domains) so the workspace runs the client\'s law';
103
+ return 'let the generated application prove, stage and govern adoption of its packaged law';
102
104
  case reauth:
103
105
  return 're-authenticate (acquire a fresh auth-provider token) and reconnect';
104
106
  case quarantineLocalSnapshotAndReclone:
@@ -7,9 +7,9 @@ name: nomos_types
7
7
  repository: https://github.com/Captain-App/nomos2
8
8
  description: >-
9
9
  Pure kernel wire/data types for Nomos Dart frontends — no transport, no bridge,
10
- no runtime. The hand-written serde-JSON-compatible types plus the offer codec,
10
+ no runtime. Typed protobuf and USDA boundary values plus the offer codec,
11
11
  reactive read engine, schema validation, and data-only error/trace types.
12
- version: 0.8.3
12
+ version: 0.8.4
13
13
 
14
14
  environment:
15
15
  sdk: ^3.5.0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@githolon/dsl",
3
- "version": "0.103.7",
3
+ "version": "0.103.8",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "Nomos 2 domain-authoring DSL: aggregates + directives in TS, executed and encoded to the Rust kernel's wire shapes.",
@@ -1404,7 +1404,7 @@ function recommendedActionSentence(action) {
1404
1404
  case "recompileClient":
1405
1405
  return "recompile the client (githolon compile / npx nomos-compile) against the deployed law";
1406
1406
  case "redeployLaw":
1407
- return "redeploy the package (POST /v2/workspaces/<ws>/domains) so the workspace runs the client's law";
1407
+ return "let the generated application prove, stage and govern adoption of its packaged law";
1408
1408
  case "reauth":
1409
1409
  return "re-authenticate (acquire a fresh auth-provider token) and reconnect";
1410
1410
  case "quarantineLocalSnapshotAndReclone":
@@ -7557,7 +7557,7 @@ function lawStatusOf(installed, clientHash) {
7557
7557
  function lawDriftMessage({ what, workspace, clientHash, installed }) {
7558
7558
  const short = (h) => `${String(h).slice(0, 12)}\u2026`;
7559
7559
  const runs = installed.length ? `runs law ${installed.slice(0, 6).map(short).join(", ")}${installed.length > 6 ? ` (+${installed.length - 6} more)` : ""}` : "has NO active law installed";
7560
- return `${what}: this client was generated under law ${short(clientHash)}, but workspace '${workspace}' ${runs} \u2014 the client and the workspace have drifted (or this domain was never deployed here). Recompile (githolon compile / npx nomos-compile) and redeploy the package (POST /v2/workspaces/${workspace}/domains), or regenerate the client against the deployed law (GET /v2/workspaces/${workspace}/domains names the hashes it runs). [law-drift]`;
7560
+ return `${what}: this client was generated under law ${short(clientHash)}, but workspace '${workspace}' ${runs} \u2014 the client and the workspace have drifted (or this domain was never installed here). The generated application will now prove, stage and govern adoption of its packaged model; if adoption is refused it surfaces a typed model decision instead of requiring application code to deploy law. [law-drift]`;
7561
7561
  }
7562
7562
  function birthOutcomeFailure(birthOutcomes) {
7563
7563
  if (!Array.isArray(birthOutcomes)) return null;
@@ -7795,7 +7795,12 @@ ${String(commit).toLowerCase()}`;
7795
7795
  remoteMain = await resolveBranchHead().catch(() => null);
7796
7796
  } else {
7797
7797
  await writeSkeleton();
7798
- remoteMain = await fetchRemoteHead();
7798
+ const _remoteStatus = span("receive", "boot: fetch remote status", "cloud-status");
7799
+ try {
7800
+ remoteMain = await fetchRemoteHead();
7801
+ } finally {
7802
+ _remoteStatus.end();
7803
+ }
7799
7804
  if (!remoteMain) {
7800
7805
  _bootLedger.end();
7801
7806
  if (!allowUnborn) throw new Error(`workspace '${workspace}' has no ledger main \u2014 create it first (POST /v2/workspaces/${workspace})`);
@@ -7818,6 +7823,10 @@ ${String(commit).toLowerCase()}`;
7818
7823
  let cloudLedgerCache = null;
7819
7824
  const watchTicks = /* @__PURE__ */ new Set();
7820
7825
  const watchStops = /* @__PURE__ */ new Set();
7826
+ let installedLawRowsCache;
7827
+ const invalidateInstalledLawRows = () => {
7828
+ installedLawRowsCache = void 0;
7829
+ };
7821
7830
  let _disposed = false;
7822
7831
  const nudgeWatches = () => {
7823
7832
  try {
@@ -8084,25 +8093,29 @@ ${String(commit).toLowerCase()}`;
8084
8093
  }
8085
8094
  };
8086
8095
  const installRowsInner = () => {
8096
+ if (installedLawRowsCache !== void 0) return installedLawRowsCache;
8087
8097
  try {
8088
8098
  const answer = JSON.parse(call("query", { queryBytes: qBytes({ op: "installedLaw" }) }));
8089
- if (Array.isArray(answer?.domains)) return answer.domains.map((domain) => ({
8090
- id: domain.installationId,
8091
- data: {
8092
- "spec.domainHash": domain.domainHash,
8093
- "spec.packageHash": domain.packageHash,
8094
- "spec.policyAggregate": domain.policyId,
8095
- "spec.installedBy": domain.installedBy,
8096
- "spec.authorityScope": domain.authorityScope,
8097
- "spec.supersedes": domain.supersedes,
8098
- "spec.lawClosureIdentity": domain.lawClosureIdentity,
8099
- "spec.dependencies": Array.isArray(domain.dependencies) ? domain.dependencies : [],
8100
- "spec.domainKeys": Array.isArray(domain.domainKeys) ? domain.domainKeys : [],
8101
- "status.phase": domain.phase,
8102
- "status.supersededBy": domain.supersededBy,
8103
- "metadata.generation": domain.generation
8104
- }
8105
- }));
8099
+ if (Array.isArray(answer?.domains)) {
8100
+ installedLawRowsCache = answer.domains.map((domain) => ({
8101
+ id: domain.installationId,
8102
+ data: {
8103
+ "spec.domainHash": domain.domainHash,
8104
+ "spec.packageHash": domain.packageHash,
8105
+ "spec.policyAggregate": domain.policyId,
8106
+ "spec.installedBy": domain.installedBy,
8107
+ "spec.authorityScope": domain.authorityScope,
8108
+ "spec.supersedes": domain.supersedes,
8109
+ "spec.lawClosureIdentity": domain.lawClosureIdentity,
8110
+ "spec.dependencies": Array.isArray(domain.dependencies) ? domain.dependencies : [],
8111
+ "spec.domainKeys": Array.isArray(domain.domainKeys) ? domain.domainKeys : [],
8112
+ "status.phase": domain.phase,
8113
+ "status.supersededBy": domain.supersededBy,
8114
+ "metadata.generation": domain.generation
8115
+ }
8116
+ }));
8117
+ return installedLawRowsCache;
8118
+ }
8106
8119
  if (typeof process !== "undefined" && process.env?.NOMOS_DEBUG_RAW) {
8107
8120
  console.error("[nomos] installedLaw meta-read returned no domains; using legacy projection fallback", answer);
8108
8121
  }
@@ -8112,10 +8125,11 @@ ${String(commit).toLowerCase()}`;
8112
8125
  }
8113
8126
  }
8114
8127
  try {
8115
- return JSON.parse(call("query", { queryBytes: qBytes({ kind: "query", queryId: "aggregatesByType", paramsJson: JSON.stringify({ __type: "DomainInstallation" }) }) })) || [];
8128
+ installedLawRowsCache = JSON.parse(call("query", { queryBytes: qBytes({ kind: "query", queryId: "aggregatesByType", paramsJson: JSON.stringify({ __type: "DomainInstallation" }) }) })) || [];
8116
8129
  } catch {
8117
- return null;
8130
+ installedLawRowsCache = null;
8118
8131
  }
8132
+ return installedLawRowsCache;
8119
8133
  };
8120
8134
  const installedLawInner = () => {
8121
8135
  const rows = installRowsInner();
@@ -8285,6 +8299,7 @@ ${String(commit).toLowerCase()}`;
8285
8299
  }
8286
8300
  }
8287
8301
  }
8302
+ invalidateInstalledLawRows();
8288
8303
  nudgeWatches();
8289
8304
  return {
8290
8305
  upToDate: false,
@@ -8916,6 +8931,9 @@ ${String(commit).toLowerCase()}`;
8916
8931
  created = Array.isArray(res.created) ? res.created : [];
8917
8932
  affected = Array.isArray(res.affected) ? res.affected : [];
8918
8933
  }
8934
+ if ((domain === "nomos" || domain === "bootstrap") && ["installDomain", "stageDomain", "promoteDomain", "rollbackDomain"].includes(directiveId)) {
8935
+ invalidateInstalledLawRows();
8936
+ }
8919
8937
  scheduleMaintenanceSoon();
8920
8938
  nudgeWatchesSoon();
8921
8939
  const bornFailure = birthOutcomeFailure(res.birthOutcomes);
@@ -8939,7 +8957,7 @@ ${String(commit).toLowerCase()}`;
8939
8957
  if (!domain.trim() || !candidateHash.trim()) {
8940
8958
  return { ok: false, stage: "preflight", error: "the generated model identity is missing" };
8941
8959
  }
8942
- const candidateInstallation = installRowsInner().find(
8960
+ const candidateInstallation = (installRowsInner() ?? []).find(
8943
8961
  (row) => row?.id === `domain-installation:${candidateHash}`
8944
8962
  );
8945
8963
  const candidatePhase = String(candidateInstallation?.data?.["status.phase"] ?? "");
@@ -284,7 +284,7 @@ function dartActionOutputs(
284
284
  const fields = new Set<string>();
285
285
  return outputs.map((output) => {
286
286
  const dartType = concreteClassName(output.aggregateId);
287
- const field = member(dartType);
287
+ const field = member(output.many ? plural(dartType) : dartType);
288
288
  if (fields.has(field)) {
289
289
  throw new Error(
290
290
  `Dart application result for '${directive.id}' has two aggregate consequences named '${field}'; ` +
@@ -1140,7 +1140,11 @@ export function generateDartApplication(
1140
1140
  ` Future<${targetApplication}> _nmsOpenReference(NomosRef<${rootType}> reference) {`,
1141
1141
  ` final workspace = NmsInternalNomosRefs.workspace(reference);`,
1142
1142
  ` final existing = _nmsApplications[workspace];`,
1143
- ` if (existing != null) return existing;`,
1143
+ ` if (existing != null) {`,
1144
+ ` return NmsInternalApplicationHost.nmsInternalAwaitReferencedApplication(`,
1145
+ ` workspace: workspace, opening: existing,`,
1146
+ ` );`,
1147
+ ` }`,
1144
1148
  ` late final Future<${targetApplication}> opened;`,
1145
1149
  ` opened = (() async {`,
1146
1150
  ` try {`,
@@ -1153,7 +1157,9 @@ export function generateDartApplication(
1153
1157
  ` }`,
1154
1158
  ` })();`,
1155
1159
  ` _nmsApplications[workspace] = opened;`,
1156
- ` return opened;`,
1160
+ ` return NmsInternalApplicationHost.nmsInternalAwaitReferencedApplication(`,
1161
+ ` workspace: workspace, opening: opened,`,
1162
+ ` );`,
1157
1163
  ` }`,
1158
1164
  ``,
1159
1165
  ` /// Open the workspace named by a typed ${rootType} custody reference.`,
@@ -2080,7 +2086,7 @@ export function generateDartApplication(
2080
2086
  ` Widget Function(BuildContext context, Object error, VoidCallback retry)? errorBuilder,`,
2081
2087
  ` ApplicationModelChange? onModelChange,`,
2082
2088
  ` ValueChanged<NomosApplicationStartupState>? onStartupStateChanged,`,
2083
- ` Duration startupTimeout = const Duration(seconds: 45),`,
2089
+ ` Duration startupTimeout = const Duration(minutes: 3),`,
2084
2090
  ` }) => NmsInternalApplicationHost.home<${application}>(`,
2085
2091
  ` key: key, cloud: cloud, application: application, signIn: signIn,`,
2086
2092
  ` bind: nomosInternalBind${application}, builder: builder,`,
@@ -1642,12 +1642,12 @@ const dartTypesImportFor = (generatedSource: string): string => {
1642
1642
  * just the floor generated code needs — a lagging pin forces tenants into dependency_overrides. */
1643
1643
  // 0.3.0: SurfacedValue<T>/SurfacedObservation/PendingConflictRow — generated Surfaced-field typing +
1644
1644
  // the pendingConflicts read rows.
1645
- const NOMOS_TYPES_DEP = "^0.8.3";
1645
+ const NOMOS_TYPES_DEP = "^0.8.4";
1646
1646
  // 0.48.x: session-bound clients (XClient.bind/NomosClientInterface/DomainClientSessionMismatch/
1647
1647
  // DomainNotInstalledForSession, engine.follow, pendingConflicts lanes) — the generated client
1648
1648
  // REQUIRES this surface. 0.48.1 fixes NomosSession.watchPendingConflicts delegation.
1649
- const NOMOS_CLIENT_DEP = "^0.64.6";
1650
- const NOMOS_FLUTTER_DEP = "^0.63.9";
1649
+ const NOMOS_CLIENT_DEP = "^0.64.7";
1650
+ const NOMOS_FLUTTER_DEP = "^0.63.10";
1651
1651
  // DRIFT TRIPWIRE: pubspec_pins.test.ts asserts these equal the CURRENT versions in dsl/dart/pubspec.yaml
1652
1652
  // and dsl/dart_types/pubspec.yaml — a Dart release without this bump fails the suite, so tenants never
1653
1653
  // land back in dependency_overrides (the exact co2 report this closes, third occurrence).
@@ -1917,14 +1917,25 @@ function generatedPackageApplication(
1917
1917
  ` /// Prove, adopt or restore the package law against this workspace's exact history.`,
1918
1918
  ` ${rootMember.prefix}.NomosModel get model => ${rootMember.member}.model;`,
1919
1919
  ``,
1920
- ` /// Current durability and convergence across this business application.`,
1921
- ` ApplicationStatus get currentStatus => NmsInternalApplicationHost.currentApplicationStatus(_nmsSession);`,
1920
+ ` /// Current durability and convergence for the receiving-group workspace.`,
1921
+ ` /// A slow or offline sibling never makes this workspace's readiness ambiguous.`,
1922
+ ` ApplicationStatus get currentStatus => NmsInternalApplicationHost.currentStatus(_nmsSession);`,
1922
1923
  ``,
1923
- ` /// React whenever this application saves, receives work, goes offline or needs attention.`,
1924
- ` Stream<ApplicationStatus> watchStatus() => NmsInternalApplicationHost.watchApplicationStatus(_nmsSession);`,
1924
+ ` /// React whenever this receiving group saves, receives work, goes offline or needs attention.`,
1925
+ ` Stream<ApplicationStatus> watchStatus() => NmsInternalApplicationHost.watchStatus(_nmsSession);`,
1925
1926
  ``,
1926
- ` /// Wait until accepted local work is in shared custody and this application has caught up.`,
1927
+ ` /// Wait until this receiving group's accepted work is in custody and caught up.`,
1927
1928
  ` Future<void> whenCurrent({Duration timeout = const Duration(minutes: 2)}) =>`,
1929
+ ` NmsInternalApplicationHost.whenCurrent(_nmsSession, timeout: timeout);`,
1930
+ ``,
1931
+ ` /// Aggregate posture across every child currently owned by this generated application.`,
1932
+ ` ApplicationStatus get applicationStatus => NmsInternalApplicationHost.currentApplicationStatus(_nmsSession);`,
1933
+ ``,
1934
+ ` /// React to aggregate posture across every generated child currently in this application plane.`,
1935
+ ` Stream<ApplicationStatus> watchApplicationStatus() => NmsInternalApplicationHost.watchApplicationStatus(_nmsSession);`,
1936
+ ``,
1937
+ ` /// Explicitly wait for every generated child currently owned by this application.`,
1938
+ ` Future<void> whenApplicationCurrent({Duration timeout = const Duration(minutes: 2)}) =>`,
1928
1939
  ` NmsInternalApplicationHost.whenApplicationCurrent(_nmsSession, timeout: timeout);`,
1929
1940
  ...(hasInvitations
1930
1941
  ? [
@@ -1973,7 +1984,7 @@ function generatedPackageApplication(
1973
1984
  ` Widget Function(BuildContext context, Object error, VoidCallback retry)? errorBuilder,`,
1974
1985
  ` ApplicationModelChange? onModelChange,`,
1975
1986
  ` ValueChanged<NomosApplicationStartupState>? onStartupStateChanged,`,
1976
- ` Duration startupTimeout = const Duration(seconds: 45),`,
1987
+ ` Duration startupTimeout = const Duration(minutes: 3),`,
1977
1988
  ` }) => NmsInternalApplicationHost.home<${application}>(`,
1978
1989
  ` key: key, cloud: cloud, application: application, signIn: signIn,`,
1979
1990
  ` bind: nomosInternalBind${application}, builder: builder,`,
@@ -2544,7 +2555,8 @@ function emitDartPackages(
2544
2555
  "library;",
2545
2556
  "",
2546
2557
  `export 'package:${packages.types}/${genRel}/${businessSharedFile}';`,
2547
- `export 'package:nomos_flutter/src/generated_application_host.dart' show ApplicationModelApproval, ApplicationModelDecision, ApplicationModelPolicy, ApplicationModelReview;`,
2558
+ `export 'package:nomos_flutter/src/generated_application_host.dart' show ApplicationModelApproval, ApplicationModelDecision, ApplicationModelPolicy, ApplicationModelReview, NomosApplicationStartupPhase, NomosApplicationStartupState, NomosApplicationStartupTimeout, NomosWorkspaceOpenTimeout;`,
2559
+ `export 'package:nomos_types/nomos_types.dart' show CustodyError, CustodyPhase, CustodySource, NomosRecommendedAction;`,
2548
2560
  ...tenantTypesExportKeys
2549
2561
  .map((file) => {
2550
2562
  const names = tenantDartExportNames(typesSources.get(file) ?? "");
package/src/intent.ts CHANGED
@@ -9,6 +9,7 @@
9
9
  import type { z } from "zod";
10
10
 
11
11
  import type {
12
+ BusinessSourceTrust,
12
13
  Directive,
13
14
  PreconditionDescriptor,
14
15
  ReferentialMarker,
@@ -233,11 +234,38 @@ function unsupportedKernelGate(directive: Directive<any>): string | undefined {
233
234
  if (directive.delegatedRoleGate !== undefined) return "delegated authority";
234
235
  if (directive.firstDeviceEnrollGate !== undefined) return "first-device enrollment";
235
236
  if (directive.certifiesEraGate !== undefined) return "era certification";
236
- if (directive.businessSourceTrust !== undefined) return "source-trust preflight";
237
237
  if ((directive.businessRecordInputs?.length ?? 0) > 0) return "record-input binding";
238
238
  return undefined;
239
239
  }
240
240
 
241
+ function remapBusinessSourceTrust<I>(
242
+ step: IntentStep<I, any>,
243
+ trust: BusinessSourceTrust,
244
+ ): BusinessSourceTrust {
245
+ const field = (privatePath: string): string => {
246
+ const mapped = remapStepPayloadPath(step, privatePath.split("."));
247
+ if (mapped === undefined || mapped.length === 0) {
248
+ throw new Error(
249
+ `compound intent cannot remap source-trust field '${privatePath}' from '${step.directive.id}'`,
250
+ );
251
+ }
252
+ return mapped.join(".");
253
+ };
254
+ return {
255
+ viaDirectiveId: trust.viaDirectiveId,
256
+ fromPayload: field(trust.fromPayload),
257
+ queryId: trust.queryId,
258
+ queryArgs: Object.fromEntries(
259
+ Object.entries(trust.queryArgs).map(([target, source]) => [target, field(source)]),
260
+ ),
261
+ copy: Object.fromEntries(
262
+ Object.entries(trust.copy).map(([target, source]) => [target, field(source)]),
263
+ ),
264
+ genesisField: trust.genesisField,
265
+ keyHashesField: trust.keyHashesField,
266
+ };
267
+ }
268
+
241
269
  const dedupeBy = <T>(values: readonly T[], key: (value: T) => string): T[] => {
242
270
  const out: T[] = [];
243
271
  const seen = new Set<string>();
@@ -333,24 +361,44 @@ class IntentBuilder<I> {
333
361
 
334
362
  const primary = this.steps.find((step) => step.directive.birthsChild !== true)?.directive
335
363
  ?? this.steps[0]!.directive;
336
- const outputs: SecondaryOutput[] = [];
337
- for (const [index, step] of this.steps.entries()) {
364
+ const allOutputs: SecondaryOutput[] = [];
365
+ for (const step of this.steps) {
338
366
  const candidate = step.directive;
339
- if (
340
- candidate.birthsChild !== true &&
341
- candidate !== primary &&
342
- !(candidate.aggregateId === primary.aggregateId && candidate.marker === primary.marker)
343
- ) {
344
- outputs.push({ aggregateId: candidate.aggregateId, marker: candidate.marker });
367
+ if (candidate.birthsChild !== true) {
368
+ allOutputs.push({
369
+ aggregateId: candidate.aggregateId,
370
+ marker: candidate.marker,
371
+ ...(candidate.outputCardinality === "many" ? { many: true } : {}),
372
+ ...(candidate.outputCardinality === "optional" ? { optional: true } : {}),
373
+ });
374
+ allOutputs.push(...(candidate.secondaryOutputs ?? []));
345
375
  }
346
- if (candidate.birthsChild !== true) outputs.push(...(candidate.secondaryOutputs ?? []));
347
376
  }
348
- const secondaryOutputs = dedupeBy(
349
- outputs.filter(
350
- (output) => !(output.aggregateId === primary.aggregateId && output.marker === primary.marker),
351
- ),
352
- (output) => `${output.marker}\0${output.aggregateId}`,
377
+ const outputGroups = new Map<string, SecondaryOutput[]>();
378
+ for (const output of allOutputs) {
379
+ const key = `${output.marker}\0${output.aggregateId}`;
380
+ outputGroups.set(key, [...(outputGroups.get(key) ?? []), output]);
381
+ }
382
+ const composedOutput = (group: readonly SecondaryOutput[]): SecondaryOutput => ({
383
+ aggregateId: group[0]!.aggregateId,
384
+ marker: group[0]!.marker,
385
+ ...(group.length > 1 || group.some((output) => output.many === true)
386
+ ? { many: true }
387
+ : group[0]!.optional === true
388
+ ? { optional: true }
389
+ : {}),
390
+ });
391
+ const primaryOutput = composedOutput(
392
+ outputGroups.get(`${primary.marker}\0${primary.aggregateId}`) ?? [{
393
+ aggregateId: primary.aggregateId,
394
+ marker: primary.marker,
395
+ }],
353
396
  );
397
+ const secondaryOutputs = [...outputGroups.values()]
398
+ .map(composedOutput)
399
+ .filter(
400
+ (output) => !(output.aggregateId === primary.aggregateId && output.marker === primary.marker),
401
+ );
354
402
  const inferredReturns = [
355
403
  primary.aggregateId,
356
404
  ...secondaryOutputs.map((output) => output.aggregateId),
@@ -421,6 +469,16 @@ class IntentBuilder<I> {
421
469
  }
422
470
  }
423
471
  const relationGate = oneStaticRelationGate(this.steps);
472
+ const sourceTrusts = this.steps.flatMap((step) =>
473
+ step.directive.businessSourceTrust === undefined
474
+ ? []
475
+ : [remapBusinessSourceTrust(step, step.directive.businessSourceTrust)],
476
+ );
477
+ if (sourceTrusts.length > 1) {
478
+ throw new Error(
479
+ `intent('${this.id}') composes more than one source-trust preflight — split the business action by source`,
480
+ );
481
+ }
424
482
  const steps = [...this.steps];
425
483
  const plan = (facts: I, ctx: Ports): PlannedOp[] => {
426
484
  const returned: PlannedOp[] = [];
@@ -455,8 +513,10 @@ class IntentBuilder<I> {
455
513
  // engine cannot rebuild its aggregate registry entry and silently drops
456
514
  // compound intents that also birth a child.
457
515
  ...(primary.aggregate === undefined ? {} : { aggregate: primary.aggregate }),
458
- ...(primary.outputCardinality !== undefined
459
- ? { outputCardinality: primary.outputCardinality }
516
+ ...(primaryOutput.many === true
517
+ ? { outputCardinality: "many" as const }
518
+ : primaryOutput.optional === true
519
+ ? { outputCardinality: "optional" as const }
460
520
  : {}),
461
521
  ...(secondaryOutputs.length > 0 ? { secondaryOutputs } : {}),
462
522
  payloadSchema: (birthSteps[0]?.directive.payloadSchema ?? this.contractDeclaration.accepts) as unknown as z.ZodType<I>,
@@ -475,6 +535,9 @@ class IntentBuilder<I> {
475
535
  ].sort(),
476
536
  ...(preconditions.length > 0 ? { preconditions } : {}),
477
537
  ...(relationGate !== undefined ? { requiresRelationGate: relationGate } : {}),
538
+ ...(sourceTrusts[0] === undefined
539
+ ? {}
540
+ : { businessSourceTrust: sourceTrusts[0] }),
478
541
  ...(businessBirth === undefined
479
542
  ? {}
480
543
  : {