@githolon/dsl 0.105.13 → 0.105.15

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,16 @@
1
+ ## 0.64.31
2
+
3
+ - Restage the validated intent-offer byte gate and deterministic signer-posture reader into the immutable Dart runner.
4
+
5
+ ## 0.64.30
6
+
7
+ - Recover an authenticated generated application's replacement device through the established repeated-birth compatibility lane when guardian policy refuses keyless enrolment.
8
+ - Resolve signer posture from the relation tuple's deterministic aggregate address so composed application law cannot make framework query aliases ambiguous.
9
+
10
+ ## 0.64.29
11
+
12
+ - Restaged with the current kernel candidate: regenerated vendored assets (kernel release identity is baked into them). Published pub.dev archives are immutable, so regenerated bytes ride their own version.
13
+
1
14
  ## 0.64.28
2
15
 
3
16
  - Restaged with the current kernel candidate: regenerated vendored assets (kernel release identity is baked into them). Published pub.dev archives are immutable, so regenerated bytes ride their own version.
@@ -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: "64219cdd5441cd92cb08d5200a6e65e7814364cc6d1b7cd1b014322ea4372092", version: "kernel-64219cdd", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience", "temporalEnum"], protocol: 1 }, testMint: { hash: "9ca691fd3524897b2edc236167b1b490701c85b41ad066cc41041829d42357f7", version: "kernel-9ca691fd", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience", "temporalEnum"], protocol: 1 } };
4
+ var define_NOMOS_KERNEL_RELEASE_default = { production: { hash: "d37253bcefd90a180a6a1af96422a9f0724dfca9efd9ae7cff070afa2c410f09", version: "kernel-d37253bc", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience", "temporalEnum"], protocol: 1 }, testMint: { hash: "b6bddd8d61390edbe2ee4e5f3c7f21108bdb7800af746d20f568936f63e2d517", version: "kernel-b6bddd8d", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience", "temporalEnum"], protocol: 1 } };
5
5
 
6
6
  // runner/node-entry.ts
7
7
  import { createInterface } from "node:readline";
@@ -534,7 +534,7 @@ function createWebviewRunner({ post: post2, openRealm: openRealm2 }) {
534
534
  // FRAMEWORK-PRIVATE: generated clients say model.adopt(); the runner/client owns proof + receipt assembly.
535
535
  async adoptGeneratedModel(a) {
536
536
  const rec = pickSession(a);
537
- const r = await (await liveHolon(rec)).__nomosAdoptModel(a.domain, a.candidateHash, { because: a.because, dispositions: a.dispositions });
537
+ const r = await (await liveHolon(rec)).__nomosAdoptModel(a.domain, a.candidateHash, { because: a.because });
538
538
  if (r && r.ok && rec.autoStop && rec.autoStop.trigger) rec.autoStop.trigger("write");
539
539
  return { verdict: r };
540
540
  },
@@ -7667,7 +7667,7 @@ function prepareManagedPromotion(report, candidateHash, domain, opts = {}) {
7667
7667
  domainHash: candidateHash,
7668
7668
  ...opts.replaces ? { replaces: opts.replaces } : {},
7669
7669
  retireReplaced: opts.retireReplaced ?? false,
7670
- ...opts.dispositions ? { dispositions: opts.dispositions } : {},
7670
+ ...report.dispositions ? { dispositions: report.dispositions } : {},
7671
7671
  preflight
7672
7672
  }
7673
7673
  };
@@ -7683,7 +7683,6 @@ function prepareManagedRestoration(report, currentHash, priorHash, domain, opts
7683
7683
  }
7684
7684
  const acceptanceReason = opts.acceptanceReason?.trim();
7685
7685
  const prepared = prepareManagedPromotion(report, priorHash, domain, {
7686
- dispositions: report.dispositions,
7687
7686
  ...acceptanceReason ? { acceptanceReason } : {}
7688
7687
  });
