@githolon/dsl 0.105.4 → 0.105.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dart/CHANGELOG.md +38 -0
- package/dart/lib/src/runner/node-entry.mjs +223 -33
- package/dart/lib/src/runner/offline-install.mjs +263 -37
- package/dart/lib/src/webview_bridge.dart +149 -16
- package/dart/pubspec.lock +1 -1
- package/dart/pubspec.yaml +2 -2
- package/dart/test/acquire_session_test.dart +37 -0
- package/dart/test/residency_refusal_test.dart +49 -0
- package/dart/test/sealing_client_test.dart +1 -1
- package/dart/test/webview_bridge_test.dart +19 -0
- package/dart_types/CHANGELOG.md +13 -0
- package/dart_types/lib/nomos_types.dart +4 -0
- package/dart_types/lib/src/local_work_rejected.dart +117 -0
- package/dart_types/lib/src/subscriptions.dart +5 -1
- package/dart_types/pubspec.yaml +1 -1
- package/package.json +1 -1
- package/runtime/generated-application-host.js +202 -32
- package/src/check_package_main.ts +25 -54
- package/src/codegen_ts.ts +7 -0
- package/src/compat_package_main.ts +36 -30
- package/src/compile_package_main.ts +44 -39
- package/src/decl_shapes.ts +1 -1
- package/src/engine_entry.ts +2 -2
- package/src/evolve_preview.ts +7 -7
- package/src/identity_model.ts +123 -0
- package/src/identity_usda.ts +548 -0
- package/src/law_identity.ts +15 -0
- package/src/lsp_server.ts +14 -37
- package/src/stable_ids.ts +1 -1
- package/src/stable_id_lockfile.ts +0 -278
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* discovery), runs {@link checkDomainModules}, prints the unified report, and exits
|
|
11
11
|
* non-zero on any REFUSE-level finding. `compile` runs the same twins implicitly.
|
|
12
12
|
*/
|
|
13
|
-
import { existsSync, readFileSync,
|
|
13
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
14
14
|
import path from "node:path";
|
|
15
15
|
import { pathToFileURL } from "node:url";
|
|
16
16
|
|
|
@@ -22,12 +22,14 @@ import { LawSourceMap } from "./law_source_map.js";
|
|
|
22
22
|
import {
|
|
23
23
|
currentEvolveLaw,
|
|
24
24
|
evolveDiff,
|
|
25
|
-
evolveLawFromInterface,
|
|
26
25
|
evolveLawFromLockfile,
|
|
27
26
|
type EvolveLaw,
|
|
28
|
-
type
|
|
27
|
+
type CompilerIdentityModel,
|
|
29
28
|
} from "./evolve_preview.js";
|
|
30
|
-
import {
|
|
29
|
+
import {
|
|
30
|
+
NOMOS_IDENTITY_FILENAME,
|
|
31
|
+
parseIdentityUsda,
|
|
32
|
+
} from "./identity_usda.js";
|
|
31
33
|
import {
|
|
32
34
|
validateNomosPackageConfig,
|
|
33
35
|
type NormalizedNomosPackageConfig,
|
|
@@ -136,77 +138,46 @@ export async function loadComposedModulesWithSources(
|
|
|
136
138
|
}
|
|
137
139
|
|
|
138
140
|
/**
|
|
139
|
-
* Load the PRIOR
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
* A live `https://…` prior is NOT supported (the installed package's stable-ids aren't retrievable
|
|
143
|
-
* from GET /domains); point `--against` at the deployed source's interface and lock sidecars instead.
|
|
141
|
+
* Load the PRIOR identity surface for `--against <path>` (the evolve preview's baseline). The one
|
|
142
|
+
* supported artifact is the committed `nomos.identity.usda` layer, directly or via its package dir.
|
|
143
|
+
* There is no interface/JSON sidecar lane: prior executable-law inspection belongs to the holon.
|
|
144
144
|
*/
|
|
145
145
|
function loadPriorEvolveLaw(arg: string): { law: EvolveLaw; source: string; note?: string } {
|
|
146
146
|
if (/^https?:\/\//.test(arg)) {
|
|
147
147
|
fail(
|
|
148
148
|
`--against does not support a live URL (${arg}) — the installed package's #58 stable-ids are ` +
|
|
149
|
-
|
|
149
|
+
`not retrievable from GET /domains. Point --against at the deployed source's ${NOMOS_IDENTITY_FILENAME}.`,
|
|
150
150
|
);
|
|
151
151
|
}
|
|
152
152
|
const abs = path.resolve(process.cwd(), arg);
|
|
153
153
|
if (!existsSync(abs)) fail(`--against: prior not found: ${abs}`);
|
|
154
|
-
// Resolve a directory to its
|
|
154
|
+
// Resolve a directory to its one committed identity layer.
|
|
155
155
|
let file = abs;
|
|
156
156
|
if (statSync(abs).isDirectory()) {
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
else if (existsSync(lock)) file = lock;
|
|
161
|
-
else fail(`--against: no *.interface.json or nomos.stable-ids.json under ${abs}`);
|
|
157
|
+
const identity = path.join(abs, NOMOS_IDENTITY_FILENAME);
|
|
158
|
+
if (existsSync(identity)) file = identity;
|
|
159
|
+
else fail(`--against: no ${NOMOS_IDENTITY_FILENAME} under ${abs}`);
|
|
162
160
|
}
|
|
163
|
-
let
|
|
161
|
+
let lock: CompilerIdentityModel;
|
|
164
162
|
try {
|
|
165
|
-
|
|
163
|
+
lock = parseIdentityUsda(readFileSync(file, "utf8"));
|
|
166
164
|
} catch (e) {
|
|
167
165
|
fail(`--against: could not parse ${file}: ${(e as Error).message}`);
|
|
168
166
|
}
|
|
169
|
-
if (path.basename(file) === "nomos.stable-ids.json") {
|
|
170
|
-
return {
|
|
171
|
-
law: evolveLawFromLockfile(parseStableIdLockfile(parsed)),
|
|
172
|
-
source: file,
|
|
173
|
-
note: `prior is a lockfile — aggregate/field identity is diffed, but directive payload changes require the sibling interface sidecar.`,
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
const lockCandidates = [
|
|
177
|
-
path.join(path.dirname(file), "nomos.stable-ids.json"),
|
|
178
|
-
path.join(path.dirname(path.dirname(file)), "nomos.stable-ids.json"),
|
|
179
|
-
];
|
|
180
|
-
const lockFile = lockCandidates.find((candidate) => existsSync(candidate));
|
|
181
|
-
const lock = lockFile === undefined
|
|
182
|
-
? undefined
|
|
183
|
-
: parseStableIdLockfile(JSON.parse(readFileSync(lockFile, "utf8")));
|
|
184
167
|
return {
|
|
185
|
-
law:
|
|
186
|
-
source:
|
|
187
|
-
|
|
188
|
-
? { note: `prior has no stable-id lock beside it — directive shapes are checked, but driver and contract evolution evidence is incomplete.` }
|
|
189
|
-
: {}),
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/** Find a compiler diagnostic `*.interface.json` directly or one level down in `build/`. */
|
|
194
|
-
function findInterfaceJson(dir: string): string | undefined {
|
|
195
|
-
const scan = (d: string): string | undefined => {
|
|
196
|
-
if (!existsSync(d)) return undefined;
|
|
197
|
-
const hit = readdirSync(d).find((f) => f.endsWith(".interface.json"));
|
|
198
|
-
return hit !== undefined ? path.join(d, hit) : undefined;
|
|
168
|
+
law: evolveLawFromLockfile(lock),
|
|
169
|
+
source: file,
|
|
170
|
+
note: `prior identity is diffed by stable id; directive payload compatibility is negotiated from installed USDA by the holon, never a sidecar.`,
|
|
199
171
|
};
|
|
200
|
-
return scan(dir) ?? scan(path.join(dir, "build"));
|
|
201
172
|
}
|
|
202
173
|
|
|
203
|
-
/** Read the committed
|
|
204
|
-
function loadCwdLockfile(configArg: string):
|
|
174
|
+
/** Read the committed typed identity layer beside the config (the CURRENT identity). */
|
|
175
|
+
function loadCwdLockfile(configArg: string): CompilerIdentityModel | undefined {
|
|
205
176
|
const cfgDir = path.dirname(path.resolve(process.cwd(), configArg));
|
|
206
|
-
const lockPath = path.join(cfgDir,
|
|
177
|
+
const lockPath = path.join(cfgDir, NOMOS_IDENTITY_FILENAME);
|
|
207
178
|
if (!existsSync(lockPath)) return undefined;
|
|
208
179
|
try {
|
|
209
|
-
return
|
|
180
|
+
return parseIdentityUsda(readFileSync(lockPath, "utf8"));
|
|
210
181
|
} catch {
|
|
211
182
|
return undefined;
|
|
212
183
|
}
|
|
@@ -233,12 +204,12 @@ async function main(): Promise<void> {
|
|
|
233
204
|
let evolveDispositions: Record<string, unknown> | undefined;
|
|
234
205
|
if (againstIdx >= 0 || againstArg !== undefined) {
|
|
235
206
|
if (againstArg === undefined || againstArg.startsWith("--")) {
|
|
236
|
-
fail(`--against needs a path: --against
|
|
207
|
+
fail(`--against needs a path: --against <${NOMOS_IDENTITY_FILENAME} | package dir>`);
|
|
237
208
|
}
|
|
238
209
|
const lock = loadCwdLockfile(configArg);
|
|
239
210
|
if (lock === undefined && !asJson) {
|
|
240
211
|
console.log(
|
|
241
|
-
|
|
212
|
+
`githolon check: --against — no ${NOMOS_IDENTITY_FILENAME} in the config dir; the current law's stable ids ` +
|
|
242
213
|
"fall back to NAMES (a rename would read as removal+add). Run `githolon compile` first for a sid-accurate preview.",
|
|
243
214
|
);
|
|
244
215
|
}
|
package/src/codegen_ts.ts
CHANGED
|
@@ -4078,6 +4078,13 @@ export function generateTsClient(modules: readonly DomainModule[], opts: TsClien
|
|
|
4078
4078
|
` (holon, user) => _nomosBind${applicationName}(holon as NomosHolon, user),`,
|
|
4079
4079
|
` );`,
|
|
4080
4080
|
`}`,
|
|
4081
|
+
...(clientInterface === undefined
|
|
4082
|
+
? []
|
|
4083
|
+
: [
|
|
4084
|
+
`// Compiler tooling compares the requirement carried by the client that will actually ship.`,
|
|
4085
|
+
`// A global symbol keeps this off tenant autocomplete while avoiding a duplicate sidecar.`,
|
|
4086
|
+
`Object.defineProperty(${applicationOpener}, Symbol.for("nomos.generated-interface"), { value: ${interfaceConstName(opts.packageName)}, enumerable: false });`,
|
|
4087
|
+
]),
|
|
4081
4088
|
``,
|
|
4082
4089
|
);
|
|
4083
4090
|
}
|
|
@@ -5,17 +5,17 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* `githolon compat <target> [--config …] [--domain …] [--json]` — THE CI GATE (task #31, the compat superpower).
|
|
7
7
|
*
|
|
8
|
-
* Compares the CURRENT
|
|
9
|
-
*
|
|
8
|
+
* Compares the CURRENT generated client's carried structural REQUIREMENT against a TARGET's
|
|
9
|
+
* installed law (the workspace OFFER), PER MEMBER, via the #72
|
|
10
10
|
* subtype relation (`memberVerdicts`). Exits NON-ZERO on any incompatible member — so a client/law
|
|
11
11
|
* mismatch is caught in CI, before it ships. The target is:
|
|
12
|
-
* •
|
|
12
|
+
* • a generated `.client.mjs` (or a build/package DIR containing one);
|
|
13
13
|
* • a LIVE workspace URL (`https://host/v2/workspaces/<ws>` or `https://host --workspace <ws>`) —
|
|
14
14
|
* connect()s and reads the on-ledger offer (`holon.interfaceOffer()`).
|
|
15
15
|
*
|
|
16
16
|
* Human report by default; `--json` emits the machine surface (the per-member array + verdict).
|
|
17
17
|
*/
|
|
18
|
-
import { existsSync,
|
|
18
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
19
19
|
import path from "node:path";
|
|
20
20
|
|
|
21
21
|
import { memberVerdicts, type DomainInterface, type MemberVerdict } from "./shape_compat.js";
|
|
@@ -41,7 +41,7 @@ function mergeInterfaces(byDomain: InterfaceMap | undefined): DomainInterface {
|
|
|
41
41
|
return out;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
/** The package name from `nomos.project.ts` (only field we need — to locate
|
|
44
|
+
/** The package name from `nomos.project.ts` (only field we need — to locate its generated client). */
|
|
45
45
|
async function loadPackageName(configArg: string): Promise<{ name: string; dir: string }> {
|
|
46
46
|
const configPath = path.resolve(process.cwd(), configArg);
|
|
47
47
|
if (!existsSync(configPath)) fail(`config not found: ${configPath} (pass the package config, or run from the package dir)`);
|
|
@@ -51,45 +51,51 @@ async function loadPackageName(configArg: string): Promise<{ name: string; dir:
|
|
|
51
51
|
return { name: cfg.name, dir: path.dirname(configPath) };
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
const GENERATED_INTERFACE = Symbol.for("nomos.generated-interface");
|
|
55
|
+
|
|
56
|
+
async function loadClientRequirement(file: string): Promise<InterfaceMap> {
|
|
57
|
+
const { pathToFileURL } = await import("node:url");
|
|
58
|
+
let generated: Record<string, unknown>;
|
|
59
|
+
try {
|
|
60
|
+
generated = await import(`${pathToFileURL(file).href}?compat=${Date.now()}`) as Record<string, unknown>;
|
|
61
|
+
} catch (error) {
|
|
62
|
+
fail(`could not load generated client ${file}: ${(error as Error).message}`);
|
|
63
|
+
}
|
|
64
|
+
for (const value of Object.values(generated)) {
|
|
65
|
+
if (typeof value !== "function") continue;
|
|
66
|
+
const requirement = (value as unknown as Record<PropertyKey, unknown>)[GENERATED_INTERFACE];
|
|
67
|
+
if (requirement !== null && typeof requirement === "object") return requirement as InterfaceMap;
|
|
68
|
+
}
|
|
69
|
+
fail(`generated client ${file} carries no Nomos structural requirement; recompile it with the current @githolon/dsl`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** The CURRENT requirement carried by the generated client that will ship. */
|
|
73
|
+
async function loadCurrentInterface(pkgDir: string, name: string): Promise<InterfaceMap> {
|
|
74
|
+
const p = path.join(pkgDir, "build", `${name}.client.mjs`);
|
|
57
75
|
if (!existsSync(p)) {
|
|
58
76
|
fail(
|
|
59
|
-
`no current
|
|
77
|
+
`no current generated client at ${p} — run \`githolon compile\` first.`,
|
|
60
78
|
);
|
|
61
79
|
}
|
|
62
|
-
|
|
63
|
-
return JSON.parse(readFileSync(p, "utf8")) as InterfaceMap;
|
|
64
|
-
} catch (e) {
|
|
65
|
-
fail(`could not parse ${p}: ${(e as Error).message}`);
|
|
66
|
-
}
|
|
80
|
+
return loadClientRequirement(p);
|
|
67
81
|
}
|
|
68
82
|
|
|
69
|
-
/** Read a TARGET
|
|
70
|
-
function loadFileOffer(arg: string): { offer: InterfaceMap; source: string } {
|
|
83
|
+
/** Read a TARGET requirement from the generated client it will ship. */
|
|
84
|
+
async function loadFileOffer(arg: string): Promise<{ offer: InterfaceMap; source: string }> {
|
|
71
85
|
const abs = path.resolve(process.cwd(), arg);
|
|
72
86
|
if (!existsSync(abs)) fail(`target not found: ${abs}`);
|
|
73
87
|
let file = abs;
|
|
74
88
|
if (statSync(abs).isDirectory()) {
|
|
75
89
|
const scan = (d: string): string | undefined => {
|
|
76
90
|
if (!existsSync(d)) return undefined;
|
|
77
|
-
const hit = readdirSync(d).find((f) => f.endsWith(".
|
|
91
|
+
const hit = readdirSync(d).find((f) => f.endsWith(".client.mjs"));
|
|
78
92
|
return hit !== undefined ? path.join(d, hit) : undefined;
|
|
79
93
|
};
|
|
80
94
|
const found = scan(abs) ?? scan(path.join(abs, "build"));
|
|
81
|
-
if (found === undefined) fail(`no *.
|
|
95
|
+
if (found === undefined) fail(`no *.client.mjs under ${abs}`);
|
|
82
96
|
file = found;
|
|
83
97
|
}
|
|
84
|
-
|
|
85
|
-
try {
|
|
86
|
-
parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
87
|
-
} catch (e) {
|
|
88
|
-
fail(`could not parse ${file}: ${(e as Error).message}`);
|
|
89
|
-
}
|
|
90
|
-
const offer = parsed as InterfaceMap;
|
|
91
|
-
if (offer === null || typeof offer !== "object") fail(`target ${file} carries no structural interface`);
|
|
92
|
-
return { offer, source: file };
|
|
98
|
+
return { offer: await loadClientRequirement(file), source: file };
|
|
93
99
|
}
|
|
94
100
|
|
|
95
101
|
/** Read a LIVE workspace's on-ledger offer through the compiler-private runtime bundled with the DSL. */
|
|
@@ -155,10 +161,10 @@ async function main(): Promise<void> {
|
|
|
155
161
|
// The positional target = the first non-flag arg that isn't a flag VALUE.
|
|
156
162
|
const flagsWithVals = new Set(["--config", "--workspace", "--domain"]);
|
|
157
163
|
const target = argv.find((a, i) => !a.startsWith("--") && !(i > 0 && flagsWithVals.has(argv[i - 1]!)));
|
|
158
|
-
if (!target) fail(`usage: githolon compat <workspace-url |
|
|
164
|
+
if (!target) fail(`usage: githolon compat <workspace-url | client.mjs | dir> [--config <cfg>] [--workspace <ws>] [--domain <name,...>] [--json]`);
|
|
159
165
|
|
|
160
166
|
const { name, dir } = await loadPackageName(configArg);
|
|
161
|
-
const allCurrent = loadCurrentInterface(dir, name);
|
|
167
|
+
const allCurrent = await loadCurrentInterface(dir, name);
|
|
162
168
|
const requestedDomains = domainFlag?.split(",").map((domain) => domain.trim()).filter(Boolean) ?? [];
|
|
163
169
|
for (const domain of requestedDomains) {
|
|
164
170
|
if (allCurrent[domain] === undefined) fail(`current package '${name}' has no domain '${domain}'`);
|
|
@@ -169,7 +175,7 @@ async function main(): Promise<void> {
|
|
|
169
175
|
|
|
170
176
|
const { offer, source } = /^https?:\/\//.test(target)
|
|
171
177
|
? await loadLiveOffer(target, workspaceFlag)
|
|
172
|
-
: loadFileOffer(target);
|
|
178
|
+
: await loadFileOffer(target);
|
|
173
179
|
|
|
174
180
|
// The subtype check is PER MEMBER over the merged interfaces (directives keyed by id, aggregates by label).
|
|
175
181
|
const verdicts = memberVerdicts(mergeInterfaces(current), mergeInterfaces(offer));
|
|
@@ -145,11 +145,14 @@ import {
|
|
|
145
145
|
type StableIds,
|
|
146
146
|
} from "./stable_ids.js";
|
|
147
147
|
import {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
148
|
+
identityRegistryFromModel,
|
|
149
|
+
type CompilerIdentityModel,
|
|
150
|
+
} from "./identity_model.js";
|
|
151
|
+
import {
|
|
152
|
+
NOMOS_IDENTITY_FILENAME,
|
|
153
|
+
parseIdentityUsda,
|
|
154
|
+
serializeIdentityUsda,
|
|
155
|
+
} from "./identity_usda.js";
|
|
153
156
|
import { reconcileStableIdsWithIdentity } from "./stable_id_identity_bridge.js";
|
|
154
157
|
import { discoverLawGraph, type LawGraph } from "./law_graph.js";
|
|
155
158
|
import { emitFrameworkLawUsda, emitSparseLawGraphUsda } from "./law_graph_usda.js";
|
|
@@ -657,7 +660,7 @@ function firstLawDifference(expected: unknown, actual: unknown, at = "$law"): st
|
|
|
657
660
|
// ── decl auto-discovery (by SHAPE, mirroring the engine entry's duck-types) ───────
|
|
658
661
|
// The query/workspace-invariant/spatial/sum/count predicates + `discover` live in the SHARED
|
|
659
662
|
// bundle-safe `decl_shapes.ts` (imported above) — the lump's self-describe verb discovers by the
|
|
660
|
-
// EXACT same shape so the kernel-served OpenAPI
|
|
663
|
+
// EXACT same shape so the kernel-served OpenAPI is a deterministic projection of installed law.
|
|
661
664
|
|
|
662
665
|
function isDerivedDecl(v: unknown): v is DerivedDecl {
|
|
663
666
|
return (
|
|
@@ -836,6 +839,10 @@ const DART_SUPPORT_CORE_SRC = [
|
|
|
836
839
|
// The custody-lifecycle types (NomosCustodyBreak/NomosCustodyStatus/CustodyBreakPolicy) — the generated
|
|
837
840
|
// client + the vendored bridge reference them through the barrel, so they must vendor. Pure data.
|
|
838
841
|
"custody.dart",
|
|
842
|
+
// THE LOCAL-WORK-REJECTED LIFECYCLE (seated_barrier_and_seal_obligation.md Part 4):
|
|
843
|
+
// NomosLocalWorkRejectedEvent/NomosRejectedIntent — the vendored bridge's localWorkRejectedEvents
|
|
844
|
+
// stream types ride through the barrel, so they must vendor. Pure data.
|
|
845
|
+
"local_work_rejected.dart",
|
|
839
846
|
// SURFACED MERGE CONFLICTS: SurfacedValue<T>/SurfacedObservation<T> — a generated read model with a
|
|
840
847
|
// `.merge(Surfaced(...))` field references them through the barrel, so they must vendor. Pure data.
|
|
841
848
|
"surfaced.dart",
|
|
@@ -1586,8 +1593,8 @@ function emitDart(
|
|
|
1586
1593
|
// The generated clients import their runtime support directly. Keeping it out of the public barrel is
|
|
1587
1594
|
// the surface firewall: a tenant import receives business types and application APIs, never raw runtime.
|
|
1588
1595
|
supportImport === "vendored"
|
|
1589
|
-
? `export '${genRel}/src/${VENDORED_TYPES_SHIM}' show NomosRef, NomosOptionalRef, VersionedNomosRef, ReferenceVersionStatus, ReferenceVersionCurrent, ReferenceVersionOutdated, ReferenceVersionUnavailable${sha256DigestExport}${gitObjectIdExport};`
|
|
1590
|
-
: `export 'package:nomos_types/nomos_types.dart' show NomosRef, NomosOptionalRef, VersionedNomosRef, ReferenceVersionStatus, ReferenceVersionCurrent, ReferenceVersionOutdated, ReferenceVersionUnavailable${sha256DigestExport}${gitObjectIdExport};`,
|
|
1596
|
+
? `export '${genRel}/src/${VENDORED_TYPES_SHIM}' show NomosRef, NomosOptionalRef, NomosSlot, VersionedNomosRef, ReferenceVersionStatus, ReferenceVersionCurrent, ReferenceVersionOutdated, ReferenceVersionUnavailable${sha256DigestExport}${gitObjectIdExport};`
|
|
1597
|
+
: `export 'package:nomos_types/nomos_types.dart' show NomosRef, NomosOptionalRef, NomosSlot, VersionedNomosRef, ReferenceVersionStatus, ReferenceVersionCurrent, ReferenceVersionOutdated, ReferenceVersionUnavailable${sha256DigestExport}${gitObjectIdExport};`,
|
|
1591
1598
|
...(contractsImportUri !== undefined
|
|
1592
1599
|
? tenantDartExport(`${genRel}/${CONTRACTS_FILE}.dart`, sourceByFile.get(CONTRACTS_FILE) ?? "")
|
|
1593
1600
|
: []),
|
|
@@ -1649,12 +1656,12 @@ const dartTypesImportFor = (generatedSource: string): string => {
|
|
|
1649
1656
|
* just the floor generated code needs — a lagging pin forces tenants into dependency_overrides. */
|
|
1650
1657
|
// 0.3.0: SurfacedValue<T>/SurfacedObservation/PendingConflictRow — generated Surfaced-field typing +
|
|
1651
1658
|
// the pendingConflicts read rows.
|
|
1652
|
-
const NOMOS_TYPES_DEP = "^0.8.
|
|
1659
|
+
const NOMOS_TYPES_DEP = "^0.8.7";
|
|
1653
1660
|
// 0.48.x: session-bound clients (XClient.bind/NomosClientInterface/DomainClientSessionMismatch/
|
|
1654
1661
|
// DomainNotInstalledForSession, engine.follow, pendingConflicts lanes) — the generated client
|
|
1655
1662
|
// REQUIRES this surface. 0.48.1 fixes NomosSession.watchPendingConflicts delegation.
|
|
1656
|
-
const NOMOS_CLIENT_DEP = "^0.64.
|
|
1657
|
-
const NOMOS_FLUTTER_DEP = "^0.63.
|
|
1663
|
+
const NOMOS_CLIENT_DEP = "^0.64.23";
|
|
1664
|
+
const NOMOS_FLUTTER_DEP = "^0.63.44";
|
|
1658
1665
|
// DRIFT TRIPWIRE: pubspec_pins.test.ts asserts these equal the CURRENT versions in dsl/dart/pubspec.yaml
|
|
1659
1666
|
// and dsl/dart_types/pubspec.yaml — a Dart release without this bump fails the suite, so tenants never
|
|
1660
1667
|
// land back in dependency_overrides (the exact co2 report this closes, third occurrence).
|
|
@@ -2399,7 +2406,7 @@ function emitDartPackages(
|
|
|
2399
2406
|
businessSharedPath,
|
|
2400
2407
|
[
|
|
2401
2408
|
"// GENERATED by nomos-compile — shared business values and activity; no runtime machinery.",
|
|
2402
|
-
`export 'package:nomos_types/nomos_types.dart' show NomosRef, NomosOptionalRef, VersionedNomosRef, ReferenceVersionStatus, ReferenceVersionCurrent, ReferenceVersionOutdated, ReferenceVersionUnavailable${sha256DigestExport}${gitObjectIdExport}, Identity, User, Recipient, Invitation, ActivityEvent, ActivityRef, ActivitySeverity, SurfacedObservation, SurfacedValue, SurfacedResolved, SurfacedPending, SurfacedEvolutionRequired;`,
|
|
2409
|
+
`export 'package:nomos_types/nomos_types.dart' show NomosRef, NomosOptionalRef, NomosSlot, VersionedNomosRef, ReferenceVersionStatus, ReferenceVersionCurrent, ReferenceVersionOutdated, ReferenceVersionUnavailable${sha256DigestExport}${gitObjectIdExport}, Identity, User, Recipient, Invitation, ActivityEvent, ActivityRef, ActivitySeverity, SurfacedObservation, SurfacedValue, SurfacedResolved, SurfacedPending, SurfacedEvolutionRequired;`,
|
|
2403
2410
|
...(sharedBusinessTypeNames.length === 0
|
|
2404
2411
|
? []
|
|
2405
2412
|
: [`export '${FRAMEWORK_FILE}.dart' show ${sharedBusinessTypeNames.join(", ")};`]),
|
|
@@ -3017,6 +3024,8 @@ async function main(): Promise<void> {
|
|
|
3017
3024
|
`${cfg.name}.layered.usda`,
|
|
3018
3025
|
`${cfg.name}.law-closure.json`,
|
|
3019
3026
|
`${cfg.name}.deploy.json`,
|
|
3027
|
+
`${cfg.name}.interface.json`,
|
|
3028
|
+
`${cfg.name}.openapi.json`,
|
|
3020
3029
|
]) rmSync(path.join(outDir, retired), { force: true });
|
|
3021
3030
|
for (const retiredDir of ["layers", "v3-layers", `${cfg.name}.relation-layers`]) {
|
|
3022
3031
|
rmSync(path.join(outDir, retiredDir), { recursive: true, force: true });
|
|
@@ -3065,7 +3074,7 @@ async function main(): Promise<void> {
|
|
|
3065
3074
|
// lump's `globalThis.describe` needs that it cannot rediscover by shape alone (mins/maxes are
|
|
3066
3075
|
// config-named; sharding sums are framework-appended). Plain JSON (finishCount/Sum/Extremum
|
|
3067
3076
|
// pass finished decls through), serialized into the generated entry as `openapiDecls`, so the
|
|
3068
|
-
// kernel-run describe reproduces
|
|
3077
|
+
// kernel-run describe reproduces this compile's public description deterministically.
|
|
3069
3078
|
const openapiDeclsByDomain: Record<string, unknown> = {};
|
|
3070
3079
|
// A tenant module may import declarations from another configured law module (business-birth
|
|
3071
3080
|
// composition is the common case). Ordinary ES evaluation then initializes that entire closure
|
|
@@ -3734,25 +3743,25 @@ async function main(): Promise<void> {
|
|
|
3734
3743
|
|
|
3735
3744
|
// ── STABLE-ID CONTINUITY (#58 — names are labels, identity is minted) ──
|
|
3736
3745
|
// Derive each composed domain's stable ids from the PRIOR compile: the committed
|
|
3737
|
-
// `nomos.
|
|
3746
|
+
// `nomos.identity.usda` layer beside the config (the durable source — survives
|
|
3738
3747
|
// a clean clone), else the previous build's identity manifests. Match by name;
|
|
3739
3748
|
// exactly ONE disappeared + ONE appeared name of the same kind/shape is an inferred
|
|
3740
3749
|
// RENAME (sid carried, lineage recorded, printed below); anything else mints fresh
|
|
3741
3750
|
// at first appearance (a leftover disappearance is THE EVOLVE GATE's typed question
|
|
3742
3751
|
// at deploy — answered in the upgrade intent's disposition). The resolved continuity
|
|
3743
3752
|
// is attached to the module so the canonical manifest + USD-IR carry it.
|
|
3744
|
-
const lockPath = path.join(cfgDir,
|
|
3745
|
-
const priorLock:
|
|
3746
|
-
?
|
|
3753
|
+
const lockPath = path.join(cfgDir, NOMOS_IDENTITY_FILENAME);
|
|
3754
|
+
const priorLock: CompilerIdentityModel | undefined = existsSync(lockPath)
|
|
3755
|
+
? parseIdentityUsda(readFileSync(lockPath, "utf8"))
|
|
3747
3756
|
: undefined;
|
|
3748
3757
|
const inferredRenames: { domain: string; renames: InferredRename[] }[] = [];
|
|
3749
|
-
let nextIdentity =
|
|
3758
|
+
let nextIdentity = identityRegistryFromModel(priorLock);
|
|
3750
3759
|
const typedLawGraphs = new Map<string, LawGraph>();
|
|
3751
3760
|
// The lock is project-wide, not package-local. Several package configs commonly live beside one
|
|
3752
3761
|
// application stage; compiling one must not erase the stable identity of domains owned by its siblings.
|
|
3753
3762
|
// Current package domains are replaced below, while absent domains remain only as continuity metadata
|
|
3754
3763
|
// and never leak into this package's interface, law, clients or deployment.
|
|
3755
|
-
const nextLock:
|
|
3764
|
+
const nextLock: CompilerIdentityModel = {
|
|
3756
3765
|
v: 1,
|
|
3757
3766
|
domains: { ...(priorLock?.domains ?? {}) },
|
|
3758
3767
|
identity: nextIdentity,
|
|
@@ -3786,7 +3795,7 @@ async function main(): Promise<void> {
|
|
|
3786
3795
|
// it carries no stable ids either.
|
|
3787
3796
|
continue;
|
|
3788
3797
|
}
|
|
3789
|
-
// Continuity source: the committed nomos.
|
|
3798
|
+
// Continuity source: the committed nomos.identity.usda layer (the canonical identity ledger).
|
|
3790
3799
|
// (The old "else the prior build's domain_identity_manifests.json" fallback is gone with that sidecar.)
|
|
3791
3800
|
let prior: StableIds | undefined;
|
|
3792
3801
|
let priorSchemas: Record<string, WireSchema> | undefined;
|
|
@@ -3882,11 +3891,11 @@ async function main(): Promise<void> {
|
|
|
3882
3891
|
schemas: Object.fromEntries(currentAggs.map((a) => [a.id, a.schema])),
|
|
3883
3892
|
};
|
|
3884
3893
|
}
|
|
3885
|
-
// Persist the
|
|
3894
|
+
// Persist the typed identity layer (commit it with the law: it is how a rename keeps its
|
|
3886
3895
|
// identity across clean clones). Existing project-domain order is retained, so once sibling
|
|
3887
3896
|
// packages are registered, recompiling them in any order rewrites the same bytes without a
|
|
3888
3897
|
// giant formatting-only diff in an established lock.
|
|
3889
|
-
writeFileSync(lockPath,
|
|
3898
|
+
writeFileSync(lockPath, serializeIdentityUsda(nextLock), "utf8");
|
|
3890
3899
|
|
|
3891
3900
|
// ── THE STRUCTURAL INTERFACE (#72) — directives (payload shapes) + aggregates (read
|
|
3892
3901
|
// shapes, sid-keyed), keyed by DOMAIN. The SAME object is (a) baked into the generated
|
|
@@ -3934,11 +3943,12 @@ async function main(): Promise<void> {
|
|
|
3934
3943
|
}
|
|
3935
3944
|
: di;
|
|
3936
3945
|
}
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3946
|
+
// NO INTERFACE SIDECAR. The structural interface is an in-memory codegen model only: it is baked
|
|
3947
|
+
// INTO the generated clients where compiler tooling can inspect the requirement that will ship.
|
|
3948
|
+
// Emitting it as JSON created a second representation of law that DRIFTED: the prior sidecar
|
|
3949
|
+
// omitted `principal` and `bornAt`, two fields the USDA declares
|
|
3950
|
+
// `nomos:required = true`, so anything reading it saw a contract the kernel would refuse.
|
|
3951
|
+
// One fact, one representation: the typed USDA closure is the contract.
|
|
3942
3952
|
|
|
3943
3953
|
// ── RECURSIVE-PAYLOAD NOTES (z.lazy) — a self-referencing tree/JSON payload field is FULLY
|
|
3944
3954
|
// supported: each codegen layer mints a named recursive type for it (TS `type <Name>`, Dart
|
|
@@ -5111,16 +5121,11 @@ async function main(): Promise<void> {
|
|
|
5111
5121
|
requiresKernel,
|
|
5112
5122
|
};
|
|
5113
5123
|
|
|
5114
|
-
// ── 3b.
|
|
5115
|
-
//
|
|
5116
|
-
//
|
|
5117
|
-
//
|
|
5118
|
-
|
|
5119
|
-
presentationDomainModules.map((m) => generateOpenApiFragment(m, { lawHash: domainHash })),
|
|
5120
|
-
{ title: `${cfg.name} (nomos package)`, lawHash: domainHash },
|
|
5121
|
-
);
|
|
5122
|
-
const openapiPath = path.join(outDir, `${cfg.name}.openapi.json`);
|
|
5123
|
-
writeFileSync(openapiPath, JSON.stringify(publicOpenapi, null, 2) + "\n", "utf8");
|
|
5124
|
+
// ── 3b. NO OPENAPI SIDECAR. OpenAPI remains the sanctioned standard for describing this package's
|
|
5125
|
+
// API — but it is SERVED, not stored: the kernel derives it from the installed typed USDA IR
|
|
5126
|
+
// (`GET /v2/workspaces/<ws>/openapi.json`), so the description cannot drift from the law it
|
|
5127
|
+
// describes. Writing a build-time copy created exactly the drift the representation rule forbids
|
|
5128
|
+
// — a derived second copy a reader could believe. Ask the holon that runs the law.
|
|
5124
5129
|
|
|
5125
5130
|
// ── 4. human build summary (diagnostic only; never deployment input) ──
|
|
5126
5131
|
const summary = {
|
|
@@ -5882,7 +5887,7 @@ async function main(): Promise<void> {
|
|
|
5882
5887
|
// STABLE IDS (#58): the minted/carried identity surface + every INFERRED rename —
|
|
5883
5888
|
// the silent lane made visible (if an inference is wrong — you meant remove+add —
|
|
5884
5889
|
// split the edit into two compiles, or answer the evolve gate with a disposition).
|
|
5885
|
-
console.log(`
|
|
5890
|
+
console.log(` identity ${rel(lockPath)} (committed typed USDA — identity across renames and retirements)`);
|
|
5886
5891
|
for (const { domain, renames } of inferredRenames) {
|
|
5887
5892
|
for (const r of renames) {
|
|
5888
5893
|
console.log(
|
|
@@ -5899,7 +5904,7 @@ async function main(): Promise<void> {
|
|
|
5899
5904
|
}
|
|
5900
5905
|
console.log(` client ${rel(clientPath)} (typed TS client — payloads, read models, query accessors)`);
|
|
5901
5906
|
for (const note of recursiveNotes) console.log(` note ${note}`);
|
|
5902
|
-
console.log(` openapi
|
|
5907
|
+
console.log(` openapi served by the holon from installed USDA (GET /v2/workspaces/<ws>/openapi.json) — no build-time copy to drift`);
|
|
5903
5908
|
if (proofPath !== undefined) {
|
|
5904
5909
|
console.log(` proof ${rel(proofPath)} (a runnable e2e GENERATED from your law — run: githolon proof)`);
|
|
5905
5910
|
} else {
|
package/src/decl_shapes.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* Why shared: the kernel-served OpenAPI (G1 — openapi residue removal) is produced by the lump
|
|
11
11
|
* running `generateOpenApiFragment` over the SAME modules it dispatches; if the lump discovered
|
|
12
12
|
* queries/counts/sums/spatials by a DIFFERENT shape than the compiler did when it wrote
|
|
13
|
-
*
|
|
13
|
+
* the kernel-served OpenAPI, runtime description would drift from installed law. One predicate
|
|
14
14
|
* set ⇒ one shape ⇒ byte-identity.
|
|
15
15
|
*
|
|
16
16
|
* ENGINE-BUNDLE-SAFE: imports NO node builtin (only DSL types) — it bundles under esbuild
|
package/src/engine_entry.ts
CHANGED
|
@@ -175,7 +175,7 @@ export interface EngineEntryConfig {
|
|
|
175
175
|
readonly openapiDocument?: OpenApiDoc;
|
|
176
176
|
/**
|
|
177
177
|
* The package's OpenAPI document title (the compiler's `"<name> (nomos package)"`). Baked into
|
|
178
|
-
* the lump so `describe` reproduces the compiler's
|
|
178
|
+
* the lump so `describe` reproduces the compiler's public description byte-for-byte without
|
|
179
179
|
* the kernel knowing the package name. The kernel MAY override it (the workspace-level title).
|
|
180
180
|
*/
|
|
181
181
|
readonly packageTitle?: string;
|
|
@@ -1075,7 +1075,7 @@ export function registerEngine(config: EngineEntryConfig): RegisteredEngine {
|
|
|
1075
1075
|
* dispatches. The kernel selects the content-addressed describe plan from the native USD
|
|
1076
1076
|
* package in custody, so the workspace's API surface is a pure,
|
|
1077
1077
|
* deterministic function of installed law — NOT a host-staged blob. Its public `paths` reproduce
|
|
1078
|
-
* the
|
|
1078
|
+
* the public description the compiler derived; describe also carries a private, law-derived
|
|
1079
1079
|
* framework routing manifest which the host consumes internally and never publishes.
|
|
1080
1080
|
* `opts.lawHash`/`opts.title` are injected by the kernel at describe-time (the version stamp +
|
|
1081
1081
|
* package title), matching the compiler's `domainHash`/`"<name> (nomos package)"`.
|
package/src/evolve_preview.ts
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* law get typed 422s until regenerated (directives are not sid-tracked).
|
|
27
27
|
*
|
|
28
28
|
* The preview NEVER needs to emit a `rebinds` fragment: a rename is detected by a MATCHED sid
|
|
29
|
-
* (the compiler carries it via the nomos.
|
|
29
|
+
* (the compiler carries it via the nomos.identity.usda lockfile), so it is already a silent
|
|
30
30
|
* admit — rebinds is only for the hand-repair path where the sid was lost, which this preview,
|
|
31
31
|
* reading the carried sids, never produces.
|
|
32
32
|
*/
|
|
@@ -34,8 +34,8 @@ import type { Finding } from "./law_check.js";
|
|
|
34
34
|
import type { DirectivePayloadShape, DomainInterface } from "./shape_compat.js";
|
|
35
35
|
import { domainInterface } from "./shape_compat.js";
|
|
36
36
|
import type { StableIds } from "./stable_ids_types.js";
|
|
37
|
-
import type {
|
|
38
|
-
export type {
|
|
37
|
+
import type { CompilerIdentityModel } from "./identity_model.js";
|
|
38
|
+
export type { CompilerIdentityModel } from "./identity_model.js";
|
|
39
39
|
import type { DomainModule } from "./codegen_dart.js";
|
|
40
40
|
import type { WireSchema } from "./wire.js";
|
|
41
41
|
|
|
@@ -137,7 +137,7 @@ function evolveDomainFromInterface(iface: DomainInterface): EvolveDomain {
|
|
|
137
137
|
* by the kernel; `.law.usdz` is only its lossless one-file transport envelope. */
|
|
138
138
|
export function evolveLawFromInterface(
|
|
139
139
|
ifaces: Record<string, DomainInterface>,
|
|
140
|
-
lock?:
|
|
140
|
+
lock?: CompilerIdentityModel,
|
|
141
141
|
): EvolveLaw {
|
|
142
142
|
const law: EvolveLaw = {};
|
|
143
143
|
for (const [key, iface] of Object.entries(ifaces)) {
|
|
@@ -180,10 +180,10 @@ export function evolveLawFromInterface(
|
|
|
180
180
|
return law;
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
-
/** Build an EvolveLaw from a `nomos.
|
|
183
|
+
/** Build an EvolveLaw from a `nomos.identity.usda` lockfile — aggregate identity + drivers, but
|
|
184
184
|
* NO directive payloads (a lockfile carries no interface). Directive-level warnings are then
|
|
185
185
|
* unavailable; the caller notes it. */
|
|
186
|
-
export function evolveLawFromLockfile(lock:
|
|
186
|
+
export function evolveLawFromLockfile(lock: CompilerIdentityModel): EvolveLaw {
|
|
187
187
|
const law: EvolveLaw = {};
|
|
188
188
|
for (const [key, d] of Object.entries(lock.domains ?? {})) {
|
|
189
189
|
law[key] = {
|
|
@@ -201,7 +201,7 @@ export function evolveLawFromLockfile(lock: StableIdLockfile): EvolveLaw {
|
|
|
201
201
|
* pre-#58 fallback) — a rename then reads as removal+add; the caller warns to compile first. */
|
|
202
202
|
export function currentEvolveLaw(
|
|
203
203
|
modules: readonly DomainModule[],
|
|
204
|
-
lock?:
|
|
204
|
+
lock?: CompilerIdentityModel,
|
|
205
205
|
): EvolveLaw {
|
|
206
206
|
const law: EvolveLaw = {};
|
|
207
207
|
for (const mod of modules) {
|