@githolon/dsl 0.105.23 → 0.105.24
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 +9 -0
- package/dart/lib/src/runner/node-entry.mjs +4461 -267
- package/dart/lib/src/runner/offline-install.mjs +4337 -115
- package/dart/lib/src/test_harness.dart +316 -235
- package/dart/lib/src/webview_bridge.dart +1478 -1087
- package/dart/pubspec.lock +1 -1
- package/dart/pubspec.yaml +2 -2
- package/dart_types/CHANGELOG.md +5 -0
- package/dart_types/lib/src/errors.dart +78 -58
- package/dart_types/pubspec.yaml +1 -1
- package/package.json +1 -1
- package/runtime/generated-application-host.js +4235 -102
- package/src/codegen_dart_client.ts +7 -10
- package/src/codegen_ts.ts +3 -6
- package/src/compat_manifest.ts +6 -7
- package/src/compile_package_main.ts +9 -11
- package/src/index.ts +9 -11
- package/src/kernel_capabilities.ts +79 -237
|
@@ -39,7 +39,7 @@ import { isGitObjectIdSchema, isSha256DigestSchema, type Field } from "./fields.
|
|
|
39
39
|
import type { Directive } from "./directive.js";
|
|
40
40
|
import type { QueryDecl } from "./query.js";
|
|
41
41
|
import type { DomainModule } from "./codegen_dart.js";
|
|
42
|
-
import {
|
|
42
|
+
import { requiredKernelContracts } from "./kernel_capabilities.js";
|
|
43
43
|
import {
|
|
44
44
|
cap,
|
|
45
45
|
readModelClassName,
|
|
@@ -352,7 +352,7 @@ export function generateDartBridgeClient(
|
|
|
352
352
|
})[domain];
|
|
353
353
|
const className = dartClientClassName(domain);
|
|
354
354
|
const hashConst = dartHashConstName(mod.name);
|
|
355
|
-
const
|
|
355
|
+
const kernelContracts = requiredKernelContracts([mod]);
|
|
356
356
|
const supportImport =
|
|
357
357
|
opts.supportImport === "package"
|
|
358
358
|
? "package:nomos_client/src/nms_generated_runtime.dart"
|
|
@@ -2360,10 +2360,9 @@ export function generateDartBridgeClient(
|
|
|
2360
2360
|
` /// THE STATIC INTERFACE DESCRIPTOR (session_bound_clients.md asks 5/9): what this client EXPECTS`,
|
|
2361
2361
|
` /// of the workspace it binds to — the domain key, the law hash it was generated against, and the`,
|
|
2362
2362
|
` /// structural interface (#72). Consumed by [bind] and by \`session.assertCompatible(${className}.interface)\`.`,
|
|
2363
|
-
` ///
|
|
2364
|
-
`
|
|
2365
|
-
|
|
2366
|
-
.map((f) => dartStr(f))
|
|
2363
|
+
` /// Standard OSGi Contract Namespace requirements derived from this law's shape.`,
|
|
2364
|
+
` static const List<Map<String, String>> kernelContracts = [${kernelContracts
|
|
2365
|
+
.map((contract) => `{${dartStr("namespace")}: ${dartStr(contract.namespace)}, ${dartStr("name")}: ${dartStr(contract.name)}, ${dartStr("version")}: ${dartStr(contract.version)}}`)
|
|
2367
2366
|
.join(", ")}];`,
|
|
2368
2367
|
``,
|
|
2369
2368
|
` static const NomosClientInterface interface = NomosClientInterface(`,
|
|
@@ -2459,10 +2458,8 @@ export function generateDartBridgeClient(
|
|
|
2459
2458
|
` final law = await session.lawStatus(interface.expectedDomainHash);`,
|
|
2460
2459
|
` if (law['drifted'] == true) await adoptGeneratedModel();`,
|
|
2461
2460
|
` await session.assertCompatible(interface);`,
|
|
2462
|
-
` // RELEASE COHERENCE:
|
|
2463
|
-
`
|
|
2464
|
-
` // up front — not an opaque deep-fold refusal. Best-effort (no-op if the cloud advertises no caps).`,
|
|
2465
|
-
` await session.assertKernelCoherence(requiresKernel, lawHash: ${hashConst});`,
|
|
2461
|
+
` // RELEASE COHERENCE: resolve this law's OSGi Contract Namespace requirements before use.`,
|
|
2462
|
+
` await session.assertKernelCoherence(kernelContracts, lawHash: ${hashConst});`,
|
|
2466
2463
|
...(ownedScope === undefined
|
|
2467
2464
|
? []
|
|
2468
2465
|
: [
|
package/src/codegen_ts.ts
CHANGED
|
@@ -1931,9 +1931,8 @@ export function generateTsClient(modules: readonly DomainModule[], opts: TsClien
|
|
|
1931
1931
|
` checkCompat?(compat: { lawHash: string; interfaceHash: string; packageName: string }, requirement?: unknown): NomosCompatVerdict | null;`,
|
|
1932
1932
|
` /** Framework-private readiness hint; generated domain bindings keep first-use plan work off the offer path. */`,
|
|
1933
1933
|
` prepareDomain?(domain: string, packageHash: string): void;`,
|
|
1934
|
-
` /**
|
|
1935
|
-
`
|
|
1936
|
-
` assertKernelCoherence?(requiresKernel: readonly string[], opts?: { lawHash?: string }): unknown;`,
|
|
1934
|
+
` /** Resolve the law's standard OSGi Contract Namespace requirements before bind. */`,
|
|
1935
|
+
` assertKernelCoherence?(requirements: readonly { namespace: "osgi.contract"; name: string; version: string }[], opts?: { lawHash?: string }): unknown;`,
|
|
1937
1936
|
` /** The live compat verdict (set by checkCompat). \`has(memberId)\` is the dark-launch feature flag;`,
|
|
1938
1937
|
` * \`refresh()\` re-derives against the current projection. Absent until the factory binds. */`,
|
|
1939
1938
|
` compat?: NomosCompatVerdict;`,
|
|
@@ -3893,9 +3892,7 @@ export function generateTsClient(modules: readonly DomainModule[], opts: TsClien
|
|
|
3893
3892
|
clientInterface !== undefined
|
|
3894
3893
|
? ` holon.checkCompat?.(${compatConstName(opts.packageName)}, ${interfaceConstName(opts.packageName)});`
|
|
3895
3894
|
: ` holon.checkCompat?.(${compatConstName(opts.packageName)});`,
|
|
3896
|
-
|
|
3897
|
-
// this law requires (e.g. compoundKeys) — instead of the opaque deep fold refusal later.
|
|
3898
|
-
` holon.assertKernelCoherence?.(${compatConstName(opts.packageName)}.requiresKernel ?? [], { lawHash: ${compatConstName(opts.packageName)}.lawHash });`,
|
|
3895
|
+
` holon.assertKernelCoherence?.(${compatConstName(opts.packageName)}.kernelContracts ?? [], { lawHash: ${compatConstName(opts.packageName)}.lawHash });`,
|
|
3899
3896
|
]
|
|
3900
3897
|
: []),
|
|
3901
3898
|
` return {`,
|
package/src/compat_manifest.ts
CHANGED
|
@@ -17,11 +17,10 @@ export interface NomosCompat {
|
|
|
17
17
|
readonly domains: Record<string, { readonly identityHash?: string }>;
|
|
18
18
|
/** The generator provenance — the `@githolon/dsl` version + this manifest's schema. */
|
|
19
19
|
readonly generator: { readonly dsl: string; readonly schema: number };
|
|
20
|
-
/**
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
readonly requiresKernel: readonly string[];
|
|
20
|
+
/** Standard OSGi Contract Namespace requirements derived from the law shape. */
|
|
21
|
+
readonly kernelContracts: readonly {
|
|
22
|
+
readonly namespace: "osgi.contract";
|
|
23
|
+
readonly name: string;
|
|
24
|
+
readonly version: string;
|
|
25
|
+
}[];
|
|
27
26
|
}
|
|
@@ -168,7 +168,7 @@ import { usdzPack } from "./usdz.js";
|
|
|
168
168
|
import { checkDomainModules, formatFindings, hasRefusal } from "./law_check.js";
|
|
169
169
|
import { currentEvolveLaw, evolveDiff, evolveLawFromLockfile } from "./evolve_preview.js";
|
|
170
170
|
import type { NomosCompat } from "./compat_manifest.js";
|
|
171
|
-
import {
|
|
171
|
+
import { requiredKernelContracts, type KernelContractProbeModule } from "./kernel_capabilities.js";
|
|
172
172
|
import { APPLICATION_HOME_DOMAIN } from "./framework/application_home_domain.js";
|
|
173
173
|
import { applicationHomePolicyLaw } from "./framework/application_home.js";
|
|
174
174
|
import { isApplicationHomeGenesis } from "./application_home_genesis.js";
|
|
@@ -1660,12 +1660,12 @@ const dartTypesImportFor = (generatedSource: string): string => {
|
|
|
1660
1660
|
* just the floor generated code needs — a lagging pin forces tenants into dependency_overrides. */
|
|
1661
1661
|
// 0.3.0: SurfacedValue<T>/SurfacedObservation/PendingConflictRow — generated Surfaced-field typing +
|
|
1662
1662
|
// the pendingConflicts read rows.
|
|
1663
|
-
const NOMOS_TYPES_DEP = "^0.8.
|
|
1663
|
+
const NOMOS_TYPES_DEP = "^0.8.8";
|
|
1664
1664
|
// 0.48.x: session-bound clients (XClient.bind/NomosClientInterface/DomainClientSessionMismatch/
|
|
1665
1665
|
// DomainNotInstalledForSession, engine.follow, pendingConflicts lanes) — the generated client
|
|
1666
1666
|
// REQUIRES this surface. 0.48.1 fixes NomosSession.watchPendingConflicts delegation.
|
|
1667
|
-
const NOMOS_CLIENT_DEP = "^0.64.
|
|
1668
|
-
const NOMOS_FLUTTER_DEP = "^0.63.
|
|
1667
|
+
const NOMOS_CLIENT_DEP = "^0.64.39";
|
|
1668
|
+
const NOMOS_FLUTTER_DEP = "^0.63.64";
|
|
1669
1669
|
// DRIFT TRIPWIRE: pubspec_pins.test.ts asserts these equal the CURRENT versions in dsl/dart/pubspec.yaml
|
|
1670
1670
|
// and dsl/dart_types/pubspec.yaml — a Dart release without this bump fails the suite, so tenants never
|
|
1671
1671
|
// land back in dependency_overrides (the exact co2 report this closes, third occurrence).
|
|
@@ -5193,17 +5193,15 @@ async function main(): Promise<void> {
|
|
|
5193
5193
|
const identityHash = identityHashes[key];
|
|
5194
5194
|
compatDomains[key] = identityHash === undefined ? {} : { identityHash };
|
|
5195
5195
|
}
|
|
5196
|
-
// RELEASE COHERENCE —
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
const requiresKernel = ((): string[] => {
|
|
5200
|
-
const probes: FeatureProbeModule[] = domainModules.map((m) => ({
|
|
5196
|
+
// RELEASE COHERENCE — typed OSGi Contract Namespace requirements derived from law shape.
|
|
5197
|
+
const kernelContracts = (() => {
|
|
5198
|
+
const probes: KernelContractProbeModule[] = domainModules.map((m) => ({
|
|
5201
5199
|
...(m.queries ? { queries: m.queries } : {}),
|
|
5202
5200
|
...(m.deriveds ? { deriveds: m.deriveds } : {}),
|
|
5203
5201
|
...(m.surfacedResolvers ? { surfacedResolvers: m.surfacedResolvers } : {}),
|
|
5204
5202
|
...(m.aggregates ? { aggregates: m.aggregates } : {}),
|
|
5205
5203
|
}));
|
|
5206
|
-
return
|
|
5204
|
+
return requiredKernelContracts(probes);
|
|
5207
5205
|
})();
|
|
5208
5206
|
const nomosCompat: NomosCompat = {
|
|
5209
5207
|
packageName: cfg.name,
|
|
@@ -5211,7 +5209,7 @@ async function main(): Promise<void> {
|
|
|
5211
5209
|
interfaceHash: sha256HexUtf8(canonicalJson(packageInterface)),
|
|
5212
5210
|
domains: compatDomains,
|
|
5213
5211
|
generator: { dsl: dslVersion, schema: 1 },
|
|
5214
|
-
|
|
5212
|
+
kernelContracts,
|
|
5215
5213
|
};
|
|
5216
5214
|
|
|
5217
5215
|
// ── 3b. NO OPENAPI SIDECAR. OpenAPI remains the sanctioned standard for describing this package's
|
package/src/index.ts
CHANGED
|
@@ -255,19 +255,17 @@ export { repair, repairsOf, isRepairDecl, type RepairDecl, type RepairMatcher, t
|
|
|
255
255
|
// `nomos-compile` REFUSES law that references read() (a named compile error, never a runtime halt).
|
|
256
256
|
// The captured-reads wave (task #58) wires the capability in and lifts the refusal.
|
|
257
257
|
export { read } from "./read.js";
|
|
258
|
-
// RELEASE COHERENCE —
|
|
258
|
+
// RELEASE COHERENCE — standard OSGi Contract Namespace requirements derived from law shape.
|
|
259
259
|
export {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
assessKernelCoherence,
|
|
260
|
+
requiredKernelContracts,
|
|
261
|
+
assessKernelContracts,
|
|
263
262
|
KernelCoherenceError,
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
type
|
|
267
|
-
type
|
|
268
|
-
type
|
|
269
|
-
type
|
|
270
|
-
type FeatureProbeModule,
|
|
263
|
+
NOMOS_KERNEL_CONTRACT,
|
|
264
|
+
NOMOS_KERNEL_CONTRACT_VERSION,
|
|
265
|
+
type OsgiContractRequirement,
|
|
266
|
+
type OsgiContractCapability,
|
|
267
|
+
type KernelContractVerdict,
|
|
268
|
+
type KernelContractProbeModule,
|
|
271
269
|
} from "./kernel_capabilities.js";
|
|
272
270
|
// ATTESTED CROSS-WORKSPACE READS (slice B — attested_reads_design.md): the declared trust
|
|
273
271
|
// surface (`trustSource`), the foreign query reference, and the reader-side SourceFrontier.
|
|
@@ -1,60 +1,33 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// internally inconsistent. The production kernel accepts law that a compiler emits;
|
|
5
|
-
// the DEV/test-mint kernel a `githolon cloud dev` serves can be STALE and REFUSE the
|
|
6
|
-
// same law — but only at runtime, deep in a law fold ("query declares 2 index keys;
|
|
7
|
-
// the read router supports exactly one"). Four artifacts drift independently:
|
|
8
|
-
// · the compiler (@githolon/dsl) that EMITS the law,
|
|
9
|
-
// · the runner bundle (@githolon/client) that RUNS it,
|
|
10
|
-
// · the production kernel wasm the cloud serves,
|
|
11
|
-
// · the test-mint kernel wasm the dev cloud serves.
|
|
12
|
-
// There is NO version/hash check that catches the skew before the opaque refusal.
|
|
13
|
-
//
|
|
14
|
-
// THE FIX: a kernel advertises a VERSION + a set of named CAPABILITIES (feature flags
|
|
15
|
-
// keyed to the era keys / read-router lanes it implements). A package DECLARES the
|
|
16
|
-
// kernel capabilities its law REQUIRES (derived from its shape — e.g. a compound-key
|
|
17
|
-
// query needs `compoundKeys`). Before the law ever folds, we compare the two and fail
|
|
18
|
-
// with a TYPED, human-legible message NAMING the mismatch — not the deep refusal.
|
|
19
|
-
//
|
|
20
|
-
// This module is the SINGLE SOURCE OF TRUTH for: the capability vocabulary, deriving a
|
|
21
|
-
// package's requirements from its shape, the known-kernel registry (keyed by wasm
|
|
22
|
-
// sha256), and the coherence assessment. The CLI (`githolon doctor`, deploy), the
|
|
23
|
-
// generated client (baked `requiresKernel`), and the cloud worker's
|
|
24
|
-
// `/v1/runtime/capabilities` endpoint all draw on it.
|
|
25
|
-
|
|
1
|
+
// Kernel compatibility uses the standard OSGi Contract Namespace. Domain shape determines which
|
|
2
|
+
// osgi.contract requirements a generated client carries; provider repositories advertise matching
|
|
3
|
+
// capabilities. There is no hash registry, feature vocabulary manifest, or Nomos resolver language.
|
|
26
4
|
import type { QueryDecl } from "./query.js";
|
|
27
5
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
/** The #58 captured-read lane (`read()` in deployable law + `.reads(query)`). */
|
|
37
|
-
| "capturedReads"
|
|
38
|
-
/** The #41 declared-invariant gate (`invariant` / `workspaceInvariant`). */
|
|
39
|
-
| "invariantGate"
|
|
40
|
-
/** Surfaced(inner) — retained concurrent competing values as a pending set. */
|
|
41
|
-
| "surfacedMerge"
|
|
42
|
-
/** `.attributed()` / aggregate `{attributed:true}` per-field provenance. */
|
|
43
|
-
| "fieldProvenance"
|
|
44
|
-
/** Null as an opt-in named capability (`admitsNull()`). */
|
|
45
|
-
| "nullSemantics"
|
|
46
|
-
/** Dynamic attested reads under a trustPolicy allowList. */
|
|
47
|
-
| "attestedReads"
|
|
48
|
-
/** Law-declared immutable pending-conflict snapshots (compare-and-set merge refs). */
|
|
49
|
-
| "conflictSnapshots"
|
|
50
|
-
/** `.owned()` automatic owner stamp, atomic per-record seat, and framework-custodied epoch-0 key. */
|
|
51
|
-
| "ownedAudience"
|
|
52
|
-
/** Captured-clock temporal enum projections declared by `t.timestamp().temporalEnum(...)`. */
|
|
53
|
-
| "temporalEnum";
|
|
6
|
+
export interface OsgiContractRequirement {
|
|
7
|
+
readonly namespace: "osgi.contract";
|
|
8
|
+
readonly name: string;
|
|
9
|
+
readonly version: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const NOMOS_KERNEL_CONTRACT = "nomos.kernel.v1";
|
|
13
|
+
export const NOMOS_KERNEL_CONTRACT_VERSION = "1.0.0";
|
|
54
14
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
15
|
+
const EXTENSION_CONTRACTS = {
|
|
16
|
+
compoundKeys: "nomos.kernel.extension.compoundKeys",
|
|
17
|
+
capturedReads: "nomos.kernel.extension.capturedReads",
|
|
18
|
+
invariantGate: "nomos.kernel.extension.invariantGate",
|
|
19
|
+
surfacedMerge: "nomos.kernel.extension.surfacedMerge",
|
|
20
|
+
fieldProvenance: "nomos.kernel.extension.fieldProvenance",
|
|
21
|
+
nullSemantics: "nomos.kernel.extension.nullSemantics",
|
|
22
|
+
attestedReads: "nomos.kernel.extension.attestedReads",
|
|
23
|
+
conflictSnapshots: "nomos.kernel.extension.conflictSnapshots",
|
|
24
|
+
ownedAudience: "nomos.kernel.extension.ownedAudience",
|
|
25
|
+
temporalEnum: "nomos.kernel.extension.temporalEnum",
|
|
26
|
+
} as const;
|
|
27
|
+
|
|
28
|
+
type KernelExtension = keyof typeof EXTENSION_CONTRACTS;
|
|
29
|
+
|
|
30
|
+
const ERA_KEY_TO_EXTENSION: Readonly<Record<string, KernelExtension>> = {
|
|
58
31
|
nomosReadGate: "capturedReads",
|
|
59
32
|
nomosInvariantGate: "invariantGate",
|
|
60
33
|
nomosSurfaced: "surfacedMerge",
|
|
@@ -63,216 +36,85 @@ export const ERA_KEY_TO_FEATURE: Readonly<Record<string, KernelFeature>> = {
|
|
|
63
36
|
nomosAttestedReads: "attestedReads",
|
|
64
37
|
};
|
|
65
38
|
|
|
66
|
-
|
|
67
|
-
export interface FeatureProbeModule {
|
|
39
|
+
export interface KernelContractProbeModule {
|
|
68
40
|
readonly queries?: readonly QueryDecl[];
|
|
69
41
|
readonly deriveds?: readonly unknown[];
|
|
70
42
|
readonly surfacedResolvers?: readonly unknown[];
|
|
71
43
|
readonly aggregates?: readonly { audience?: { kind?: string } }[];
|
|
72
|
-
/** The domain's USD-IR layer (the era keys ride here). Optional — shape-derived
|
|
73
|
-
* features (compoundKeys) work without it. */
|
|
74
44
|
readonly layer?: Record<string, unknown>;
|
|
75
45
|
}
|
|
76
46
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
47
|
+
const requirement = (name: string): OsgiContractRequirement => ({
|
|
48
|
+
namespace: "osgi.contract",
|
|
49
|
+
name,
|
|
50
|
+
version: NOMOS_KERNEL_CONTRACT_VERSION,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
/** Derive exact OSGi Contract Namespace requirements from the emitted law shape. */
|
|
54
|
+
export function requiredKernelContracts(
|
|
55
|
+
modules: readonly KernelContractProbeModule[],
|
|
56
|
+
): OsgiContractRequirement[] {
|
|
57
|
+
const extensions = new Set<KernelExtension>();
|
|
58
|
+
for (const module of modules) {
|
|
59
|
+
for (const query of module.queries ?? []) {
|
|
60
|
+
if (Array.isArray(query.key) && query.key.length > 1) extensions.add("compoundKeys");
|
|
88
61
|
}
|
|
89
|
-
if ((
|
|
62
|
+
if ((module.deriveds ?? []).some((derived) =>
|
|
90
63
|
typeof derived === "object" && derived !== null && "kind" in derived &&
|
|
91
64
|
derived.kind === "temporalEnum")) {
|
|
92
|
-
|
|
65
|
+
extensions.add("temporalEnum");
|
|
93
66
|
}
|
|
94
|
-
if ((
|
|
95
|
-
if ((
|
|
96
|
-
|
|
67
|
+
if ((module.surfacedResolvers?.length ?? 0) > 0) extensions.add("conflictSnapshots");
|
|
68
|
+
if ((module.aggregates ?? []).some((aggregate) => aggregate.audience?.kind === "owned")) {
|
|
69
|
+
extensions.add("ownedAudience");
|
|
97
70
|
}
|
|
98
|
-
if (
|
|
99
|
-
for (const [eraKey,
|
|
100
|
-
if (
|
|
71
|
+
if (module.layer) {
|
|
72
|
+
for (const [eraKey, extension] of Object.entries(ERA_KEY_TO_EXTENSION)) {
|
|
73
|
+
if (module.layer[eraKey] !== undefined) extensions.add(extension);
|
|
101
74
|
}
|
|
102
75
|
}
|
|
103
76
|
}
|
|
104
|
-
return [
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
* the shape the kernel stamps (see `kernelStamp` op in wasm_git_holon.rs) AND the shape
|
|
109
|
-
* the host `/v1/runtime/capabilities` endpoint synthesizes for the deployed wasm it can't
|
|
110
|
-
* yet ask (keyed by the wasm sha256 in the registry below). */
|
|
111
|
-
export interface KernelStamp {
|
|
112
|
-
/** The kernel semver-ish version tag baked into the wasm at build. */
|
|
113
|
-
readonly version: string;
|
|
114
|
-
/** The wasm artifact sha256 (64-hex), when known. */
|
|
115
|
-
readonly hash?: string;
|
|
116
|
-
/** The named capabilities this kernel implements. */
|
|
117
|
-
readonly features: readonly KernelFeature[];
|
|
118
|
-
/** Human note (e.g. "production", "test-mint (DEV ONLY)") — surfaced in the skew message. */
|
|
119
|
-
readonly note?: string;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/** THE KNOWN-KERNEL REGISTRY — maps a kernel wasm sha256 PREFIX to its capability stamp.
|
|
123
|
-
* Keyed by prefix so a short hash (the co2 report cites `846c6bf8` / `f81cb952`) resolves.
|
|
124
|
-
*
|
|
125
|
-
* WHY host-side and not only asked of the kernel: the CURRENTLY-DEPLOYED stale kernel
|
|
126
|
-
* predates the stamp op — it cannot answer "what are your capabilities?". Until every
|
|
127
|
-
* serving kernel carries the in-wasm stamp, this registry lets the host + client resolve
|
|
128
|
-
* a deployed wasm's capabilities from its BYTES, which is always available. A kernel that
|
|
129
|
-
* DOES carry the stamp op is preferred; this is the fallback that works today.
|
|
130
|
-
*
|
|
131
|
-
* Add an entry the moment a new kernel wasm is cut (its sha256 + the features it gained). */
|
|
132
|
-
export interface KernelRegistryEntry extends KernelStamp {
|
|
133
|
-
readonly prefix: string;
|
|
134
|
-
/** Human note (e.g. "production", "test-mint (DEV ONLY)"). */
|
|
135
|
-
readonly note?: string;
|
|
77
|
+
return [
|
|
78
|
+
requirement(NOMOS_KERNEL_CONTRACT),
|
|
79
|
+
...[...extensions].map((extension) => requirement(EXTENSION_CONTRACTS[extension])),
|
|
80
|
+
].sort((a, b) => a.name.localeCompare(b.name));
|
|
136
81
|
}
|
|
137
82
|
|
|
138
|
-
export
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
note: "current local production build",
|
|
143
|
-
features: [
|
|
144
|
-
"compoundKeys",
|
|
145
|
-
"capturedReads",
|
|
146
|
-
"invariantGate",
|
|
147
|
-
"surfacedMerge",
|
|
148
|
-
"fieldProvenance",
|
|
149
|
-
"nullSemantics",
|
|
150
|
-
"attestedReads",
|
|
151
|
-
],
|
|
152
|
-
},
|
|
153
|
-
{
|
|
154
|
-
prefix: "846c6bf8",
|
|
155
|
-
version: "kernel-846c6bf8",
|
|
156
|
-
note: "production (accepts compound-key law)",
|
|
157
|
-
features: [
|
|
158
|
-
"compoundKeys",
|
|
159
|
-
"capturedReads",
|
|
160
|
-
"invariantGate",
|
|
161
|
-
"surfacedMerge",
|
|
162
|
-
"fieldProvenance",
|
|
163
|
-
"nullSemantics",
|
|
164
|
-
"attestedReads",
|
|
165
|
-
],
|
|
166
|
-
},
|
|
167
|
-
{
|
|
168
|
-
// CURRENT test-mint kernel (rebuilt from the SAME source as prod 846c6bf8, 2026-07-14; staged to R2 +
|
|
169
|
-
// built/staged by deploy.sh every release). Feature-equivalent to production — the dev cloud is coherent.
|
|
170
|
-
prefix: "f6e44b3a",
|
|
171
|
-
version: "kernel-f6e44b3a",
|
|
172
|
-
note: "test-mint (DEV) — current, feature-equivalent to production",
|
|
173
|
-
features: [
|
|
174
|
-
"compoundKeys",
|
|
175
|
-
"capturedReads",
|
|
176
|
-
"invariantGate",
|
|
177
|
-
"surfacedMerge",
|
|
178
|
-
"fieldProvenance",
|
|
179
|
-
"nullSemantics",
|
|
180
|
-
"attestedReads",
|
|
181
|
-
],
|
|
182
|
-
},
|
|
183
|
-
{
|
|
184
|
-
prefix: "f81cb952",
|
|
185
|
-
version: "kernel-f81cb952",
|
|
186
|
-
note: "test-mint (DEV ONLY — STALE: predates compound-key read router; superseded by f6e44b3a)",
|
|
187
|
-
features: [
|
|
188
|
-
"capturedReads",
|
|
189
|
-
"invariantGate",
|
|
190
|
-
"surfacedMerge",
|
|
191
|
-
"fieldProvenance",
|
|
192
|
-
"nullSemantics",
|
|
193
|
-
"attestedReads",
|
|
194
|
-
],
|
|
195
|
-
},
|
|
196
|
-
];
|
|
197
|
-
|
|
198
|
-
/** Resolve a kernel wasm hash (full or short) to its known capability stamp, or `null`
|
|
199
|
-
* when the hash is unknown to the registry (a kernel we've never catalogued). */
|
|
200
|
-
export function capabilitiesForKernelHash(hash: string | undefined | null): KernelStamp | null {
|
|
201
|
-
if (typeof hash !== "string" || hash.length < 6) return null;
|
|
202
|
-
const h = hash.toLowerCase().replace(/^sha256:|^policy:/, "");
|
|
203
|
-
const hit = KERNEL_CAPABILITY_REGISTRY.find((e) => h.startsWith(e.prefix) || e.prefix.startsWith(h));
|
|
204
|
-
return hit
|
|
205
|
-
? { version: hit.version, hash: h, features: hit.features, ...(hit.note ? { note: hit.note } : {}) }
|
|
206
|
-
: null;
|
|
83
|
+
export interface OsgiContractCapability {
|
|
84
|
+
readonly namespace: "osgi.contract";
|
|
85
|
+
readonly name: string;
|
|
86
|
+
readonly versions: readonly string[];
|
|
207
87
|
}
|
|
208
88
|
|
|
209
|
-
|
|
210
|
-
export interface KernelCoherenceVerdict {
|
|
89
|
+
export interface KernelContractVerdict {
|
|
211
90
|
readonly ok: boolean;
|
|
212
|
-
|
|
213
|
-
readonly missing: KernelFeature[];
|
|
214
|
-
/** A human-legible one-line message — the thing surfaced INSTEAD of the deep fold refusal. */
|
|
91
|
+
readonly missing: readonly OsgiContractRequirement[];
|
|
215
92
|
readonly message: string;
|
|
216
93
|
}
|
|
217
94
|
|
|
218
|
-
/**
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
*
|
|
223
|
-
* The message names BOTH hashes and the offending capability — the co2 skew, legibly. */
|
|
224
|
-
export function assessKernelCoherence(params: {
|
|
225
|
-
requires: readonly KernelFeature[];
|
|
226
|
-
kernel: KernelStamp | null;
|
|
227
|
-
/** The target kernel's hash, for the message even when the stamp is unknown. */
|
|
228
|
-
kernelHash?: string;
|
|
229
|
-
/** The law's hash, for the message. */
|
|
95
|
+
/** Compare requirements and capabilities using OSGi Contract Namespace identity and versions. */
|
|
96
|
+
export function assessKernelContracts(params: {
|
|
97
|
+
requirements: readonly OsgiContractRequirement[];
|
|
98
|
+
capabilities: readonly OsgiContractCapability[];
|
|
230
99
|
lawHash?: string;
|
|
231
|
-
}):
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
message:
|
|
244
|
-
`cannot verify release coherence — this cloud's kernel ${kernH} is UNKNOWN to the ` +
|
|
245
|
-
`capability registry, so it cannot be confirmed to support [${requires.join(", ")}] that ` +
|
|
246
|
-
`law ${lawH} requires. Update the kernel registry or upgrade the cloud's kernel.`,
|
|
247
|
-
};
|
|
248
|
-
}
|
|
249
|
-
const missing = requires.filter((f) => !kernel.features.includes(f)) as KernelFeature[];
|
|
250
|
-
if (missing.length === 0) {
|
|
251
|
-
return { ok: true, missing: [], message: `kernel ${kernH} supports all capabilities law ${lawH} requires` };
|
|
252
|
-
}
|
|
253
|
-
return {
|
|
254
|
-
ok: false,
|
|
255
|
-
missing,
|
|
256
|
-
message:
|
|
257
|
-
`this cloud's kernel ${kernH} lacks capability '${missing.join("', '")}' that law ${lawH} requires — ` +
|
|
258
|
-
`the cloud is running a STALE kernel (${kernel.note ?? kernel.version}). ` +
|
|
259
|
-
(missing.includes("compoundKeys")
|
|
260
|
-
? `A compound-key query (\`.key(a, b, …)\`) will be refused deep in a law fold with ` +
|
|
261
|
-
`"query declares N index keys; the read router supports exactly one". `
|
|
262
|
-
: missing.includes("temporalEnum")
|
|
263
|
-
? `A temporal enum read will be refused while mounting law with ` +
|
|
264
|
-
`"unknown nomos:readKind temporalEnum". `
|
|
265
|
-
: ``) +
|
|
266
|
-
`Upgrade the cloud's kernel (or point at a cloud whose kernel is coherent with this release).`,
|
|
267
|
-
};
|
|
100
|
+
}): KernelContractVerdict {
|
|
101
|
+
const missing = params.requirements.filter((required) => !params.capabilities.some((offered) =>
|
|
102
|
+
offered.namespace === required.namespace && offered.name === required.name &&
|
|
103
|
+
offered.versions.includes(required.version)));
|
|
104
|
+
const law = params.lawHash ? params.lawHash.replace(/^sha256:|^policy:/, "").slice(0, 8) : "<unknown>";
|
|
105
|
+
return missing.length === 0
|
|
106
|
+
? { ok: true, missing: [], message: `OSGi kernel contracts satisfy law ${law}` }
|
|
107
|
+
: {
|
|
108
|
+
ok: false,
|
|
109
|
+
missing,
|
|
110
|
+
message: `kernel lacks OSGi contract ${missing.map((item) => `${item.name}=${item.version}`).join(", ")} required by law ${law}`,
|
|
111
|
+
};
|
|
268
112
|
}
|
|
269
113
|
|
|
270
|
-
/** A typed error thrown when a coherence assertion fails — carries the structured verdict so
|
|
271
|
-
* callers can render it or branch, instead of parsing a message. */
|
|
272
114
|
export class KernelCoherenceError extends Error {
|
|
273
|
-
readonly verdict:
|
|
274
|
-
readonly code = "kernel-
|
|
275
|
-
constructor(verdict:
|
|
115
|
+
readonly verdict: KernelContractVerdict;
|
|
116
|
+
readonly code = "kernel-contract-incompatible";
|
|
117
|
+
constructor(verdict: KernelContractVerdict) {
|
|
276
118
|
super(verdict.message);
|
|
277
119
|
this.name = "KernelCoherenceError";
|
|
278
120
|
this.verdict = verdict;
|