7689
7688
  if (!prepared.ok) {
@@ -8153,8 +8152,8 @@ function createGovernanceOffers(ctx) {
8153
8152
  },
8154
8153
  /**
8155
8154
  * PARENT-AUTHORITY POSTURE (read-only diagnostic): is `identity:<principal>#signer@key:<keyHash>`
8156
- * a LIVE tuple on `parent`'s chain? Reads the parent's declared `relationTuplesByObject` query over
8157
- * the open gateway — one O(1) relation read, no authoring. Returns
8155
+ * a LIVE tuple on `parent`'s chain? Reads the tuple's deterministic aggregate address over the
8156
+ * generic record lane — one O(1) read, no authoring and no ambiguous query alias in composed law. Returns
8158
8157
  * `{ parent, principal, keyHash, object, relation, enrolled, revoked, checkedAt }`.
8159
8158
  * `revoked: true` means the subject's leaf was flipped `status:revoked` (remove-wins — a lawful
8160
8159
  * re-enroll of the SAME key is refused; mint + enroll a new device key instead).
@@ -8168,12 +8167,13 @@ function createGovernanceOffers(ctx) {
8168
8167
  keyHash = await sha256hexBytes2(bytesUnb642(publicKey));
8169
8168
  }
8170
8169
  const object = signerObjectOf(p);
8170
+ const aggregateId = `reltuple-${object}-signer`;
8171
8171
  let rows;
8172
8172
  if (parent === workspace && !remote) {
8173
- rows = JSON.parse(call("query", { queryBytes: qBytes2({ kind: "query", queryId: "relationTuplesByObject", paramsJson: JSON.stringify({ object }) }) })) || [];
8173
+ rows = JSON.parse(call("query", { queryBytes: qBytes2({ op: "byId", aggregateId }) })) || [];
8174
8174
  } else {
8175
8175
  const headers = authToken ? { Authorization: `Bearer ${authToken}`, "x-nomos-auth": authToken } : authHeaders;
8176
- const r = await _fetch(`${base}/v2/workspaces/${parent}/relationTuplesByObject?object=${encodeURIComponent(object)}`, { headers });
8176
+ const r = await _fetch(`${base}/v2/workspaces/${parent}/aggregates/${encodeURIComponent(aggregateId)}`, { headers });
8177
8177
  const text = await r.text();
8178
8178
  let body;
8179
8179
  try {
@@ -8181,7 +8181,7 @@ function createGovernanceOffers(ctx) {
8181
8181
  } catch {
8182
8182
  body = text;
8183
8183
  }
8184
- if (!r.ok) throw new Error(`parentSignerEnrollment: reading ${parent}'s relationTuplesByObject failed (${r.status}): ${typeof body === "string" ? body.slice(0, 200) : JSON.stringify(body).slice(0, 200)}`);
8184
+ if (!r.ok) throw new Error(`parentSignerEnrollment: reading ${parent}'s signer tuple failed (${r.status}): ${typeof body === "string" ? body.slice(0, 200) : JSON.stringify(body).slice(0, 200)}`);
8185
8185
  rows = Array.isArray(body) ? body : body && Array.isArray(body.rows) ? body.rows : [];
8186
8186
  }
8187
8187
  let enrolled = false, revoked = false, verifiedVia;
@@ -8227,7 +8227,14 @@ function createGovernanceOffers(ctx) {
8227
8227
  rows = JSON.parse(call("query", { queryBytes: qBytes2({ kind: "query", queryId: "relationTuplesByObject", paramsJson: JSON.stringify({ object }) }) })) || [];
8228
8228
  } else {
8229
8229
  const headers = authToken ? { Authorization: `Bearer ${authToken}`, "x-nomos-auth": authToken } : authHeaders;
8230
- const r = await _fetch(`${base}/v2/workspaces/${ws}/relationTuplesByObject?object=${encodeURIComponent(object)}`, { headers });
8230
+ const route = await resolveFrameworkRoute({
8231
+ parent: ws,
8232
+ operationId: "relationTuplesByObject",
8233
+ method: "get",
8234
+ token: authToken,
8235
+ principal: subj
8236
+ });
8237
+ const r = await _fetch(`${base}/v2/workspaces/${ws}${route.path}?object=${encodeURIComponent(object)}`, { headers });
8231
8238
  const text = await r.text();
8232
8239
  let body;
8233
8240
  try {
@@ -10234,7 +10241,7 @@ ${String(commit).toLowerCase()}`;
10234
10241
  domain,
10235
10242
  candidateHash,
10236
10243
  atHash,
10237
- ...opts.dispositions ? { dispositions: opts.dispositions } : {}
10244
+ ackBy: connectionPrincipal
10238
10245
  })
10239
10246
  }));
10240
10247
  });
@@ -10247,8 +10254,7 @@ ${String(commit).toLowerCase()}`;
10247
10254
  }
10248
10255
  const prepared = prepareManagedPromotion(report, candidateHash, domain, {
10249
10256
  ...currentHash && currentHash !== candidateHash ? { replaces: currentHash } : {},
10250
- ...opts.because !== void 0 ? { acceptanceReason: opts.because } : {},
10251
- ...opts.dispositions ? { dispositions: opts.dispositions } : {}
10257
+ ...opts.because !== void 0 ? { acceptanceReason: opts.because } : {}
10252
10258
  });
10253
10259
  if (!prepared.ok) return prepared;
10254
10260
  try {
@@ -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: "64219cdd5441cd92cb08d5200a6e65e7814364cc6d1b7cd1b014322ea4372092", version: "kernel-64219cdd", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience", "temporalEnum"], protocol: 1 }, testMint: { hash: "9ca691fd3524897b2edc236167b1b490701c85b41ad066cc41041829d42357f7", version: "kernel-9ca691fd", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience", "temporalEnum"], protocol: 1 } };
9
+ var define_NOMOS_KERNEL_RELEASE_default = { production: { hash: "d37253bcefd90a180a6a1af96422a9f0724dfca9efd9ae7cff070afa2c410f09", version: "kernel-d37253bc", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience", "temporalEnum"], protocol: 1 }, testMint: { hash: "b6bddd8d61390edbe2ee4e5f3c7f21108bdb7800af746d20f568936f63e2d517", version: "kernel-b6bddd8d", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience", "temporalEnum"], protocol: 1 } };
10
10
 
11
11
  // runner/offline-install.ts
12
12
  import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync } from "node:fs";
@@ -102,6 +102,8 @@ async function refreshRuntimeDir(cloud, dir, { fetchImpl = globalThis.fetch, log
102
102
  // src/_adapter/engine.ts
103
103
  var engine_exports = {};
104
104
  __export(engine_exports, {
105
+ MAX_INLINE_INTENT_OFFER_BYTES: () => MAX_INLINE_INTENT_OFFER_BYTES,
106
+ MAX_STAGED_INTENT_OFFER_BYTES: () => MAX_STAGED_INTENT_OFFER_BYTES,
105
107
  NOMOS_SHARD_ROWS_READ: () => NOMOS_SHARD_ROWS_READ,
106
108
  admitAll: () => admitAll,
107
109
  admitIntentOffers: () => admitIntentOffers,
@@ -164,6 +166,7 @@ __export(engine_exports, {
164
166
  ingestPackAsCustody: () => ingestPackAsCustody,
165
167
  installedLaw: () => installedLaw,
166
168
  intentOfferResidencies: () => intentOfferResidencies,
169
+ intentOfferSizeRefusal: () => intentOfferSizeRefusal,
167
170
  isDirty: () => isDirty,
168
171
  isWarranted: () => isWarranted,
169
172
  kernelStamp: () => kernelStamp,
@@ -2009,7 +2012,7 @@ function prepareManagedPromotion(report, candidateHash, domain, opts = {}) {
2009
2012
  domainHash: candidateHash,
2010
2013
  ...opts.replaces ? { replaces: opts.replaces } : {},
2011
2014
  retireReplaced: opts.retireReplaced ?? false,
2012
- ...opts.dispositions ? { dispositions: opts.dispositions } : {},
2015
+ ...report.dispositions ? { dispositions: report.dispositions } : {},
2013
2016
  preflight
2014
2017
  }
2015
2018
  };
@@ -2025,7 +2028,6 @@ function prepareManagedRestoration(report, currentHash, priorHash, domain, opts
2025
2028
  }
2026
2029
  const acceptanceReason = opts.acceptanceReason?.trim();
2027
2030
  const prepared = prepareManagedPromotion(report, priorHash, domain, {
2028
- dispositions: report.dispositions,
2029
2031
  ...acceptanceReason ? { acceptanceReason } : {}
2030
2032
  });
2031
2033
  if (!prepared.ok) {
@@ -6782,6 +6784,12 @@ async function replicateIntents(eng2, ws, ledger, intents, { push = true } = {})
6782
6784
  log("replicate-globals", { ws, replicated: replicated.length, skipped: skipped.length, refused: refused.length });
6783
6785
  return { replicated, skipped, refused };
6784
6786
  }
6787
+ var MAX_INLINE_INTENT_OFFER_BYTES = 32 * 1024 * 1024;
6788
+ var MAX_STAGED_INTENT_OFFER_BYTES = 64 * 1024 * 1024;
6789
+ function intentOfferSizeRefusal(staged, byteLength) {
6790
+ const maxOfferBytes = staged ? MAX_STAGED_INTENT_OFFER_BYTES : MAX_INLINE_INTENT_OFFER_BYTES;
6791
+ return byteLength <= 0 || byteLength > maxOfferBytes ? `intent offer must carry changeB64 <= ${maxOfferBytes / (1024 * 1024)} MiB` : null;
6792
+ }
6785
6793
  async function admitIntentOffers(eng2, ws, ledger, offers, { receiptFence = null, shardRouting = null, clientBase = null } = {}) {
6786
6794
  const main = await mainIntentIds(eng2, ws);
6787
6795
  const sessions = /* @__PURE__ */ new Map();
@@ -6853,9 +6861,16 @@ async function admitIntentOffers(eng2, ws, ledger, offers, { receiptFence = null
6853
6861
  let blob = offer?.blob instanceof Uint8Array ? offer.blob : null;
6854
6862
  try {
6855
6863
  if (!blob && typeof offer?.changeB64 === "string") blob = Uint8Array.from(atob(offer.changeB64), (c) => c.charCodeAt(0));
6856
- const maxOfferBytes = offer?.staged ? 64 * 1024 * 1024 : 32 * 1024 * 1024;
6857
- if (!blob || blob.byteLength === 0 || blob.byteLength > maxOfferBytes) {
6858
- rec.rejected.push({ oid: String(offer?.oid || "").slice(0, 10), error: `intent offer must carry changeB64 <= ${maxOfferBytes / (1024 * 1024)} MiB` });
6864
+ if (!blob) {
6865
+ rec.rejected.push({
6866
+ oid: String(offer?.oid || "").slice(0, 10),
6867
+ error: intentOfferSizeRefusal(!!offer?.staged, 0)
6868
+ });
6869
+ continue;
6870
+ }
6871
+ const sizeRefusal = intentOfferSizeRefusal(!!offer?.staged, blob.byteLength);
6872
+ if (sizeRefusal !== null) {
6873
+ rec.rejected.push({ oid: String(offer?.oid || "").slice(0, 10), error: sizeRefusal });
6859
6874
  continue;
6860
6875
  }
6861
6876
  const inspected = kgit.inspectChange(eng2, blob);
@@ -7115,7 +7130,7 @@ async function mountWorkspace(eng2, ws, ledger) {
7115
7130
  throw new Error(`kernel refused restored main ${remoteMain}: ${JSON.stringify(mounted)}`);
7116
7131
  }
7117
7132
  restored = true;
7118
- if (!seeded?.seeded) {
7133
+ if (!seeded?.seeded && ledger.readOnly !== true) {
7119
7134
  void pushCheckpoint(eng2, ws, ledger).catch(() => {
7120
7135
  });
7121
7136
  }
@@ -8580,12 +8595,12 @@ async function verifyChain(eng2, ws, ledger) {
8580
8595
  function verifyChainLocal(eng2, ws) {
8581
8596
  return namedQueryProto(eng2, ws, QueryOperation.VERIFY_CHAIN);
8582
8597
  }
8583
- function historyPreflight(eng2, ws, domain, candidateHash, atHash, dispositions) {
8598
+ function historyPreflight(eng2, ws, domain, candidateHash, atHash, actor = "") {
8584
8599
  return namedQueryProto(eng2, ws, QueryOperation.HISTORY_PREFLIGHT, {
8585
8600
  domain,
8586
8601
  candidateHash,
8587
8602
  atHash,
8588
- ...dispositions ? { dispositions } : {}
8603
+ ...actor.trim() ? { ackBy: actor.trim() } : {}
8589
8604
  });
8590
8605
  }
8591
8606
  function historyRestorePreflight(eng2, ws, domain, currentHash, priorHash, atHash, actor) {
@@ -8612,7 +8627,7 @@ function promotePreflighted(eng2, ws, domain, candidateHash, opts = {}) {
8612
8627
  }
8613
8628
  let report;
8614
8629
  try {
8615
- report = historyPreflight(eng2, ws, domain, candidateHash, atHash, opts.dispositions);
8630
+ report = historyPreflight(eng2, ws, domain, candidateHash, atHash, actingPrincipal);
8616
8631
  } catch (error) {
8617
8632
  return { ok: false, stage: "preflight", error: String(error?.message || error) };
8618
8633
  }
@@ -8621,7 +8636,6 @@ function promotePreflighted(eng2, ws, domain, candidateHash, opts = {}) {
8621
8636
  const {
8622
8637
  replaces: _replaces,
8623
8638
  retireReplaced: _retireReplaced,
8624
- dispositions: _dispositions,
8625
8639
  acceptanceReason: _acceptance,
8626
8640
  ...authorOpts
8627
8641
  } = opts;
@@ -191,7 +191,7 @@ class DomainClientModelAdoptionRequired implements Exception {
191
191
  final String summary;
192
192
  final DomainModelReview review;
193
193
  final Future<void> Function()? _stage;
194
- final Future<void> Function(String reason, {Map<String, Object?>? dispositions})? _accept;
194
+ final Future<void> Function(String reason)? _accept;
195
195
 
196
196
  const DomainClientModelAdoptionRequired({
197
197
  required this.expectedDomainKey,
@@ -200,7 +200,7 @@ class DomainClientModelAdoptionRequired implements Exception {
200
200
  required this.summary,
201
201
  required this.review,
202
202
  Future<void> Function()? stage,
203
- Future<void> Function(String reason, {Map<String, Object?>? dispositions})? accept,
203
+ Future<void> Function(String reason)? accept,
204
204
  }) : _stage = stage,
205
205
  _accept = accept;
206
206
 
@@ -216,10 +216,10 @@ class DomainClientModelAdoptionRequired implements Exception {
216
216
 
217
217
  bool get canAccept => _accept != null;
218
218
 
219
- /// [dispositions] carries only sids the kernel's OWN exact-history proof
220
- /// named as truly removed (`{"retired": [sid, ...]}`) — never authored from
221
- /// memory; a wrong disposition is a silent data-model error, not a waiver.
222
- Future<void> accept(String reason, {Map<String, Object?>? dispositions}) {
219
+ /// Accept the candidate after reviewing the compiler-derived consequences.
220
+ /// Stable identities, retirements and value evolutions come from candidate
221
+ /// law; application code supplies accountability, never mechanical waivers.
222
+ Future<void> accept(String reason) {
223
223
  final value = reason.trim();
224
224
  if (value.isEmpty) {
225
225
  throw ArgumentError.value(
@@ -232,7 +232,7 @@ class DomainClientModelAdoptionRequired implements Exception {
232
232
  if (accept == null) {
233
233
  throw StateError('This generated model change cannot be accepted.');
234
234
  }
235
- return accept(value, dispositions: dispositions);
235
+ return accept(value);
236
236
  }
237
237
 
238
238
  @override
@@ -2761,13 +2761,11 @@ class NomosBridge {
2761
2761
  required String domain,
2762
2762
  required String candidateHash,
2763
2763
  String? because,
2764
- Map<String, Object?>? dispositions,
2765
2764
  }) async {
2766
2765
  final r = _asMap(await _call('adoptGeneratedModel', {
2767
2766
  'domain': domain,
2768
2767
  'candidateHash': candidateHash,
2769
2768
  if (because != null) 'because': because,
2770
- if (dispositions != null) 'dispositions': dispositions,
2771
2769
  }));
2772
2770
  return ((r['verdict'] as Map?) ?? const <String, Object?>{})
2773
2771
  .cast<String, Object?>();
@@ -4057,7 +4055,8 @@ class NomosBridge {
4057
4055
  if (!_syncEvents.isClosed) await _syncEvents.close();
4058
4056
  if (!_signalEvents.isClosed) await _signalEvents.close();
4059
4057
  if (!_custodyEvents.isClosed) await _custodyEvents.close();
4060
- if (!_localWorkRejectedEvents.isClosed) await _localWorkRejectedEvents.close();
4058
+ if (!_localWorkRejectedEvents.isClosed)
4059
+ await _localWorkRejectedEvents.close();
4061
4060
  if (!_flameEvents.isClosed) await _flameEvents.close();
4062
4061
  if (!_spanEvents.isClosed) await _spanEvents.close();
4063
4062
  if (!_transferEvents.isClosed) await _transferEvents.close();
@@ -4382,8 +4381,8 @@ class _BridgeForeignWorkspaceReader implements NomosForeignWorkspaceReader {
4382
4381
  String? nomosInternalResidencyRequiredWorkspace(Object error) {
4383
4382
  final text = error.toString();
4384
4383
  if (!text.contains('foreign-read-not-ready')) return null;
4385
- final match = RegExp(r"source workspace '([^']+)' is not resident")
4386
- .firstMatch(text);
4384
+ final match =
4385
+ RegExp(r"source workspace '([^']+)' is not resident").firstMatch(text);
4387
4386
  final workspace = match?.group(1)?.trim();
4388
4387
  return (workspace == null || workspace.isEmpty) ? null : workspace;
4389
4388
  }
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.28
10
+ version: 0.64.31
11
11
 
12
12
  environment:
13
13
  sdk: ^3.5.0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@githolon/dsl",
3
- "version": "0.105.13",
3
+ "version": "0.105.15",
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.",
@@ -6698,7 +6698,7 @@ function prepareManagedPromotion(report, candidateHash, domain, opts = {}) {
6698
6698
  domainHash: candidateHash,
6699
6699
  ...opts.replaces ? { replaces: opts.replaces } : {},
6700
6700
  retireReplaced: opts.retireReplaced ?? false,
6701
- ...opts.dispositions ? { dispositions: opts.dispositions } : {},
6701
+ ...report.dispositions ? { dispositions: report.dispositions } : {},
6702
6702
  preflight
6703
6703
  }
6704
6704
  };
@@ -6714,7 +6714,6 @@ function prepareManagedRestoration(report, currentHash, priorHash, domain, opts
6714
6714
  }
6715
6715
  const acceptanceReason = opts.acceptanceReason?.trim();
6716
6716
  const prepared = prepareManagedPromotion(report, priorHash, domain, {
6717
- dispositions: report.dispositions,
6718
6717
  ...acceptanceReason ? { acceptanceReason } : {}
6719
6718
  });
6720
6719
  if (!prepared.ok) {
@@ -7184,8 +7183,8 @@ function createGovernanceOffers(ctx) {
7184
7183
  },
7185
7184
  /**
7186
7185
  * PARENT-AUTHORITY POSTURE (read-only diagnostic): is `identity:<principal>#signer@key:<keyHash>`
7187
- * a LIVE tuple on `parent`'s chain? Reads the parent's declared `relationTuplesByObject` query over
7188
- * the open gateway — one O(1) relation read, no authoring. Returns
7186
+ * a LIVE tuple on `parent`'s chain? Reads the tuple's deterministic aggregate address over the
7187
+ * generic record lane — one O(1) read, no authoring and no ambiguous query alias in composed law. Returns
7189
7188
  * `{ parent, principal, keyHash, object, relation, enrolled, revoked, checkedAt }`.
7190
7189
  * `revoked: true` means the subject's leaf was flipped `status:revoked` (remove-wins — a lawful
7191
7190
  * re-enroll of the SAME key is refused; mint + enroll a new device key instead).
@@ -7199,12 +7198,13 @@ function createGovernanceOffers(ctx) {
7199
7198
  keyHash = await sha256hexBytes2(bytesUnb642(publicKey));
7200
7199
  }
7201
7200
  const object = signerObjectOf(p);
7201
+ const aggregateId = `reltuple-${object}-signer`;
7202
7202
  let rows;
7203
7203
  if (parent === workspace && !remote) {
7204
- rows = JSON.parse(call("query", { queryBytes: qBytes2({ kind: "query", queryId: "relationTuplesByObject", paramsJson: JSON.stringify({ object }) }) })) || [];
7204
+ rows = JSON.parse(call("query", { queryBytes: qBytes2({ op: "byId", aggregateId }) })) || [];
7205
7205
  } else {
7206
7206
  const headers = authToken ? { Authorization: `Bearer ${authToken}`, "x-nomos-auth": authToken } : authHeaders;
7207
- const r = await _fetch(`${base}/v2/workspaces/${parent}/relationTuplesByObject?object=${encodeURIComponent(object)}`, { headers });
7207
+ const r = await _fetch(`${base}/v2/workspaces/${parent}/aggregates/${encodeURIComponent(aggregateId)}`, { headers });
7208
7208
  const text2 = await r.text();
7209
7209
  let body;
7210
7210
  try {
@@ -7212,7 +7212,7 @@ function createGovernanceOffers(ctx) {
7212
7212
  } catch {
7213
7213
  body = text2;
7214
7214
  }
7215
- if (!r.ok) throw new Error(`parentSignerEnrollment: reading ${parent}'s relationTuplesByObject failed (${r.status}): ${typeof body === "string" ? body.slice(0, 200) : JSON.stringify(body).slice(0, 200)}`);
7215
+ if (!r.ok) throw new Error(`parentSignerEnrollment: reading ${parent}'s signer tuple failed (${r.status}): ${typeof body === "string" ? body.slice(0, 200) : JSON.stringify(body).slice(0, 200)}`);
7216
7216
  rows = Array.isArray(body) ? body : body && Array.isArray(body.rows) ? body.rows : [];
7217
7217
  }
7218
7218
  let enrolled = false, revoked = false, verifiedVia;
@@ -7258,7 +7258,14 @@ function createGovernanceOffers(ctx) {
7258
7258
  rows = JSON.parse(call("query", { queryBytes: qBytes2({ kind: "query", queryId: "relationTuplesByObject", paramsJson: JSON.stringify({ object }) }) })) || [];
7259
7259
  } else {
7260
7260
  const headers = authToken ? { Authorization: `Bearer ${authToken}`, "x-nomos-auth": authToken } : authHeaders;
7261
- const r = await _fetch(`${base}/v2/workspaces/${ws}/relationTuplesByObject?object=${encodeURIComponent(object)}`, { headers });
7261
+ const route = await resolveFrameworkRoute({
7262
+ parent: ws,
7263
+ operationId: "relationTuplesByObject",
7264
+ method: "get",
7265
+ token: authToken,
7266
+ principal: subj
7267
+ });
7268
+ const r = await _fetch(`${base}/v2/workspaces/${ws}${route.path}?object=${encodeURIComponent(object)}`, { headers });
7262
7269
  const text2 = await r.text();
7263
7270
  let body;
7264
7271
  try {
@@ -9265,7 +9272,7 @@ ${String(commit).toLowerCase()}`;
9265
9272
  domain,
9266
9273
  candidateHash,
9267
9274
  atHash,
9268
- ...opts.dispositions ? { dispositions: opts.dispositions } : {}
9275
+ ackBy: connectionPrincipal
9269
9276
  })
9270
9277
  }));
9271
9278
  });
@@ -9278,8 +9285,7 @@ ${String(commit).toLowerCase()}`;
9278
9285
  }
9279
9286
  const prepared = prepareManagedPromotion(report, candidateHash, domain, {
9280
9287
  ...currentHash && currentHash !== candidateHash ? { replaces: currentHash } : {},
9281
- ...opts.because !== void 0 ? { acceptanceReason: opts.because } : {},
9282
- ...opts.dispositions ? { dispositions: opts.dispositions } : {}
9288
+ ...opts.because !== void 0 ? { acceptanceReason: opts.because } : {}
9283
9289
  });
9284
9290
  if (!prepared.ok) return prepared;
9285
9291
  try {
@@ -13492,16 +13498,55 @@ function applicationError(message, code, cause) {
13492
13498
  if (cause !== void 0) error.cause = cause;
13493
13499
  return error;
13494
13500
  }
13495
- async function ensureGeneratedModelCurrent(application) {
13501
+ function applicationOpenFailure(application, requestedModel, cause) {
13502
+ const typed = cause;
13503
+ if (typed?.name === "NomosApplicationError" && typeof typed.code === "string") {
13504
+ return cause;
13505
+ }
13506
+ const raw = String(cause?.message ?? cause ?? "unknown failure");
13507
+ if (/birth-current-law-unavailable|birth install target|\[nomos\.birth\.model_not_active\]/i.test(raw)) {
13508
+ const model = /(?:birth install target|under model)\s+([0-9a-f]{64})/i.exec(raw)?.[1] ?? requestedModel;
13509
+ const shortModel = /^[0-9a-f]{64}$/i.test(model) ? `${model.slice(0, 16)}\u2026` : "the requested model";
13510
+ return applicationError(
13511
+ `Nomos application '${application}' cannot create this private workspace because its parent does not currently serve model ${shortModel}. No workspace was created. A current generated client should inherit the parent's active model at birth and then govern adoption of its packaged model; regenerate the application client before retrying, or have an authorised application release adopt that model on the parent.`,
13512
+ "nomos.application.bootstrap_model_not_active",
13513
+ cause
13514
+ );
13515
+ }
13516
+ return applicationError(
13517
+ `Nomos could not finish preparing the signed-in '${application}' application: ${raw}`,
13518
+ "nomos.application.open_failed",
13519
+ cause
13520
+ );
13521
+ }
13522
+ async function ensureGeneratedModelCurrent(application, approveModel) {
13496
13523
  if (application.model?.adopt === void 0) {
13497
13524
  throw applicationError(
13498
13525
  "This generated application has no model lifecycle surface and cannot prove its plans are current.",
13499
13526
  "nomos.application.model_lifecycle_missing"
13500
13527
  );
13501
13528
  }
13502
- const adoption = await application.model.adopt();
13529
+ let adoption = await application.model.adopt();
13530
+ if (adoption.status === "needs-staging" && adoption.stage !== void 0) {
13531
+ adoption = await adoption.stage();
13532
+ }
13503
13533
  if (adoption.status === "adopted") return;
13504
13534
  if (adoption.status === "needs-decision") {
13535
+ if (approveModel !== void 0 && adoption.accept !== void 0) {
13536
+ const approval = await approveModel({
13537
+ summary: adoption.summary,
13538
+ review: adoption.review
13539
+ });
13540
+ const because = approval.because.trim();
13541
+ if (!because) {
13542
+ throw applicationError(
13543
+ "Model approval must state the business reason for the change.",
13544
+ "nomos.application.model_decision_reason_missing"
13545
+ );
13546
+ }
13547
+ adoption = await adoption.accept(because);
13548
+ if (adoption.status === "adopted") return;
13549
+ }
13505
13550
  throw applicationError(
13506
13551
  "This application model changes prior business outcomes and needs an attributed migration decision before the app can write.",
13507
13552
  "nomos.application.model_decision_required",
@@ -13624,7 +13669,7 @@ async function nomosInternalOpenGeneratedApplication(options, bind, internals =
13624
13669
  ...environment?.NOMOS_TEST_K_ROOT_PUBLIC ? { __testKRootPublic: environment.NOMOS_TEST_K_ROOT_PUBLIC } : {}
13625
13670
  });
13626
13671
  const applicationObject = measureOpenSync("bind generated business API", () => bind(holon2, user));
13627
- await ensureGeneratedModelCurrent(applicationObject);
13672
+ await ensureGeneratedModelCurrent(applicationObject, options.approveModel);
13628
13673
  await measureOpen("prepare generated entry commands", () => prepareGeneratedEntryCommands(holon2, options.readyCommands, options.onPerformance));
13629
13674
  const stop = holon2.autoSync({
13630
13675
  onResult: (result) => {
@@ -13861,17 +13906,11 @@ async function nomosInternalOpenGeneratedApplication(options, bind, internals =
13861
13906
  }
13862
13907
  authToken = deviceToken;
13863
13908
  if (!completed) {
13864
- let homeAvailable = false;
13865
- try {
13866
- homeAvailable = Boolean(await measureOpen("check private application custody", () => authorityHolon.head()));
13867
- } catch {
13868
- }
13869
- if (!homeAvailable) {
13909
+ const birthOrRepeat = async () => {
13870
13910
  const birth = await measureOpen("establish private application custody", () => authorityHolon.nomosInternalBirthReceivingGroup({
13871
13911
  parent: application,
13872
13912
  principal,
13873
13913
  subject,
13874
- lawHash: options.lawHash,
13875
13914
  device: { secret, public: publicKey },
13876
13915
  authToken,
13877
13916
  idToken: authToken,
@@ -13881,16 +13920,36 @@ async function nomosInternalOpenGeneratedApplication(options, bind, internals =
13881
13920
  }));
13882
13921
  const verdict = birth.verify;
13883
13922
  if (verdict !== void 0 && verdict.valid !== true) throw new Error(`the born application failed replay verification: ${String(verdict.error ?? "unknown")}`);
13923
+ };
13924
+ let homeAvailable = false;
13925
+ try {
13926
+ homeAvailable = Boolean(await measureOpen("check private application custody", () => authorityHolon.head()));
13927
+ } catch {
13928
+ }
13929
+ if (!homeAvailable) {
13930
+ await birthOrRepeat();
13884
13931
  } else if (!hadDurableSecret) {
13885
- await measureOpen("enrol application device with its parent", () => authorityHolon.ensureParentSignerEnrollment({
13886
- parent: application,
13887
- principal,
13888
- publicKey,
13889
- authorSecret: secret,
13890
- authToken,
13891
- idToken: authToken,
13892
- verifiedVia: issuer
13893
- }));
13932
+ try {
13933
+ await measureOpen("enrol application device in its private custody", () => authorityHolon.ensureParentSignerEnrollment({
13934
+ // The write gate that this device will use is the receiving-group workspace itself.
13935
+ // The application root authorises/births that home; it is not a substitute signer index.
13936
+ parent: receivingGroup,
13937
+ // The author gate speaks canonical Nomos principals. A provider subject is deliberately
13938
+ // opaque and may contain its own namespace separators; never enrol that raw value as the actor.
13939
+ principal: subject,
13940
+ publicKey,
13941
+ authorSecret: secret,
13942
+ authToken,
13943
+ idToken: authToken,
13944
+ verifiedVia: issuer
13945
+ }));
13946
+ } catch (error) {
13947
+ if (String(error).includes("receiving-group-additional-device-requires-current-device-or-guardian")) {
13948
+ await birthOrRepeat();
13949
+ } else {
13950
+ throw error;
13951
+ }
13952
+ }
13894
13953
  }
13895
13954
  await measureOpen("save application bootstrap progress", () => store.saveText(journalState, "home-available"));
13896
13955
  authorityHolon = await measureOpen("rebind durable application authority", () => mountAuthority(secret, authToken));
@@ -13904,8 +13963,8 @@ async function nomosInternalOpenGeneratedApplication(options, bind, internals =
13904
13963
  if (verified.valid !== true) throw new Error(`the private authority context failed replay verification: ${String(verified.error ?? "unknown")}`);
13905
13964
  await measureOpen("save application bootstrap progress", () => store.saveText(journalState, "verified"));
13906
13965
  try {
13907
- await measureOpen("confirm parent signer enrolment", () => authorityHolon.ensureParentSignerEnrollment({
13908
- parent: application,
13966
+ await measureOpen("confirm private-custody signer enrolment", () => authorityHolon.ensureParentSignerEnrollment({
13967
+ parent: receivingGroup,
13909
13968
  principal: subject,
13910
13969
  authorSecret: secret,
13911
13970
  authToken,
@@ -13930,7 +13989,7 @@ async function nomosInternalOpenGeneratedApplication(options, bind, internals =
13930
13989
  } catch {
13931
13990
  }
13932
13991
  const applicationObject = measureOpenSync("bind generated business API", () => bind(holon, user));
13933
- await measureOpen("confirm generated model is current", () => ensureGeneratedModelCurrent(applicationObject));
13992
+ await measureOpen("confirm generated model is current", () => ensureGeneratedModelCurrent(applicationObject, options.approveModel));
13934
13993
  await measureOpen("prepare generated entry commands", () => prepareGeneratedEntryCommands(holon, options.readyCommands, options.onPerformance));
13935
13994
  phase = "current";
13936
13995
  autoSync = holon.autoSync({
@@ -14009,7 +14068,7 @@ async function nomosInternalOpenGeneratedApplication(options, bind, internals =
14009
14068
  } catch (cause) {
14010
14069
  await closeRealm().catch(() => {
14011
14070
  });
14012
- throw applicationError("Nomos could not finish preparing the signed-in business application.", "nomos.application.open_failed", cause);
14071
+ throw applicationOpenFailure(application, options.lawHash, cause);
14013
14072
  }
14014
14073
  }
14015
14074
  export {