@githolon/dsl 0.107.0 → 0.107.1
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 +6329 -5902
- package/dart/lib/src/runner/offline-install.mjs +393 -149
- package/dart/lib/src/webview_bridge.dart +662 -502
- package/dart/pubspec.yaml +1 -1
- package/dart/test/webview_bridge_test.dart +39 -2
- package/package.json +1 -1
- package/runtime/generated-application-host.js +6329 -5902
- package/src/compile_package_main.ts +2 -2
- package/src/framework/capability.ts +9 -3
- package/src/framework/domain_lifecycle.ts +8 -60
- package/src/framework/governance_relations.ts +10 -0
- package/src/framework/workspaces.ts +2 -1
- package/src/role.ts +13 -7
|
@@ -1664,8 +1664,8 @@ 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.46";
|
|
1668
|
+
const NOMOS_FLUTTER_DEP = "^0.63.75";
|
|
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).
|
|
@@ -300,9 +300,15 @@ export function capability<
|
|
|
300
300
|
// The loop is dynamic (declared field names), so the per-field `set()` typing
|
|
301
301
|
// is asserted — the PUBLIC payload types stay fully inferred from the zod shape.
|
|
302
302
|
writeParams: (taskId, p) =>
|
|
303
|
-
Object.keys(spec.request)
|
|
304
|
-
|
|
305
|
-
|
|
303
|
+
Object.keys(spec.request)
|
|
304
|
+
// ABSENT OPTIONALS ARE SKIPPED, symmetrically with the receipt half below: an optional
|
|
305
|
+
// request field the caller omitted must author NO op — `undefined` can never be ledger
|
|
306
|
+
// state, and writing it deterministically halts the author plan (caught live 2026-08-19:
|
|
307
|
+
// the first tempo-less oblige after the tempo law refused on `estimatedMs`).
|
|
308
|
+
.filter((k) => (p as Record<string, unknown>)[k] !== undefined)
|
|
309
|
+
.map((k) =>
|
|
310
|
+
set(instance(taskAggregate, taskId), k as never, (p as Record<string, unknown>)[k] as never),
|
|
311
|
+
),
|
|
306
312
|
// The receipt half, symmetrical with the request half above: declared fields are merged
|
|
307
313
|
// onto the complete envelope as TYPED values and written straight through. The payload
|
|
308
314
|
// boundary has already validated them against the same zod the author declared, so the
|
|
@@ -137,7 +137,7 @@ export const DomainInstallation = aggregate("DomainInstallation", {
|
|
|
137
137
|
}).public();
|
|
138
138
|
|
|
139
139
|
/**
|
|
140
|
-
* The accepted
|
|
140
|
+
* The accepted current-frontier evidence for one activation. This is deliberately an
|
|
141
141
|
* obscure framework concept: tenant models never author or name it. The generated
|
|
142
142
|
* lifecycle client runs pre-flight and folds this receipt in the SAME intent that
|
|
143
143
|
* activates the candidate, so recording evidence cannot make its own head anchor stale.
|
|
@@ -151,18 +151,7 @@ export const ReleaseReceipt = aggregate(RELEASE_RECEIPT_AGGREGATE, {
|
|
|
151
151
|
domain: t.string().merge(Lww),
|
|
152
152
|
atHash: t.gitObjectId().merge(Lww),
|
|
153
153
|
atStateRoot: t.gitObjectId().merge(Lww),
|
|
154
|
-
historyHash: t.sha256Digest().merge(Lww),
|
|
155
|
-
reportHash: t.sha256Digest().merge(Lww),
|
|
156
|
-
reportJson: t.string().merge(Lww),
|
|
157
|
-
complete: t.bool(),
|
|
158
154
|
evolveOk: t.bool(),
|
|
159
|
-
rawPromotable: t.bool(),
|
|
160
|
-
projectionEqual: t.bool(),
|
|
161
|
-
replayedIntents: t.int().merge(Lww),
|
|
162
|
-
candidateIntents: t.int().merge(Lww),
|
|
163
|
-
divergenceCount: t.int().merge(Lww),
|
|
164
|
-
baselineRoot: t.sha256Digest().merge(Lww),
|
|
165
|
-
candidateRoot: t.sha256Digest().merge(Lww),
|
|
166
155
|
acceptanceReason: t.string().merge(Lww).optional(),
|
|
167
156
|
acceptedBy: attributionField(t.string().merge(Lww)),
|
|
168
157
|
acceptedAt: t.int().merge(Lww),
|
|
@@ -176,12 +165,12 @@ function domainInstallationInstance(domainHash: Sha256Digest) {
|
|
|
176
165
|
return instance(DomainInstallation, domainInstallationAggregateId(domainHash));
|
|
177
166
|
}
|
|
178
167
|
|
|
179
|
-
export function releaseReceiptAggregateId(
|
|
180
|
-
return `${RELEASE_RECEIPT_PREFIX}${
|
|
168
|
+
export function releaseReceiptAggregateId(candidateHash: Sha256Digest, atStateRoot: string): string {
|
|
169
|
+
return `${RELEASE_RECEIPT_PREFIX}${candidateHash}:${atStateRoot}`;
|
|
181
170
|
}
|
|
182
171
|
|
|
183
|
-
function releaseReceiptInstance(
|
|
184
|
-
return instance(ReleaseReceipt, releaseReceiptAggregateId(
|
|
172
|
+
function releaseReceiptInstance(candidateHash: Sha256Digest, atStateRoot: string) {
|
|
173
|
+
return instance(ReleaseReceipt, releaseReceiptAggregateId(candidateHash, atStateRoot));
|
|
185
174
|
}
|
|
186
175
|
|
|
187
176
|
const dispositions = z.object({
|
|
@@ -198,28 +187,9 @@ const preflightReceipt = z.object({
|
|
|
198
187
|
domain: z.string().min(1),
|
|
199
188
|
atHash: gitOid,
|
|
200
189
|
atStateRoot: gitOid,
|
|
201
|
-
historyHash: lowerHex64,
|
|
202
|
-
reportHash: lowerHex64,
|
|
203
|
-
reportJson: z.string().min(2),
|
|
204
|
-
complete: z.literal(true),
|
|
205
190
|
evolveOk: z.literal(true),
|
|
206
|
-
rawPromotable: z.boolean(),
|
|
207
|
-
projectionEqual: z.boolean(),
|
|
208
|
-
replayedIntents: z.number().int().nonnegative(),
|
|
209
|
-
candidateIntents: z.number().int().nonnegative(),
|
|
210
|
-
divergenceCount: z.number().int().nonnegative(),
|
|
211
|
-
baselineRoot: lowerHex64,
|
|
212
|
-
candidateRoot: lowerHex64,
|
|
213
191
|
acceptanceReason: z.string().trim().min(1).optional(),
|
|
214
|
-
}).
|
|
215
|
-
if (!receipt.rawPromotable && receipt.acceptanceReason === undefined) {
|
|
216
|
-
ctx.addIssue({
|
|
217
|
-
code: z.ZodIssueCode.custom,
|
|
218
|
-
path: ["acceptanceReason"],
|
|
219
|
-
message: "a divergent but complete report needs an explicit business acceptance reason",
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
});
|
|
192
|
+
}).strict();
|
|
223
193
|
|
|
224
194
|
const installPackagePayload = {
|
|
225
195
|
domainHash: lowerHex64,
|
|
@@ -317,7 +287,7 @@ export const promoteDomain = directive(DOMAIN_LIFECYCLE_DIRECTIVES.Promote)
|
|
|
317
287
|
}))
|
|
318
288
|
.plan((p, ctx): PlannedOp[] => {
|
|
319
289
|
const promoted = domainInstallationInstance(p.domainHash);
|
|
320
|
-
const receipt = releaseReceiptInstance(p.preflight.
|
|
290
|
+
const receipt = releaseReceiptInstance(p.domainHash, p.preflight.atStateRoot);
|
|
321
291
|
const ops: PlannedOp[] = [
|
|
322
292
|
set(promoted, "status.phase", DomainInstallationPhase.Active),
|
|
323
293
|
set(promoted, "status.observedGeneration", 1),
|
|
@@ -326,18 +296,7 @@ export const promoteDomain = directive(DOMAIN_LIFECYCLE_DIRECTIVES.Promote)
|
|
|
326
296
|
set(receipt, "domain", p.preflight.domain),
|
|
327
297
|
set(receipt, "atHash", p.preflight.atHash),
|
|
328
298
|
set(receipt, "atStateRoot", p.preflight.atStateRoot),
|
|
329
|
-
set(receipt, "historyHash", p.preflight.historyHash),
|
|
330
|
-
set(receipt, "reportHash", p.preflight.reportHash),
|
|
331
|
-
set(receipt, "reportJson", p.preflight.reportJson),
|
|
332
|
-
set(receipt, "complete", true),
|
|
333
299
|
set(receipt, "evolveOk", true),
|
|
334
|
-
set(receipt, "rawPromotable", p.preflight.rawPromotable),
|
|
335
|
-
set(receipt, "projectionEqual", p.preflight.projectionEqual),
|
|
336
|
-
set(receipt, "replayedIntents", p.preflight.replayedIntents),
|
|
337
|
-
set(receipt, "candidateIntents", p.preflight.candidateIntents),
|
|
338
|
-
set(receipt, "divergenceCount", p.preflight.divergenceCount),
|
|
339
|
-
set(receipt, "baselineRoot", p.preflight.baselineRoot),
|
|
340
|
-
set(receipt, "candidateRoot", p.preflight.candidateRoot),
|
|
341
300
|
...(p.preflight.acceptanceReason !== undefined
|
|
342
301
|
? [set(receipt, "acceptanceReason", p.preflight.acceptanceReason)]
|
|
343
302
|
: []),
|
|
@@ -380,7 +339,7 @@ export const rollbackDomain = directive(DOMAIN_LIFECYCLE_DIRECTIVES.Rollback)
|
|
|
380
339
|
.plan((p, ctx): PlannedOp[] => {
|
|
381
340
|
const candidate = domainInstallationInstance(p.candidateHash);
|
|
382
341
|
const prior = domainInstallationInstance(p.priorHash);
|
|
383
|
-
const receipt = releaseReceiptInstance(p.preflight.
|
|
342
|
+
const receipt = releaseReceiptInstance(p.priorHash, p.preflight.atStateRoot);
|
|
384
343
|
return [
|
|
385
344
|
set(candidate, "status.phase", DomainInstallationPhase.Disabled),
|
|
386
345
|
set(candidate, "status.supersededBy", p.priorHash),
|
|
@@ -391,18 +350,7 @@ export const rollbackDomain = directive(DOMAIN_LIFECYCLE_DIRECTIVES.Rollback)
|
|
|
391
350
|
set(receipt, "domain", p.preflight.domain),
|
|
392
351
|
set(receipt, "atHash", p.preflight.atHash),
|
|
393
352
|
set(receipt, "atStateRoot", p.preflight.atStateRoot),
|
|
394
|
-
set(receipt, "historyHash", p.preflight.historyHash),
|
|
395
|
-
set(receipt, "reportHash", p.preflight.reportHash),
|
|
396
|
-
set(receipt, "reportJson", p.preflight.reportJson),
|
|
397
|
-
set(receipt, "complete", true),
|
|
398
353
|
set(receipt, "evolveOk", true),
|
|
399
|
-
set(receipt, "rawPromotable", p.preflight.rawPromotable),
|
|
400
|
-
set(receipt, "projectionEqual", p.preflight.projectionEqual),
|
|
401
|
-
set(receipt, "replayedIntents", p.preflight.replayedIntents),
|
|
402
|
-
set(receipt, "candidateIntents", p.preflight.candidateIntents),
|
|
403
|
-
set(receipt, "divergenceCount", p.preflight.divergenceCount),
|
|
404
|
-
set(receipt, "baselineRoot", p.preflight.baselineRoot),
|
|
405
|
-
set(receipt, "candidateRoot", p.preflight.candidateRoot),
|
|
406
354
|
...(p.preflight.acceptanceReason !== undefined
|
|
407
355
|
? [set(receipt, "acceptanceReason", p.preflight.acceptanceReason)]
|
|
408
356
|
: []),
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// NOMOS — canonical framework governance relation identities.
|
|
2
|
+
//
|
|
3
|
+
// These names are global, kernel-coupled vocabulary. Coin them once so DSL
|
|
4
|
+
// sugar cannot accidentally redeclare them as tenant-local relations and cause
|
|
5
|
+
// the compiler to namespace gates away from the framework's founding tuples.
|
|
6
|
+
import { relationRef } from "../relation_schema.js";
|
|
7
|
+
|
|
8
|
+
/** The global workspace authority seated at `workspace:self#admin`. */
|
|
9
|
+
export const WORKSPACE_ADMIN_RELATION = relationRef("admin");
|
|
10
|
+
|
|
@@ -77,6 +77,7 @@ import { read } from "../read.js";
|
|
|
77
77
|
import { readRef, readSet, workspaceInvariant, refAs, type WorkspaceInvariantVerdict } from "./workspace_invariant.js";
|
|
78
78
|
import { writeTuple, removeTuple, RelationTuple, relationTupleInstanceId } from "./relations.js";
|
|
79
79
|
import { relationType, self, user, key } from "../relation_schema.js";
|
|
80
|
+
import { WORKSPACE_ADMIN_RELATION } from "./governance_relations.js";
|
|
80
81
|
import { GENESIS_WARRANT_ID } from "./genesis.js";
|
|
81
82
|
import { idOf } from "../value_object.js";
|
|
82
83
|
import { enrollSigner, signerObject, SIGNER_RELATION } from "./signing_identity.js";
|
|
@@ -191,7 +192,7 @@ export const workspaceRelations = relationType("workspace")
|
|
|
191
192
|
// migration. (A TENANT that wants a workspace-scoped role uses a namespaced `relationType("workspace")`
|
|
192
193
|
// + a `selfWorkspace()` seed; only THIS framework governance type is global.)
|
|
193
194
|
.asGlobal()
|
|
194
|
-
.relation(
|
|
195
|
+
.relation(WORKSPACE_ADMIN_RELATION, { rewrite: self(), allow: [user(), key()] })
|
|
195
196
|
.relation("creator", { rewrite: self(), allow: [user(), key()] })
|
|
196
197
|
.relation("platformCreator", { rewrite: self(), allow: [user(), key()] });
|
|
197
198
|
|
package/src/role.ts
CHANGED
|
@@ -14,8 +14,9 @@
|
|
|
14
14
|
* `relationType("workspace")` block (the fail-open footgun is CLOSED — a `.requires(role.edit)`
|
|
15
15
|
* always finds a declared relation), and the `<role>View` relation is a READ-VISIBILITY cap
|
|
16
16
|
* (used as an aggregate `requires(role.view)` — usd.ts synthesizes the global workspace read
|
|
17
|
-
* relation, exactly as any private aggregate does).
|
|
18
|
-
* default `admin`
|
|
17
|
+
* relation, exactly as any private aggregate does). A custom grant-authority relation is likewise
|
|
18
|
+
* authored locally. The default `admin` instead refers to the framework's existing GLOBAL
|
|
19
|
+
* `workspace:self#admin`; redeclaring it locally would namespace the gate away from its founding tuple.
|
|
19
20
|
*
|
|
20
21
|
* 2. GRANT / SEED DIRECTIVES per role — `grant<Role>` / `revoke<Role>` fold the relation TUPLE via
|
|
21
22
|
* the existing `writeTuple`/`removeTuple` primitives (a grant seats `<role>Edit` + `<role>View`
|
|
@@ -41,6 +42,7 @@ import type { AggregateHandle } from "./aggregate.js";
|
|
|
41
42
|
import type { Directive, RequirableDirective } from "./directive.js";
|
|
42
43
|
import { directive } from "./directive.js";
|
|
43
44
|
import { RelationTuple, writeTuple, removeTuple } from "./framework/relations.js";
|
|
45
|
+
import { WORKSPACE_ADMIN_RELATION } from "./framework/governance_relations.js";
|
|
44
46
|
import { relationType, self, user, key, type RelationTypeDecl } from "./relation_schema.js";
|
|
45
47
|
|
|
46
48
|
/** A role name: kebab-case (`editor`, `site-admin`) — lowered to relation/directive labels. */
|
|
@@ -234,7 +236,7 @@ export function role(name: string): RoleBuilder {
|
|
|
234
236
|
name,
|
|
235
237
|
editRelation: `${base}Edit`,
|
|
236
238
|
viewRelation: `${base}View`,
|
|
237
|
-
grantableBy:
|
|
239
|
+
grantableBy: WORKSPACE_ADMIN_RELATION,
|
|
238
240
|
editAggregates: [],
|
|
239
241
|
viewAggregates: [],
|
|
240
242
|
canEdit: false,
|
|
@@ -256,8 +258,10 @@ const ROLE_RELATIONS_KEY = "__nomosRoleRelations";
|
|
|
256
258
|
* EXPANDER (the `capability()`/birth-meter seam): given a module's exports bag, LIFT every `RoleEmission`
|
|
257
259
|
* into discoverable entries — the grant/revoke/seed directives become top-level exports (so `directivesOf`
|
|
258
260
|
* finds them), and ONE synthesized `relationType("workspace")` (the `<role>Edit` write relations + the
|
|
259
|
-
* distinct `grantableBy` grant-authority relations, deduped) becomes a discoverable relation type
|
|
260
|
-
* `.requires(role.edit)` / `.requires(
|
|
261
|
+
* distinct LOCAL `grantableBy` grant-authority relations, deduped) becomes a discoverable relation type
|
|
262
|
+
* (so `.requires(role.edit)` / `.requires(customGrantAuthority)` have TEETH — the fail-open footgun is
|
|
263
|
+
* closed). The default framework `admin` authority is already declared by the global governance schema
|
|
264
|
+
* and MUST NOT be redeclared here as tenant-local. The
|
|
261
265
|
* `<role>View` read relations are NOT authored here: they are read-visibility caps, synthesized by usd.ts
|
|
262
266
|
* from the aggregates that declare `requires(role.view)`. IDEMPOTENT + additive: a bag with no role is
|
|
263
267
|
* returned unchanged (byte-identical), and re-running on an already-expanded bag is a no-op.
|
|
@@ -281,12 +285,14 @@ export function expandRoleExports(mod: Record<string, unknown>): Record<string,
|
|
|
281
285
|
};
|
|
282
286
|
for (const e of emissions) {
|
|
283
287
|
if (e.meta.editRelation) declare(e.meta.editRelation);
|
|
284
|
-
declare(e.meta.grantableBy);
|
|
288
|
+
if (e.meta.grantableBy !== WORKSPACE_ADMIN_RELATION) declare(e.meta.grantableBy);
|
|
285
289
|
for (const dir of e.directives) {
|
|
286
290
|
const anyDir = dir as { id: string };
|
|
287
291
|
out[`__role_${anyDir.id}`] = dir;
|
|
288
292
|
}
|
|
289
293
|
}
|
|
290
|
-
|
|
294
|
+
// Keep the marker even for a view-only role using global admin so expansion stays idempotent without
|
|
295
|
+
// publishing an empty relation schema declaration.
|
|
296
|
+
out[ROLE_RELATIONS_KEY] = declared.size > 0 ? builder as unknown as RelationTypeDecl : true;
|
|
291
297
|
return out;
|
|
292
298
|
}
|