@githolon/dsl 0.105.13 → 0.105.14
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 +4 -0
- package/dart/lib/src/runner/node-entry.mjs +21 -9
- package/dart/lib/src/runner/offline-install.mjs +6 -8
- package/dart/lib/src/session_bound.dart +7 -7
- package/dart/lib/src/webview_bridge.dart +4 -5
- package/dart/pubspec.yaml +1 -1
- package/package.json +1 -1
- package/runtime/generated-application-host.js +50 -17
- package/src/build_package.ts +37 -3
- package/src/check_package_main.ts +12 -10
- package/src/codegen_dart.ts +7 -4
- package/src/codegen_dart_client.ts +5 -16
- package/src/codegen_ts.ts +32 -4
- package/src/compile_package_main.ts +100 -9
- package/src/evolution.ts +313 -0
- package/src/evolution_files.ts +31 -0
- package/src/evolve_preview.ts +64 -55
- package/src/index.ts +10 -0
- package/src/law_graph.ts +58 -1
- package/src/law_graph_usda.ts +26 -0
- package/src/stable_ids_for_module.ts +1 -1
package/dart/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
## 0.64.29
|
|
2
|
+
|
|
3
|
+
- 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.
|
|
4
|
+
|
|
1
5
|
## 0.64.28
|
|
2
6
|
|
|
3
7
|
- 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: "
|
|
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
|
|
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
|
-
...
|
|
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) {
|
|
@@ -8173,7 +8172,14 @@ function createGovernanceOffers(ctx) {
|
|
|
8173
8172
|
rows = JSON.parse(call("query", { queryBytes: qBytes2({ kind: "query", queryId: "relationTuplesByObject", paramsJson: JSON.stringify({ object }) }) })) || [];
|
|
8174
8173
|
} else {
|
|
8175
8174
|
const headers = authToken ? { Authorization: `Bearer ${authToken}`, "x-nomos-auth": authToken } : authHeaders;
|
|
8176
|
-
const
|
|
8175
|
+
const route = await resolveFrameworkRoute({
|
|
8176
|
+
parent,
|
|
8177
|
+
operationId: "relationTuplesByObject",
|
|
8178
|
+
method: "get",
|
|
8179
|
+
token: authToken,
|
|
8180
|
+
principal: p
|
|
8181
|
+
});
|
|
8182
|
+
const r = await _fetch(`${base}/v2/workspaces/${parent}${route.path}?object=${encodeURIComponent(object)}`, { headers });
|
|
8177
8183
|
const text = await r.text();
|
|
8178
8184
|
let body;
|
|
8179
8185
|
try {
|
|
@@ -8227,7 +8233,14 @@ function createGovernanceOffers(ctx) {
|
|
|
8227
8233
|
rows = JSON.parse(call("query", { queryBytes: qBytes2({ kind: "query", queryId: "relationTuplesByObject", paramsJson: JSON.stringify({ object }) }) })) || [];
|
|
8228
8234
|
} else {
|
|
8229
8235
|
const headers = authToken ? { Authorization: `Bearer ${authToken}`, "x-nomos-auth": authToken } : authHeaders;
|
|
8230
|
-
const
|
|
8236
|
+
const route = await resolveFrameworkRoute({
|
|
8237
|
+
parent: ws,
|
|
8238
|
+
operationId: "relationTuplesByObject",
|
|
8239
|
+
method: "get",
|
|
8240
|
+
token: authToken,
|
|
8241
|
+
principal: subj
|
|
8242
|
+
});
|
|
8243
|
+
const r = await _fetch(`${base}/v2/workspaces/${ws}${route.path}?object=${encodeURIComponent(object)}`, { headers });
|
|
8231
8244
|
const text = await r.text();
|
|
8232
8245
|
let body;
|
|
8233
8246
|
try {
|
|
@@ -10234,7 +10247,7 @@ ${String(commit).toLowerCase()}`;
|
|
|
10234
10247
|
domain,
|
|
10235
10248
|
candidateHash,
|
|
10236
10249
|
atHash,
|
|
10237
|
-
|
|
10250
|
+
ackBy: connectionPrincipal
|
|
10238
10251
|
})
|
|
10239
10252
|
}));
|
|
10240
10253
|
});
|
|
@@ -10247,8 +10260,7 @@ ${String(commit).toLowerCase()}`;
|
|
|
10247
10260
|
}
|
|
10248
10261
|
const prepared = prepareManagedPromotion(report, candidateHash, domain, {
|
|
10249
10262
|
...currentHash && currentHash !== candidateHash ? { replaces: currentHash } : {},
|
|
10250
|
-
...opts.because !== void 0 ? { acceptanceReason: opts.because } : {}
|
|
10251
|
-
...opts.dispositions ? { dispositions: opts.dispositions } : {}
|
|
10263
|
+
...opts.because !== void 0 ? { acceptanceReason: opts.because } : {}
|
|
10252
10264
|
});
|
|
10253
10265
|
if (!prepared.ok) return prepared;
|
|
10254
10266
|
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: "
|
|
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";
|
|
@@ -2009,7 +2009,7 @@ function prepareManagedPromotion(report, candidateHash, domain, opts = {}) {
|
|
|
2009
2009
|
domainHash: candidateHash,
|
|
2010
2010
|
...opts.replaces ? { replaces: opts.replaces } : {},
|
|
2011
2011
|
retireReplaced: opts.retireReplaced ?? false,
|
|
2012
|
-
...
|
|
2012
|
+
...report.dispositions ? { dispositions: report.dispositions } : {},
|
|
2013
2013
|
preflight
|
|
2014
2014
|
}
|
|
2015
2015
|
};
|
|
@@ -2025,7 +2025,6 @@ function prepareManagedRestoration(report, currentHash, priorHash, domain, opts
|
|
|
2025
2025
|
}
|
|
2026
2026
|
const acceptanceReason = opts.acceptanceReason?.trim();
|
|
2027
2027
|
const prepared = prepareManagedPromotion(report, priorHash, domain, {
|
|
2028
|
-
dispositions: report.dispositions,
|
|
2029
2028
|
...acceptanceReason ? { acceptanceReason } : {}
|
|
2030
2029
|
});
|
|
2031
2030
|
if (!prepared.ok) {
|
|
@@ -7115,7 +7114,7 @@ async function mountWorkspace(eng2, ws, ledger) {
|
|
|
7115
7114
|
throw new Error(`kernel refused restored main ${remoteMain}: ${JSON.stringify(mounted)}`);
|
|
7116
7115
|
}
|
|
7117
7116
|
restored = true;
|
|
7118
|
-
if (!seeded?.seeded) {
|
|
7117
|
+
if (!seeded?.seeded && ledger.readOnly !== true) {
|
|
7119
7118
|
void pushCheckpoint(eng2, ws, ledger).catch(() => {
|
|
7120
7119
|
});
|
|
7121
7120
|
}
|
|
@@ -8580,12 +8579,12 @@ async function verifyChain(eng2, ws, ledger) {
|
|
|
8580
8579
|
function verifyChainLocal(eng2, ws) {
|
|
8581
8580
|
return namedQueryProto(eng2, ws, QueryOperation.VERIFY_CHAIN);
|
|
8582
8581
|
}
|
|
8583
|
-
function historyPreflight(eng2, ws, domain, candidateHash, atHash,
|
|
8582
|
+
function historyPreflight(eng2, ws, domain, candidateHash, atHash, actor = "") {
|
|
8584
8583
|
return namedQueryProto(eng2, ws, QueryOperation.HISTORY_PREFLIGHT, {
|
|
8585
8584
|
domain,
|
|
8586
8585
|
candidateHash,
|
|
8587
8586
|
atHash,
|
|
8588
|
-
...
|
|
8587
|
+
...actor.trim() ? { ackBy: actor.trim() } : {}
|
|
8589
8588
|
});
|
|
8590
8589
|
}
|
|
8591
8590
|
function historyRestorePreflight(eng2, ws, domain, currentHash, priorHash, atHash, actor) {
|
|
@@ -8612,7 +8611,7 @@ function promotePreflighted(eng2, ws, domain, candidateHash, opts = {}) {
|
|
|
8612
8611
|
}
|
|
8613
8612
|
let report;
|
|
8614
8613
|
try {
|
|
8615
|
-
report = historyPreflight(eng2, ws, domain, candidateHash, atHash,
|
|
8614
|
+
report = historyPreflight(eng2, ws, domain, candidateHash, atHash, actingPrincipal);
|
|
8616
8615
|
} catch (error) {
|
|
8617
8616
|
return { ok: false, stage: "preflight", error: String(error?.message || error) };
|
|
8618
8617
|
}
|
|
@@ -8621,7 +8620,6 @@ function promotePreflighted(eng2, ws, domain, candidateHash, opts = {}) {
|
|
|
8621
8620
|
const {
|
|
8622
8621
|
replaces: _replaces,
|
|
8623
8622
|
retireReplaced: _retireReplaced,
|
|
8624
|
-
dispositions: _dispositions,
|
|
8625
8623
|
acceptanceReason: _acceptance,
|
|
8626
8624
|
...authorOpts
|
|
8627
8625
|
} = 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
|
|
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
|
|
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
|
-
///
|
|
220
|
-
///
|
|
221
|
-
///
|
|
222
|
-
Future<void> accept(String reason
|
|
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
|
|
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)
|
|
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 =
|
|
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.
|
|
10
|
+
version: 0.64.29
|
|
11
11
|
|
|
12
12
|
environment:
|
|
13
13
|
sdk: ^3.5.0
|
package/package.json
CHANGED
|
@@ -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
|
-
...
|
|
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) {
|
|
@@ -7204,7 +7203,14 @@ function createGovernanceOffers(ctx) {
|
|
|
7204
7203
|
rows = JSON.parse(call("query", { queryBytes: qBytes2({ kind: "query", queryId: "relationTuplesByObject", paramsJson: JSON.stringify({ object }) }) })) || [];
|
|
7205
7204
|
} else {
|
|
7206
7205
|
const headers = authToken ? { Authorization: `Bearer ${authToken}`, "x-nomos-auth": authToken } : authHeaders;
|
|
7207
|
-
const
|
|
7206
|
+
const route = await resolveFrameworkRoute({
|
|
7207
|
+
parent,
|
|
7208
|
+
operationId: "relationTuplesByObject",
|
|
7209
|
+
method: "get",
|
|
7210
|
+
token: authToken,
|
|
7211
|
+
principal: p
|
|
7212
|
+
});
|
|
7213
|
+
const r = await _fetch(`${base}/v2/workspaces/${parent}${route.path}?object=${encodeURIComponent(object)}`, { headers });
|
|
7208
7214
|
const text2 = await r.text();
|
|
7209
7215
|
let body;
|
|
7210
7216
|
try {
|
|
@@ -7258,7 +7264,14 @@ function createGovernanceOffers(ctx) {
|
|
|
7258
7264
|
rows = JSON.parse(call("query", { queryBytes: qBytes2({ kind: "query", queryId: "relationTuplesByObject", paramsJson: JSON.stringify({ object }) }) })) || [];
|
|
7259
7265
|
} else {
|
|
7260
7266
|
const headers = authToken ? { Authorization: `Bearer ${authToken}`, "x-nomos-auth": authToken } : authHeaders;
|
|
7261
|
-
const
|
|
7267
|
+
const route = await resolveFrameworkRoute({
|
|
7268
|
+
parent: ws,
|
|
7269
|
+
operationId: "relationTuplesByObject",
|
|
7270
|
+
method: "get",
|
|
7271
|
+
token: authToken,
|
|
7272
|
+
principal: subj
|
|
7273
|
+
});
|
|
7274
|
+
const r = await _fetch(`${base}/v2/workspaces/${ws}${route.path}?object=${encodeURIComponent(object)}`, { headers });
|
|
7262
7275
|
const text2 = await r.text();
|
|
7263
7276
|
let body;
|
|
7264
7277
|
try {
|
|
@@ -9265,7 +9278,7 @@ ${String(commit).toLowerCase()}`;
|
|
|
9265
9278
|
domain,
|
|
9266
9279
|
candidateHash,
|
|
9267
9280
|
atHash,
|
|
9268
|
-
|
|
9281
|
+
ackBy: connectionPrincipal
|
|
9269
9282
|
})
|
|
9270
9283
|
}));
|
|
9271
9284
|
});
|
|
@@ -9278,8 +9291,7 @@ ${String(commit).toLowerCase()}`;
|
|
|
9278
9291
|
}
|
|
9279
9292
|
const prepared = prepareManagedPromotion(report, candidateHash, domain, {
|
|
9280
9293
|
...currentHash && currentHash !== candidateHash ? { replaces: currentHash } : {},
|
|
9281
|
-
...opts.because !== void 0 ? { acceptanceReason: opts.because } : {}
|
|
9282
|
-
...opts.dispositions ? { dispositions: opts.dispositions } : {}
|
|
9294
|
+
...opts.because !== void 0 ? { acceptanceReason: opts.because } : {}
|
|
9283
9295
|
});
|
|
9284
9296
|
if (!prepared.ok) return prepared;
|
|
9285
9297
|
try {
|
|
@@ -13492,16 +13504,34 @@ function applicationError(message, code, cause) {
|
|
|
13492
13504
|
if (cause !== void 0) error.cause = cause;
|
|
13493
13505
|
return error;
|
|
13494
13506
|
}
|
|
13495
|
-
async function ensureGeneratedModelCurrent(application) {
|
|
13507
|
+
async function ensureGeneratedModelCurrent(application, approveModel) {
|
|
13496
13508
|
if (application.model?.adopt === void 0) {
|
|
13497
13509
|
throw applicationError(
|
|
13498
13510
|
"This generated application has no model lifecycle surface and cannot prove its plans are current.",
|
|
13499
13511
|
"nomos.application.model_lifecycle_missing"
|
|
13500
13512
|
);
|
|
13501
13513
|
}
|
|
13502
|
-
|
|
13514
|
+
let adoption = await application.model.adopt();
|
|
13515
|
+
if (adoption.status === "needs-staging" && adoption.stage !== void 0) {
|
|
13516
|
+
adoption = await adoption.stage();
|
|
13517
|
+
}
|
|
13503
13518
|
if (adoption.status === "adopted") return;
|
|
13504
13519
|
if (adoption.status === "needs-decision") {
|
|
13520
|
+
if (approveModel !== void 0 && adoption.accept !== void 0) {
|
|
13521
|
+
const approval = await approveModel({
|
|
13522
|
+
summary: adoption.summary,
|
|
13523
|
+
review: adoption.review
|
|
13524
|
+
});
|
|
13525
|
+
const because = approval.because.trim();
|
|
13526
|
+
if (!because) {
|
|
13527
|
+
throw applicationError(
|
|
13528
|
+
"Model approval must state the business reason for the change.",
|
|
13529
|
+
"nomos.application.model_decision_reason_missing"
|
|
13530
|
+
);
|
|
13531
|
+
}
|
|
13532
|
+
adoption = await adoption.accept(because);
|
|
13533
|
+
if (adoption.status === "adopted") return;
|
|
13534
|
+
}
|
|
13505
13535
|
throw applicationError(
|
|
13506
13536
|
"This application model changes prior business outcomes and needs an attributed migration decision before the app can write.",
|
|
13507
13537
|
"nomos.application.model_decision_required",
|
|
@@ -13624,7 +13654,7 @@ async function nomosInternalOpenGeneratedApplication(options, bind, internals =
|
|
|
13624
13654
|
...environment?.NOMOS_TEST_K_ROOT_PUBLIC ? { __testKRootPublic: environment.NOMOS_TEST_K_ROOT_PUBLIC } : {}
|
|
13625
13655
|
});
|
|
13626
13656
|
const applicationObject = measureOpenSync("bind generated business API", () => bind(holon2, user));
|
|
13627
|
-
await ensureGeneratedModelCurrent(applicationObject);
|
|
13657
|
+
await ensureGeneratedModelCurrent(applicationObject, options.approveModel);
|
|
13628
13658
|
await measureOpen("prepare generated entry commands", () => prepareGeneratedEntryCommands(holon2, options.readyCommands, options.onPerformance));
|
|
13629
13659
|
const stop = holon2.autoSync({
|
|
13630
13660
|
onResult: (result) => {
|
|
@@ -13871,7 +13901,6 @@ async function nomosInternalOpenGeneratedApplication(options, bind, internals =
|
|
|
13871
13901
|
parent: application,
|
|
13872
13902
|
principal,
|
|
13873
13903
|
subject,
|
|
13874
|
-
lawHash: options.lawHash,
|
|
13875
13904
|
device: { secret, public: publicKey },
|
|
13876
13905
|
authToken,
|
|
13877
13906
|
idToken: authToken,
|
|
@@ -13882,9 +13911,13 @@ async function nomosInternalOpenGeneratedApplication(options, bind, internals =
|
|
|
13882
13911
|
const verdict = birth.verify;
|
|
13883
13912
|
if (verdict !== void 0 && verdict.valid !== true) throw new Error(`the born application failed replay verification: ${String(verdict.error ?? "unknown")}`);
|
|
13884
13913
|
} else if (!hadDurableSecret) {
|
|
13885
|
-
await measureOpen("enrol application device
|
|
13886
|
-
|
|
13887
|
-
|
|
13914
|
+
await measureOpen("enrol application device in its private custody", () => authorityHolon.ensureParentSignerEnrollment({
|
|
13915
|
+
// The write gate that this device will use is the receiving-group workspace itself.
|
|
13916
|
+
// The application root authorises/births that home; it is not a substitute signer index.
|
|
13917
|
+
parent: receivingGroup,
|
|
13918
|
+
// The author gate speaks canonical Nomos principals. A provider subject is deliberately
|
|
13919
|
+
// opaque and may contain its own namespace separators; never enrol that raw value as the actor.
|
|
13920
|
+
principal: subject,
|
|
13888
13921
|
publicKey,
|
|
13889
13922
|
authorSecret: secret,
|
|
13890
13923
|
authToken,
|
|
@@ -13904,8 +13937,8 @@ async function nomosInternalOpenGeneratedApplication(options, bind, internals =
|
|
|
13904
13937
|
if (verified.valid !== true) throw new Error(`the private authority context failed replay verification: ${String(verified.error ?? "unknown")}`);
|
|
13905
13938
|
await measureOpen("save application bootstrap progress", () => store.saveText(journalState, "verified"));
|
|
13906
13939
|
try {
|
|
13907
|
-
await measureOpen("confirm
|
|
13908
|
-
parent:
|
|
13940
|
+
await measureOpen("confirm private-custody signer enrolment", () => authorityHolon.ensureParentSignerEnrollment({
|
|
13941
|
+
parent: receivingGroup,
|
|
13909
13942
|
principal: subject,
|
|
13910
13943
|
authorSecret: secret,
|
|
13911
13944
|
authToken,
|
|
@@ -13930,7 +13963,7 @@ async function nomosInternalOpenGeneratedApplication(options, bind, internals =
|
|
|
13930
13963
|
} catch {
|
|
13931
13964
|
}
|
|
13932
13965
|
const applicationObject = measureOpenSync("bind generated business API", () => bind(holon, user));
|
|
13933
|
-
await measureOpen("confirm generated model is current", () => ensureGeneratedModelCurrent(applicationObject));
|
|
13966
|
+
await measureOpen("confirm generated model is current", () => ensureGeneratedModelCurrent(applicationObject, options.approveModel));
|
|
13934
13967
|
await measureOpen("prepare generated entry commands", () => prepareGeneratedEntryCommands(holon, options.readyCommands, options.onPerformance));
|
|
13935
13968
|
phase = "current";
|
|
13936
13969
|
autoSync = holon.autoSync({
|
package/src/build_package.ts
CHANGED
|
@@ -27,6 +27,7 @@ import { createHash } from "node:crypto";
|
|
|
27
27
|
import { z } from "zod";
|
|
28
28
|
|
|
29
29
|
import type { AggregateHandle } from "./aggregate.js";
|
|
30
|
+
import type { Field } from "./fields.js";
|
|
30
31
|
import type { Directive } from "./directive.js";
|
|
31
32
|
import type { DomainModule, PermissionVocabulary, DartImport } from "./codegen_dart.js";
|
|
32
33
|
import type { AnyCount } from "./count.js";
|
|
@@ -83,6 +84,11 @@ import {
|
|
|
83
84
|
applyConflictPolicyResolvers,
|
|
84
85
|
conflictPoliciesOf,
|
|
85
86
|
} from "./conflicts.js";
|
|
87
|
+
import {
|
|
88
|
+
applyFieldEvolutionsToAggregates,
|
|
89
|
+
fieldEvolutionsOf,
|
|
90
|
+
retirementsOf,
|
|
91
|
+
} from "./evolution.js";
|
|
86
92
|
import {
|
|
87
93
|
expandBusinessBirthExports,
|
|
88
94
|
isBusinessBirthDirective,
|
|
@@ -200,6 +206,8 @@ export interface DomainModuleSpec {
|
|
|
200
206
|
export function composeDomainModule(spec: DomainModuleSpec): DomainModule {
|
|
201
207
|
const domain = spec.domain ?? spec.name;
|
|
202
208
|
const conflictPolicies = conflictPoliciesOf(spec.modules, domain);
|
|
209
|
+
const fieldEvolutions = fieldEvolutionsOf(spec.modules);
|
|
210
|
+
const retirements = retirementsOf(spec.modules, domain);
|
|
203
211
|
const applicationLanguage = applicationLanguageOf(spec.modules, domain);
|
|
204
212
|
let merged: Mod = {};
|
|
205
213
|
for (const m of spec.modules) merged = { ...merged, ...m };
|
|
@@ -520,11 +528,34 @@ export function composeDomainModule(spec: DomainModuleSpec): DomainModule {
|
|
|
520
528
|
directives.push(dir);
|
|
521
529
|
autoDeclaredEnsures.push(ty);
|
|
522
530
|
}
|
|
523
|
-
const aggregates =
|
|
524
|
-
|
|
525
|
-
|
|
531
|
+
const aggregates = applyFieldEvolutionsToAggregates(
|
|
532
|
+
applyConflictPoliciesToAggregates(
|
|
533
|
+
[...byId.values()],
|
|
534
|
+
conflictPolicies,
|
|
535
|
+
domain,
|
|
536
|
+
),
|
|
537
|
+
fieldEvolutions,
|
|
526
538
|
domain,
|
|
527
539
|
);
|
|
540
|
+
const currentAggregates = new Map(aggregates.map((aggregate) => [aggregate.id, aggregate]));
|
|
541
|
+
for (const retired of retirements) {
|
|
542
|
+
const current = currentAggregates.get(retired.aggregate);
|
|
543
|
+
if (retired.kind === "aggregate" && current !== undefined) {
|
|
544
|
+
throw new Error(
|
|
545
|
+
`domain '${domain}' declares '${retired.aggregate}' both current and retired`,
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
if (
|
|
549
|
+
retired.kind === "field" &&
|
|
550
|
+
current !== undefined &&
|
|
551
|
+
retired.field !== undefined &&
|
|
552
|
+
(current.fields as Record<string, Field>)[retired.field] !== undefined
|
|
553
|
+
) {
|
|
554
|
+
throw new Error(
|
|
555
|
+
`domain '${domain}' declares '${retired.aggregate}.${retired.field}' both current and retired`,
|
|
556
|
+
);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
528
559
|
const directiveIds = new Set(directives.map((d) => d.id));
|
|
529
560
|
for (const task of declaredCapabilities) {
|
|
530
561
|
for (const directive of [task.obligation, task.complete, task.fail, task.block, task.deadLetter]) {
|
|
@@ -855,6 +886,9 @@ export function composeDomainModule(spec: DomainModuleSpec): DomainModule {
|
|
|
855
886
|
// hash-bearing manifest; payload-field tracing also drives generated typed references.
|
|
856
887
|
// Omit-when-empty because ordinary domains need no resolver metadata.
|
|
857
888
|
...(surfacedResolvers.length > 0 ? { surfacedResolvers } : {}),
|
|
889
|
+
// Explicit authored tombstones are law. The compiler identity registry may remember
|
|
890
|
+
// every disappearance, but only these declarations permit an activation to retire it.
|
|
891
|
+
...(retirements.length > 0 ? { retirements } : {}),
|
|
858
892
|
...(queries.length > 0 ? { queries } : {}),
|
|
859
893
|
...(counts.length > 0 ? { counts } : {}),
|
|
860
894
|
...(spatials.length > 0 ? { spatials } : {}),
|
|
@@ -17,6 +17,8 @@ import { pathToFileURL } from "node:url";
|
|
|
17
17
|
import { composeDomainModule, type Mod } from "./build_package.js";
|
|
18
18
|
import type { DomainModule } from "./codegen_dart.js";
|
|
19
19
|
import { bindEnumTypeExports } from "./enum_type.js";
|
|
20
|
+
import { discoverEvolutionModulePaths, isEvolutionModulePath } from "./evolution_files.js";
|
|
21
|
+
import { assertEvolutionModuleExports } from "./evolution.js";
|
|
20
22
|
import { checkDomainModules, formatFindings, hasRefusal, type Finding } from "./law_check.js";
|
|
21
23
|
import { LawSourceMap } from "./law_source_map.js";
|
|
22
24
|
import {
|
|
@@ -105,9 +107,18 @@ export async function loadComposedModulesWithSources(
|
|
|
105
107
|
const files: string[] = [];
|
|
106
108
|
for (const rel of d.modules) {
|
|
107
109
|
const abs = path.resolve(cfgDir, rel);
|
|
110
|
+
if (isEvolutionModulePath(abs)) {
|
|
111
|
+
fail(
|
|
112
|
+
`domain '${d.key}': ${rel} is an evolution concern; move it under ` +
|
|
113
|
+
`evolutions/${d.key}/ and remove it from feature modules so it cannot enter QuickJS`,
|
|
114
|
+
);
|
|
115
|
+
}
|
|
108
116
|
if (!existsSync(abs)) fail(`domain '${d.key}': module not found: ${abs}`);
|
|
109
117
|
files.push(abs);
|
|
110
118
|
}
|
|
119
|
+
for (const abs of discoverEvolutionModulePaths(cfgDir, d.key)) {
|
|
120
|
+
if (!files.includes(abs)) files.push(abs);
|
|
121
|
+
}
|
|
111
122
|
try {
|
|
112
123
|
assertPublicPackageImports(files);
|
|
113
124
|
} catch (error) {
|
|
@@ -116,6 +127,7 @@ export async function loadComposedModulesWithSources(
|
|
|
116
127
|
for (const abs of files) {
|
|
117
128
|
// Cache-bust so a re-import (the LSP re-check after an edit) re-evaluates the edited module.
|
|
118
129
|
const mod = (await import(`${pathToFileURL(abs).href}?t=${Date.now()}`)) as Mod;
|
|
130
|
+
if (isEvolutionModulePath(abs)) assertEvolutionModuleExports(mod, abs);
|
|
119
131
|
bindEnumTypeExports(mod, abs);
|
|
120
132
|
mods.push(mod);
|
|
121
133
|
}
|
|
@@ -201,7 +213,6 @@ async function main(): Promise<void> {
|
|
|
201
213
|
const findings: Finding[] = [...dependencyFindings, ...checkDomainModules(modules)];
|
|
202
214
|
|
|
203
215
|
// ── EVOLVE PREVIEW (--against): diff the current build against a prior law + pre-fire the gate. ──
|
|
204
|
-
let evolveDispositions: Record<string, unknown> | undefined;
|
|
205
216
|
if (againstIdx >= 0 || againstArg !== undefined) {
|
|
206
217
|
if (againstArg === undefined || againstArg.startsWith("--")) {
|
|
207
218
|
fail(`--against needs a path: --against <${NOMOS_IDENTITY_FILENAME} | package dir>`);
|
|
@@ -218,7 +229,6 @@ async function main(): Promise<void> {
|
|
|
218
229
|
const current = currentEvolveLaw(modules, lock);
|
|
219
230
|
const diff = evolveDiff(prior.law, current);
|
|
220
231
|
findings.push(...diff.findings);
|
|
221
|
-
if (Object.keys(diff.dispositions).length > 0) evolveDispositions = diff.dispositions;
|
|
222
232
|
if (!asJson) console.log(`githolon check: evolve preview against ${prior.source}`);
|
|
223
233
|
}
|
|
224
234
|
|
|
@@ -255,14 +265,6 @@ async function main(): Promise<void> {
|
|
|
255
265
|
}
|
|
256
266
|
if (findings.length === 0) console.log(" all clear — no static twin flagged anything");
|
|
257
267
|
|
|
258
|
-
// The consolidated, pasteable dispositions the destructive evolves demand (per domain).
|
|
259
|
-
if (evolveDispositions !== undefined) {
|
|
260
|
-
console.log(
|
|
261
|
-
"\ngitholon check: to admit the destructive evolve, include `dispositions` in the installation offer:",
|
|
262
|
-
);
|
|
263
|
-
console.log(JSON.stringify(evolveDispositions, null, 2));
|
|
264
|
-
}
|
|
265
|
-
|
|
266
268
|
process.exit(hasRefusal(findings) ? 1 : 0);
|
|
267
269
|
}
|
|
268
270
|
|
package/src/codegen_dart.ts
CHANGED
|
@@ -2742,14 +2742,14 @@ export function generateDartActivityRegistry(entries: readonly PackageActivityEn
|
|
|
2742
2742
|
` final String summary;`,
|
|
2743
2743
|
` final NomosModelReview review;`,
|
|
2744
2744
|
` final Future<NomosModelAdoption> Function()? _stage;`,
|
|
2745
|
-
` final Future<NomosModelAdoption> Function(String
|
|
2745
|
+
` final Future<NomosModelAdoption> Function(String)? _accept;`,
|
|
2746
2746
|
` const NomosModelAdoption.adopted({required this.summary, required this.review})`,
|
|
2747
2747
|
` : status = NomosModelAdoptionStatus.adopted, _stage = null, _accept = null;`,
|
|
2748
2748
|
` const NomosModelAdoption.blocked({required this.summary, required this.review})`,
|
|
2749
2749
|
` : status = NomosModelAdoptionStatus.blocked, _stage = null, _accept = null;`,
|
|
2750
2750
|
` NomosModelAdoption.needsStaging({required this.summary, required this.review, required Future<NomosModelAdoption> Function() stage})`,
|
|
2751
2751
|
` : status = NomosModelAdoptionStatus.needsStaging, _stage = stage, _accept = null;`,
|
|
2752
|
-
` NomosModelAdoption.needsDecision({required this.summary, required this.review, required Future<NomosModelAdoption> Function(String
|
|
2752
|
+
` NomosModelAdoption.needsDecision({required this.summary, required this.review, required Future<NomosModelAdoption> Function(String) accept})`,
|
|
2753
2753
|
` : status = NomosModelAdoptionStatus.needsDecision, _stage = null, _accept = accept;`,
|
|
2754
2754
|
` Future<NomosModelAdoption> stage() {`,
|
|
2755
2755
|
` final stageCandidate = _stage;`,
|
|
@@ -2758,14 +2758,14 @@ export function generateDartActivityRegistry(entries: readonly PackageActivityEn
|
|
|
2758
2758
|
` }`,
|
|
2759
2759
|
` return stageCandidate();`,
|
|
2760
2760
|
` }`,
|
|
2761
|
-
` Future<NomosModelAdoption> accept(String because
|
|
2761
|
+
` Future<NomosModelAdoption> accept(String because) {`,
|
|
2762
2762
|
` final reason = because.trim();`,
|
|
2763
2763
|
` final acceptDecision = _accept;`,
|
|
2764
2764
|
` if (status != NomosModelAdoptionStatus.needsDecision || acceptDecision == null) {`,
|
|
2765
2765
|
` throw StateError('This model change is not waiting for a business decision.');`,
|
|
2766
2766
|
` }`,
|
|
2767
2767
|
` if (reason.isEmpty) throw ArgumentError('accept(reason) needs the business reason for changing prior outcomes');`,
|
|
2768
|
-
` return acceptDecision(reason
|
|
2768
|
+
` return acceptDecision(reason);`,
|
|
2769
2769
|
` }`,
|
|
2770
2770
|
`}`,
|
|
2771
2771
|
``,
|
|
@@ -4788,6 +4788,9 @@ export interface DomainModule {
|
|
|
4788
4788
|
* Absent when the domain declares no Surfaced field (byte-identical — the era rule).
|
|
4789
4789
|
*/
|
|
4790
4790
|
surfacedResolvers?: import("./surfaced_lint.js").SurfacedResolverBinding[];
|
|
4791
|
+
/** Explicit tombstones authored in separate evolution files. These compile into
|
|
4792
|
+
* candidate USDA and are never exposed through generated tenant clients. */
|
|
4793
|
+
retirements?: import("./evolution.js").Retirement[];
|
|
4791
4794
|
/**
|
|
4792
4795
|
* STABLE-ID CONTINUITY (#58 — names are labels, identity is minted). When present
|
|
4793
4796
|
* (attached by `nomos-compile` from the PRIOR build's identity manifests), the
|
|
@@ -1673,11 +1673,11 @@ export function generateDartBridgeClient(
|
|
|
1673
1673
|
` sameOutcome: projection?['equal'] as bool?, differences: differences);`,
|
|
1674
1674
|
` }`,
|
|
1675
1675
|
``,
|
|
1676
|
-
` Future<NomosModelAdoption> _adoptGeneratedModel([String? because
|
|
1676
|
+
` Future<NomosModelAdoption> _adoptGeneratedModel([String? because]) async {`,
|
|
1677
1677
|
` final raw = await bridge.nomosFrameworkAdoptGeneratedModel(`,
|
|
1678
1678
|
` domain: ${dartStr(
|
|
1679
1679
|
domain
|
|
1680
|
-
)}, candidateHash: domainHash, because: because
|
|
1680
|
+
)}, candidateHash: domainHash, because: because);`,
|
|
1681
1681
|
` final reportRaw = raw['report'];`,
|
|
1682
1682
|
` final report = reportRaw is Map ? reportRaw.cast<String, Object?>() : null;`,
|
|
1683
1683
|
` final review = _nomosModelReview(report);`,
|
|
@@ -1703,20 +1703,9 @@ export function generateDartBridgeClient(
|
|
|
1703
1703
|
` if (stage == 'acceptance') {`,
|
|
1704
1704
|
` return NomosModelAdoption.needsDecision(`,
|
|
1705
1705
|
` summary: 'This model would change prior business outcomes. Review the differences and record why that is intended.',`,
|
|
1706
|
-
` review: review, accept: (reason
|
|
1706
|
+
` review: review, accept: (reason) => _adoptGeneratedModel(reason));`,
|
|
1707
1707
|
` }`,
|
|
1708
1708
|
` final evolve = (report?['evolve'] as Map?)?.cast<String, Object?>();`,
|
|
1709
|
-
` // A field/aggregate the candidate genuinely removed is a #58 disposition decision, not a`,
|
|
1710
|
-
` // dead end: retry with the SAME accept/dispositions seam so the tenant's own policy can`,
|
|
1711
|
-
` // supply dispositions.retired. Every prior stage (promoted/staging-required/acceptance) is`,
|
|
1712
|
-
` // already handled above; 'identity' (needs sign-in) is the one remaining stage this must NOT`,
|
|
1713
|
-
` // paper over, so it is the sole exclusion rather than requiring an exact 'preflight' match or`,
|
|
1714
|
-
` // exact boolean report fields, which may not round-trip identically across every bridge.`,
|
|
1715
|
-
` if (stage != 'identity') {`,
|
|
1716
|
-
` return NomosModelAdoption.needsDecision(`,
|
|
1717
|
-
` summary: 'This model cannot yet interpret every existing value without a declared disposition. Review the differences and record why that is intended.',`,
|
|
1718
|
-
` review: review, accept: (reason, {dispositions}) => _adoptGeneratedModel(reason, dispositions));`,
|
|
1719
|
-
` }`,
|
|
1720
1709
|
` final rawError = raw['error']?.toString().trim();`,
|
|
1721
1710
|
` final summary = rawError != null && rawError.isNotEmpty`,
|
|
1722
1711
|
` ? rawError`,
|
|
@@ -2436,8 +2425,8 @@ export function generateDartBridgeClient(
|
|
|
2436
2425
|
` : null,`,
|
|
2437
2426
|
]),
|
|
2438
2427
|
` accept: adoption.status == NomosModelAdoptionStatus.needsDecision`,
|
|
2439
|
-
` ? (reason
|
|
2440
|
-
` final accepted = await adoption.accept(reason
|
|
2428
|
+
` ? (reason) async {`,
|
|
2429
|
+
` final accepted = await adoption.accept(reason);`,
|
|
2441
2430
|
` // A retry that still isn't adopted (a transient business-outcome/history race,`,
|
|
2442
2431
|
` // e.g. concurrent writes landing between the bare preflight and this accept) must`,
|
|
2443
2432
|
` // NOT be swallowed as a terminal StateError: re-throw the SAME typed exception so`,
|