@githolon/dsl 0.108.2 → 0.108.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dart/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 0.65.2
2
+
3
+ - Preserve complete typed birth lineage and recover existing workspaces through the authenticated
4
+ installed-controller lifecycle without falling back to dynamic host-authored payloads.
5
+
1
6
  ## 0.65.1
2
7
 
3
8
  - Publish the generated nominal application call and query surfaces required by current DSL output, so
@@ -14666,8 +14666,24 @@ function firstDeviceDelegationPayload(route, certificate, typedPayload) {
14666
14666
  if (declared.has("delegationCertificate")) {
14667
14667
  return { delegationCertificate: typedPayload };
14668
14668
  }
14669
- throw new Error(
14670
- `Nomos application route '${route.domain}${route.path}' does not declare the typed 'delegationCertificate' contract [nomos.application.contract_missing]`
14669
+ throw new NomosClientError(
14670
+ `Nomos application route '${route.domain}${route.path}' does not declare the typed 'delegationCertificate' contract`,
14671
+ {
14672
+ code: "nomos.application.contract_missing",
14673
+ operation: "enrollFirstDevice",
14674
+ recommendedAction: NomosRecommendedAction.redeployLaw,
14675
+ info: {
14676
+ code: "nomos.application.contract_missing",
14677
+ message: `Nomos application route '${route.domain}${route.path}' does not declare the typed 'delegationCertificate' contract`,
14678
+ component: "nomos.application",
14679
+ domain: route.domain,
14680
+ operation: "enrollFirstDevice",
14681
+ attributes: {
14682
+ "nomos.application.missing_contract": "delegationCertificate",
14683
+ "nomos.recovery.action": "repeat-parent-authorized-birth"
14684
+ }
14685
+ }
14686
+ }
14671
14687
  );
14672
14688
  }
14673
14689
  var GIT_OBJECT_ID = /^[0-9a-f]{40}$/;
@@ -4390,6 +4390,8 @@ __export(engine_exports, {
4390
4390
  author: () => author,
4391
4391
  authorEphemeral: () => authorEphemeral,
4392
4392
  authorKeygen: () => authorKeygen,
4393
+ authorModelLifecyclePromotion: () => authorModelLifecyclePromotion,
4394
+ authorModelLifecycleStage: () => authorModelLifecycleStage,
4393
4395
  authorOn: () => authorOn,
4394
4396
  authorOperatorCall: () => authorOperatorCall,
4395
4397
  backupHead: () => backupHead,
@@ -10898,6 +10900,7 @@ var AuthoringOptionsSchema = /* @__PURE__ */ messageDesc(file_nomos_kernel_v1_ke
10898
10900
  var CapturedClockSchema = /* @__PURE__ */ messageDesc(file_nomos_kernel_v1_kernel, 49);
10899
10901
  var BirthCertificateSchema = /* @__PURE__ */ messageDesc(file_nomos_kernel_v1_kernel, 50);
10900
10902
  var SignBirthCertificateRequestSchema = /* @__PURE__ */ messageDesc(file_nomos_kernel_v1_kernel, 51);
10903
+ var ModelLifecycleIntentSchema = /* @__PURE__ */ messageDesc(file_nomos_kernel_v1_kernel, 53);
10901
10904
  var OfferRequestSchema = /* @__PURE__ */ messageDesc(file_nomos_kernel_v1_kernel, 54);
10902
10905
  var QueryRequestSchema = /* @__PURE__ */ messageDesc(file_nomos_kernel_v1_kernel, 57);
10903
10906
  var QueryAuthoritySchema = /* @__PURE__ */ messageDesc(file_nomos_kernel_v1_kernel, 64);
@@ -10912,6 +10915,10 @@ var PendingConflictsQuerySchema = /* @__PURE__ */ messageDesc(file_nomos_kernel_
10912
10915
  var PendingConflictSummaryQuerySchema = /* @__PURE__ */ messageDesc(file_nomos_kernel_v1_kernel, 77);
10913
10916
  var NamedQuerySchema = /* @__PURE__ */ messageDesc(file_nomos_kernel_v1_kernel, 78);
10914
10917
  var FrontierTransitionRequestSchema = /* @__PURE__ */ messageDesc(file_nomos_kernel_v1_kernel, 79);
10918
+ var FrontierTransitionDispositionMapEntrySchema = /* @__PURE__ */ messageDesc(file_nomos_kernel_v1_kernel, 80);
10919
+ var FrontierTransitionDispositionsSchema = /* @__PURE__ */ messageDesc(file_nomos_kernel_v1_kernel, 81);
10920
+ var FrontierTransitionViolationSchema = /* @__PURE__ */ messageDesc(file_nomos_kernel_v1_kernel, 82);
10921
+ var FrontierTransitionResponseSchema = /* @__PURE__ */ messageDesc(file_nomos_kernel_v1_kernel, 83);
10915
10922
  var AuthorizationObjectSchema = /* @__PURE__ */ messageDesc(file_nomos_kernel_v1_kernel, 84);
10916
10923
  var AuthorizationSubjectSchema = /* @__PURE__ */ messageDesc(file_nomos_kernel_v1_kernel, 85);
10917
10924
  var AuthorizationConsistencySchema = /* @__PURE__ */ messageDesc(file_nomos_kernel_v1_kernel, 87);
@@ -10950,6 +10957,8 @@ var NomosValueSchema = /* @__PURE__ */ messageDesc(file_nomos_kernel_v1_kernel,
10950
10957
  var NomosStructSchema = /* @__PURE__ */ messageDesc(file_nomos_kernel_v1_kernel, 166);
10951
10958
  var BirthOutcomeStatusSchema = /* @__PURE__ */ enumDesc(file_nomos_kernel_v1_kernel, 0);
10952
10959
  var BirthOutcomeStatus = /* @__PURE__ */ tsEnum(BirthOutcomeStatusSchema);
10960
+ var ModelLifecycleOperationSchema = /* @__PURE__ */ enumDesc(file_nomos_kernel_v1_kernel, 3);
10961
+ var ModelLifecycleOperation = /* @__PURE__ */ tsEnum(ModelLifecycleOperationSchema);
10953
10962
  var QueryResultFormatSchema = /* @__PURE__ */ enumDesc(file_nomos_kernel_v1_kernel, 5);
10954
10963
  var QueryResultFormat = /* @__PURE__ */ tsEnum(QueryResultFormatSchema);
10955
10964
  var QueryOperationSchema = /* @__PURE__ */ enumDesc(file_nomos_kernel_v1_kernel, 6);
@@ -11586,6 +11595,100 @@ var closureInstallPayload = (hash, installedBy, options = {}) => ({
11586
11595
  function authorOperatorCall(eng2, ws, call, controllerHash, opts = {}) {
11587
11596
  return author(eng2, ws, call.domain, call.directive, call.canonicalUsda, controllerHash, opts);
11588
11597
  }
11598
+ function authorModelLifecycleStage(eng2, ws, lawUsdz, installedBy, supersedes, opts = {}) {
11599
+ const sequence = eng2.seq++;
11600
+ const captured = {
11601
+ physical: Date.now(),
11602
+ logical: 0,
11603
+ replica: eng2.replica
11604
+ };
11605
+ const response = offerRequestResponse(eng2, create(OfferRequestSchema, {
11606
+ target: protoTarget(ws),
11607
+ intent: {
11608
+ case: "modelLifecycle",
11609
+ value: create(ModelLifecycleIntentSchema, {
11610
+ operation: ModelLifecycleOperation.STAGE,
11611
+ installedBy,
11612
+ supersedes
11613
+ })
11614
+ },
11615
+ authoring: create(AuthoringOptionsSchema, {
11616
+ actor: opts.actor ?? "",
11617
+ authToken: opts.authToken ? enc3.encode(opts.authToken) : new Uint8Array(),
11618
+ authorSecret: opts.authorSecret ? bytesFromB64(opts.authorSecret) : new Uint8Array(),
11619
+ validFromEpoch: opts.validFromEpoch === void 0 ? void 0 : BigInt(opts.validFromEpoch),
11620
+ rng: osEntropyBuffer(opts.rngDraws ?? 64),
11621
+ deferProjection: opts.deferProjection !== false,
11622
+ spans: opts.spans ?? false,
11623
+ sequence: BigInt(sequence),
11624
+ clock: create(CapturedClockSchema, {
11625
+ physicalMillis: BigInt(captured.physical),
11626
+ logical: captured.logical,
11627
+ replica: BigInt(captured.replica)
11628
+ })
11629
+ }),
11630
+ lawUsdz
11631
+ }));
11632
+ return offerResult(response);
11633
+ }
11634
+ function authorModelLifecyclePromotion(eng2, ws, transition, replaces, acceptanceReason, opts = {}) {
11635
+ const sequence = eng2.seq++;
11636
+ const captured = {
11637
+ physical: Date.now(),
11638
+ logical: 0,
11639
+ replica: eng2.replica
11640
+ };
11641
+ const dispositions = transition.dispositions === void 0 ? void 0 : create(FrontierTransitionDispositionsSchema, {
11642
+ retired: [...transition.dispositions.retired],
11643
+ retyped: Object.entries(transition.dispositions.retyped).map(
11644
+ ([sourceStableId, acknowledgement]) => create(FrontierTransitionDispositionMapEntrySchema, { sourceStableId, acknowledgement })
11645
+ ),
11646
+ rebinds: Object.entries(transition.dispositions.rebinds).map(
11647
+ ([sourceStableId, acknowledgement]) => create(FrontierTransitionDispositionMapEntrySchema, { sourceStableId, acknowledgement })
11648
+ ),
11649
+ acknowledgedBy: transition.dispositions.ackBy
11650
+ });
11651
+ const response = offerRequestResponse(eng2, create(OfferRequestSchema, {
11652
+ target: protoTarget(ws),
11653
+ intent: {
11654
+ case: "modelLifecycle",
11655
+ value: create(ModelLifecycleIntentSchema, {
11656
+ operation: ModelLifecycleOperation.PROMOTE,
11657
+ replaces,
11658
+ acceptanceReason,
11659
+ transition: create(FrontierTransitionResponseSchema, {
11660
+ atHash: transition.atHash,
11661
+ currentHash: transition.currentHash,
11662
+ atStateRoot: transition.atStateRoot ?? "",
11663
+ candidateHash: transition.candidateHash,
11664
+ domain: transition.domain,
11665
+ domains: [...transition.domains ?? []],
11666
+ ready: transition.ready,
11667
+ violations: transition.evolve.violations.map(
11668
+ ({ domain, detail }) => create(FrontierTransitionViolationSchema, { domain, detail })
11669
+ ),
11670
+ dispositions
11671
+ })
11672
+ })
11673
+ },
11674
+ authoring: create(AuthoringOptionsSchema, {
11675
+ actor: opts.actor ?? "",
11676
+ authToken: opts.authToken ? enc3.encode(opts.authToken) : new Uint8Array(),
11677
+ authorSecret: opts.authorSecret ? bytesFromB64(opts.authorSecret) : new Uint8Array(),
11678
+ validFromEpoch: opts.validFromEpoch === void 0 ? void 0 : BigInt(opts.validFromEpoch),
11679
+ rng: osEntropyBuffer(opts.rngDraws ?? 64),
11680
+ deferProjection: opts.deferProjection !== false,
11681
+ spans: opts.spans ?? false,
11682
+ sequence: BigInt(sequence),
11683
+ clock: create(CapturedClockSchema, {
11684
+ physicalMillis: BigInt(captured.physical),
11685
+ logical: captured.logical,
11686
+ replica: BigInt(captured.replica)
11687
+ })
11688
+ })
11689
+ }));
11690
+ return offerResult(response);
11691
+ }
11589
11692
  function initializeWorkspace(eng2, ws, installedBy = eng2.installedBy) {
11590
11693
  const sequence = eng2.seq++;
11591
11694
  const captured = {
@@ -14457,11 +14560,12 @@ function promotePreflighted(eng2, ws, domain, candidateHash, opts = {}) {
14457
14560
  acceptanceReason: _acceptance,
14458
14561
  ...authorOpts
14459
14562
  } = opts;
14460
- const result = authorOperatorCall(
14563
+ const result = authorModelLifecyclePromotion(
14461
14564
  eng2,
14462
14565
  ws,
14463
- promoteDomainCall(ws, prepared.payload),
14464
- requireCurrentControllerLawHash(eng2, ws),
14566
+ report,
14567
+ prepared.payload.replaces,
14568
+ prepared.payload.preflight.acceptanceReason,
14465
14569
  {
14466
14570
  ...authorOpts,
14467
14571
  ...actingPrincipal ? { actor: actingPrincipal } : {}
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.65.1
10
+ version: 0.65.2
11
11
 
12
12
  environment:
13
13
  sdk: ^3.5.0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@githolon/dsl",
3
- "version": "0.108.2",
3
+ "version": "0.108.4",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "Nomos 2 domain-authoring DSL: aggregates + directives in TS, executed and encoded to the Rust kernel's wire shapes.",
@@ -13088,8 +13088,24 @@ function firstDeviceDelegationPayload(route, certificate, typedPayload) {
13088
13088
  if (declared.has("delegationCertificate")) {
13089
13089
  return { delegationCertificate: typedPayload };
13090
13090
  }
13091
- throw new Error(
13092
- `Nomos application route '${route.domain}${route.path}' does not declare the typed 'delegationCertificate' contract [nomos.application.contract_missing]`
13091
+ throw new NomosClientError(
13092
+ `Nomos application route '${route.domain}${route.path}' does not declare the typed 'delegationCertificate' contract`,
13093
+ {
13094
+ code: "nomos.application.contract_missing",
13095
+ operation: "enrollFirstDevice",
13096
+ recommendedAction: NomosRecommendedAction.redeployLaw,
13097
+ info: {
13098
+ code: "nomos.application.contract_missing",
13099
+ message: `Nomos application route '${route.domain}${route.path}' does not declare the typed 'delegationCertificate' contract`,
13100
+ component: "nomos.application",
13101
+ domain: route.domain,
13102
+ operation: "enrollFirstDevice",
13103
+ attributes: {
13104
+ "nomos.application.missing_contract": "delegationCertificate",
13105
+ "nomos.recovery.action": "repeat-parent-authorized-birth"
13106
+ }
13107
+ }
13108
+ }
13093
13109
  );
13094
13110
  }
13095
13111
  var GIT_OBJECT_ID = /^[0-9a-f]{40}$/;
@@ -22497,7 +22513,9 @@ async function nomosInternalOpenGeneratedApplication(options, bind, internals =
22497
22513
  try {
22498
22514
  await measureOpen("confirm private-custody signer enrolment", enroll);
22499
22515
  } catch (error) {
22500
- if (!String(error).includes("receiving-group-additional-device-requires-current-device-or-guardian")) throw error;
22516
+ const errorCode = typeof error === "object" && error !== null && "code" in error ? String(error.code ?? "") : "";
22517
+ const parentAuthorizedMigrationRequired = errorCode === "nomos.application.contract_missing" || String(error).includes("receiving-group-additional-device-requires-current-device-or-guardian");
22518
+ if (!parentAuthorizedMigrationRequired) throw error;
22501
22519
  await birthOrRepeat();
22502
22520
  await measureOpen("verify recovered private-custody signer enrolment", enroll);
22503
22521
  }
package/src/codegen_ts.ts CHANGED
@@ -1127,6 +1127,9 @@ export interface TsClientOptions {
1127
1127
  /** Emit the structural holon factory for the compiler-owned headless artifact. The ordinary tenant
1128
1128
  * client leaves this false so framework transport types never enter its public declaration graph. */
1129
1129
  readonly exportHolonFactory?: boolean;
1130
+ /** Emit only the fixed framework operator call set (identity, lifecycle and birth). This is the
1131
+ * small server/operator companion: exact generated USDA calls, no application/read runtime. */
1132
+ readonly frameworkOperatorOnly?: boolean;
1130
1133
  /** Exact law identities and paths from the same in-memory USDA render which produced the shipped
1131
1134
  * closure. This is compiler input for generated call encoders, never a checked-in sidecar. */
1132
1135
  readonly callUsda?: readonly {
@@ -2136,6 +2139,158 @@ export function generateTsClient(
2136
2139
  }
2137
2140
  }
2138
2141
  }
2142
+ if (opts.frameworkOperatorOnly === true) {
2143
+ const fixedGroups = new Set(["identity", "governance", "lifecycle", "birth"]);
2144
+ const operatorDefinitions = frameworkCallMethodDefinitions.filter(
2145
+ (definition) => fixedGroups.has(definition.group)
2146
+ );
2147
+ const operatorEncoders = frameworkCallEncoders.filter((entry) =>
2148
+ fixedGroups.has(entry.group)
2149
+ );
2150
+ const capabilityReceiptByKey = new Map<string, {
2151
+ readonly domain: string;
2152
+ readonly directiveId: string;
2153
+ readonly payloadType: string;
2154
+ readonly encoder: ReturnType<typeof emitTsCallUsdaEncoder>;
2155
+ }>();
2156
+ const capabilityReferenceTypes = new Set<string>();
2157
+ for (const mod of modules) {
2158
+ const domain = mod.domain ?? mod.name;
2159
+ const law = callUsdaByDomain.get(domain);
2160
+ if (law === undefined) continue;
2161
+ const authored = authoredDirectivesByDomain.get(domain) ?? [];
2162
+ for (const capability of mod.impureCapabilities ?? []) {
2163
+ for (const receipt of [
2164
+ capability.complete,
2165
+ capability.fail,
2166
+ capability.block,
2167
+ capability.deadLetter,
2168
+ ]) {
2169
+ const directive = authored.find((candidate) => candidate.id === receipt.id);
2170
+ if (directive === undefined) {
2171
+ throw new Error(
2172
+ `TypeScript capability receipt codegen: '${domain}/${receipt.id}' has no authored directive`,
2173
+ );
2174
+ }
2175
+ const payloadType = tsTypeOfPayload(
2176
+ directive.payloadSchema as z.ZodTypeAny,
2177
+ [],
2178
+ );
2179
+ for (const referenceType of payloadReferenceTypes(
2180
+ directive.payloadSchema as z.ZodTypeAny,
2181
+ )) {
2182
+ capabilityReferenceTypes.add(referenceType);
2183
+ }
2184
+ capabilityReceiptByKey.set(`${domain}\u0000${receipt.id}`, {
2185
+ domain,
2186
+ directiveId: receipt.id,
2187
+ payloadType,
2188
+ encoder: emitTsCallUsdaEncoder(
2189
+ law.graph,
2190
+ law.paths,
2191
+ domain,
2192
+ receipt.id,
2193
+ payloadType,
2194
+ ),
2195
+ });
2196
+ }
2197
+ }
2198
+ }
2199
+ const capabilityReceipts = [...capabilityReceiptByKey.values()].sort((left, right) =>
2200
+ left.domain.localeCompare(right.domain) || left.directiveId.localeCompare(right.directiveId)
2201
+ );
2202
+ return [
2203
+ `// AUTO-GENERATED by nomos-compile — exact framework operators for package "${opts.packageName}".`,
2204
+ `// No application runtime and no authority live here. Do not edit.`,
2205
+ ``,
2206
+ ...TS_CALL_USDA_PRELUDE,
2207
+ `/** A SHA-256 digest in canonical Nomos wire form. */`,
2208
+ `export type Sha256Digest = string & { readonly __nomosSha256Digest: unique symbol };`,
2209
+ `/** A Git object address in canonical gix custody form. */`,
2210
+ `export type GitObjectId = string & { readonly __nomosGitObjectId: unique symbol };`,
2211
+ `/** Exact compiler-authored framework call. Bytes are internal transport, while callers retain the nominal method and payload type. */`,
2212
+ `export interface NomosFrameworkCall<Domain extends string = string, Directive extends string = string> {`,
2213
+ ` readonly domain: Domain;`,
2214
+ ` readonly directive: Directive;`,
2215
+ ` readonly canonicalUsda: Uint8Array;`,
2216
+ ` readonly routingCandidates: readonly string[];`,
2217
+ `}`,
2218
+ `declare const _nomosAggregateType: unique symbol;`,
2219
+ ...[...capabilityReferenceTypes].sort().map(
2220
+ (id) => `export type ${id} = { readonly [_nomosAggregateType]?: ${JSON.stringify(id)} };`,
2221
+ ),
2222
+ `export interface NomosRef<TAggregate> {`,
2223
+ ` readonly [_nomosAggregateType]: (aggregate: TAggregate) => TAggregate;`,
2224
+ ` readonly workspace: string;`,
2225
+ ` readonly type: string;`,
2226
+ ` readonly id: string;`,
2227
+ ` readonly address: string;`,
2228
+ `}`,
2229
+ `/** Construct a typed address after the operator has independently established that the referenced task exists. A reference is not authority. */`,
2230
+ `export const nomosRef = <TAggregate>(workspace: string, type: string, id: string): NomosRef<TAggregate> => ({`,
2231
+ ` workspace, type, id,`,
2232
+ ` address: "nomos://" + encodeURIComponent(workspace) + "/" + encodeURIComponent(type) + "/" + encodeURIComponent(id),`,
2233
+ `} as unknown as NomosRef<TAggregate>);`,
2234
+ `const _nmsReferenceTypeMatches = (actual: string, expected: string): boolean =>`,
2235
+ ` expected === "" || actual === expected || actual.endsWith("." + expected);`,
2236
+ `const _nmsReferenceId = (value: unknown, expectedType: string, workspace: string, field: string): string => {`,
2237
+ ` if (typeof value !== "object" || value === null) throw new TypeError(field + " must be a NomosRef");`,
2238
+ ` const ref = value as { workspace?: unknown; type?: unknown; id?: unknown };`,
2239
+ ` if (typeof ref.id !== "string" || ref.id.length === 0 || typeof ref.type !== "string" || ref.type.length === 0 || typeof ref.workspace !== "string" || ref.workspace.length === 0) throw new TypeError(field + " must carry a complete NomosRef { workspace, type, id }");`,
2240
+ ` if (!_nmsReferenceTypeMatches(ref.type, expectedType)) throw new TypeError(field + " refers to " + ref.type + "; expected " + expectedType);`,
2241
+ ` if (workspace !== "" && ref.workspace !== workspace) throw new TypeError(field + " belongs to workspace " + ref.workspace + "; this call is bound to " + workspace);`,
2242
+ ` return ref.id;`,
2243
+ `};`,
2244
+ ...operatorEncoders.flatMap((entry) => entry.encoder.source),
2245
+ ...capabilityReceipts.flatMap((entry) => entry.encoder.source),
2246
+ `export const nomosFrameworkCalls = {`,
2247
+ ...[...new Set(operatorDefinitions.map((entry) => entry.group))].flatMap(
2248
+ (group) => [
2249
+ ` ${group}: {`,
2250
+ ...operatorDefinitions
2251
+ .filter((entry) => entry.group === group)
2252
+ .flatMap((definition) => {
2253
+ const alternatives = operatorEncoders.filter(
2254
+ (entry) => entry.group === group && entry.kind === definition.kind
2255
+ );
2256
+ const domainType = alternatives
2257
+ .map((entry) => JSON.stringify(entry.domain))
2258
+ .join(" | ") || "never";
2259
+ return [
2260
+ ` ${definition.kind}(input: { readonly domain: ${domainType}; readonly workspace: string } & ${definition.payloadType}): NomosFrameworkCall<${domainType}, ${JSON.stringify(definition.directiveId)}> {`,
2261
+ ` const { domain, workspace, ...payload } = input;`,
2262
+ ` switch (domain) {`,
2263
+ ...alternatives
2264
+ .map(
2265
+ (entry) =>
2266
+ ` case ${JSON.stringify(entry.domain)}: return ${entry.encoder.functionName}(payload, workspace);`
2267
+ ),
2268
+ ` default: throw new Error("The compiled application has no '${definition.kind}' call in domain '" + domain + "'.");`,
2269
+ ` }`,
2270
+ ` },`,
2271
+ ];
2272
+ }),
2273
+ ` },`,
2274
+ ]
2275
+ ),
2276
+ `} as const;`,
2277
+ `export const nomosCapabilityReceipts = {`,
2278
+ ...[...new Set(capabilityReceipts.map((entry) => entry.domain))].flatMap((domain) => [
2279
+ ` ${tsKey(domain)}: {`,
2280
+ ...capabilityReceipts
2281
+ .filter((entry) => entry.domain === domain)
2282
+ .flatMap((entry) => [
2283
+ ` ${tsKey(entry.directiveId)}(input: { readonly workspace: string } & ${entry.payloadType}): NomosFrameworkCall<${JSON.stringify(domain)}, ${JSON.stringify(entry.directiveId)}> {`,
2284
+ ` const { workspace, ...payload } = input;`,
2285
+ ` return ${entry.encoder.functionName}(payload, workspace);`,
2286
+ ` },`,
2287
+ ]),
2288
+ ` },`,
2289
+ ]),
2290
+ `} as const;`,
2291
+ ``,
2292
+ ].join("\n");
2293
+ }
2139
2294
  out.push(
2140
2295
  `// AUTO-GENERATED by nomos-compile — typed TS application implementation for package "${opts.packageName}".`,
2141
2296
  `// Regenerated on every compile; do not edit. Framework binding types below are deliberately private:`,
@@ -5646,6 +5646,9 @@ async function main(): Promise<void> {
5646
5646
  const headlessClientDeclarationPath = path.join(outDir, `${cfg.name}.headless.d.mts`);
5647
5647
  const operatorPath = path.join(outDir, `${cfg.name}.operator.mjs`);
5648
5648
  const operatorDeclarationPath = path.join(outDir, `${cfg.name}.operator.d.mts`);
5649
+ const frameworkOperatorPath = path.join(outDir, `${cfg.name}.framework.mjs`);
5650
+ const frameworkOperatorDeclarationPath = path.join(outDir, `${cfg.name}.framework.d.mts`);
5651
+ const frameworkOperatorSourcePath = path.join(outDir, `${cfg.name}.framework.ts`);
5649
5652
  const clientOptions = {
5650
5653
  packageName: cfg.name,
5651
5654
  domainHash,
@@ -5665,6 +5668,10 @@ async function main(): Promise<void> {
5665
5668
  exportHolonFactory: true,
5666
5669
  });
5667
5670
  const operatorSource = generateTsLifecycleOperator(clientOptions.callUsda);
5671
+ const frameworkOperatorSource = generateTsClient(presentationDomainModules, {
5672
+ ...clientOptions,
5673
+ frameworkOperatorOnly: true,
5674
+ });
5668
5675
  const runtimePath = path.join(DSL_DIR, "runtime", "generated-application-host.js");
5669
5676
  if (!existsSync(runtimePath)) {
5670
5677
  fail("the compiler-private generated application runtime is missing — reinstall @githolon/dsl");
@@ -6050,6 +6057,43 @@ async function main(): Promise<void> {
6050
6057
  rmSync(operatorPath, { force: true });
6051
6058
  rmSync(operatorDeclarationPath, { force: true });
6052
6059
  }
6060
+ const frameworkOperatorDeclaration = ts.transpileDeclaration(frameworkOperatorSource, {
6061
+ fileName: `${cfg.name}.framework.ts`,
6062
+ compilerOptions: {
6063
+ target: ts.ScriptTarget.ES2022,
6064
+ module: ts.ModuleKind.ESNext,
6065
+ strict: true,
6066
+ },
6067
+ reportDiagnostics: true,
6068
+ });
6069
+ const frameworkOperatorErrors = (frameworkOperatorDeclaration.diagnostics ?? []).filter(
6070
+ (diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error,
6071
+ );
6072
+ if (frameworkOperatorErrors.length > 0) {
6073
+ fail(`generated TypeScript framework operator declarations are invalid — this is a Nomos codegen bug:\n${frameworkOperatorErrors.map((diagnostic) => ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n")).join("\n")}`);
6074
+ }
6075
+ writeFileSync(frameworkOperatorDeclarationPath, frameworkOperatorDeclaration.outputText, "utf8");
6076
+ writeFileSync(frameworkOperatorSourcePath, frameworkOperatorSource, "utf8");
6077
+ await esbuildMod.build({
6078
+ stdin: {
6079
+ contents: frameworkOperatorSource,
6080
+ loader: "ts",
6081
+ resolveDir: outDir,
6082
+ sourcefile: `${cfg.name}.framework.ts`,
6083
+ },
6084
+ outfile: frameworkOperatorPath,
6085
+ bundle: true,
6086
+ platform: "neutral",
6087
+ format: "esm",
6088
+ target: "es2022",
6089
+ legalComments: "none",
6090
+ logLevel: "silent",
6091
+ });
6092
+ writeFileSync(
6093
+ frameworkOperatorPath,
6094
+ canonicalizeGeneratedClientJavascript(readFileSync(frameworkOperatorPath, "utf8")),
6095
+ "utf8",
6096
+ );
6053
6097
  } catch (e) {
6054
6098
  fail(`generated TypeScript application could not be sealed — this is a Nomos codegen bug: ${(e as Error).message}`);
6055
6099
  } finally {
@@ -199,8 +199,20 @@ function readCurrentAuthProviderRows() {
199
199
  try {
200
200
  return readFrameworkDeclaredRows(authProvider, AuthProvider, { scope: "platform" });
201
201
  } catch (error) {
202
- if (error instanceof z.ZodError && error.issues.some((issue) =>
203
- issue.code === "unrecognized_keys" && issue.keys.includes("keys")
202
+ // Law plans execute in the deterministic VM, not in the compiler's Node
203
+ // realm. Imported class identity therefore cannot be used as an
204
+ // `instanceof` discriminator here: the compiler may carry the property
205
+ // path without carrying a constructible host class. Zod's issue list is
206
+ // already the nominal failure disclosure we need; inspect that bounded
207
+ // shape without depending on host-realm prototype identity.
208
+ const issues = error !== null && typeof error === "object" &&
209
+ "issues" in error && Array.isArray(error.issues)
210
+ ? error.issues
211
+ : [];
212
+ if (issues.some((issue: unknown) =>
213
+ issue !== null && typeof issue === "object" &&
214
+ "code" in issue && issue.code === "unrecognized_keys" &&
215
+ "keys" in issue && Array.isArray(issue.keys) && issue.keys.includes("keys")
204
216
  )) {
205
217
  throw new Error(
206
218
  "the AuthProvider still uses the historical serialized key field; migrate it to a typed keySet first",
@@ -18,9 +18,10 @@ import {
18
18
  seedReceivingGroupPolicy,
19
19
  } from "./framework/home.js";
20
20
  import { enrollDelegation, enrollFirstDevice, enrollSigner } from "./framework/signing_identity.js";
21
+ import { grantAdmin } from "./framework/workspaces.js";
21
22
 
22
23
  export interface FixedFrameworkCallDefinition {
23
- readonly group: "identity" | "lifecycle" | "birth";
24
+ readonly group: "identity" | "governance" | "lifecycle" | "birth";
24
25
  readonly kind: string;
25
26
  readonly directive: Directive<any>;
26
27
  /** Needed by the pre-bind Dart birth ceremony before an application exists. */
@@ -40,6 +41,7 @@ export const fixedFrameworkCallDefinitions: readonly FixedFrameworkCallDefinitio
40
41
  { group: "identity", kind: "enrollSigner", directive: enrollSigner, dartBirth: true, requiredApplicationHome: true },
41
42
  { group: "identity", kind: "setAuthProvider", directive: setAuthProvider, requiredApplicationHome: true },
42
43
  { group: "identity", kind: "birthReceivingGroup", directive: receivingGroupBirth, dartBirth: true, requiredApplicationHome: true },
44
+ { group: "governance", kind: "grantAdmin", directive: grantAdmin },
43
45
  { group: "lifecycle", kind: "installDomain", directive: installDomain },
44
46
  { group: "lifecycle", kind: "stageDomain", directive: stageDomain },
45
47
  { group: "lifecycle", kind: "promoteDomain", directive: promoteDomain },