@githolon/dsl 0.104.1 → 0.105.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@githolon/dsl",
3
- "version": "0.104.1",
3
+ "version": "0.105.0",
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.",
@@ -0,0 +1,132 @@
1
+ // NOMOS — Nomos Sovereign: participants act · verify · remember LOCALLY; hosted
2
+ // remotes are replaceable custody/transport, not truth. ⇒ ONE Nomos GitHolon
3
+ // wasm32-wasip1 artifact {kernel · projection · embedded
4
+ // QuickJS engine} on V8 + WASI-shim, byte-identical everywhere. V8 = portability; the one
5
+ // wasm = determinism. No native, no wasmtime, no 2nd artifact, no domain-JS on bare V8.
6
+ // If a file isn't this / hosting this / authoring for this / proving this — it's gone.
7
+
8
+ /**
9
+ * build_provenance.ts — the compile states what it produced as an IN-TOTO ATTESTATION,
10
+ * not as prose a regex has to mine.
11
+ *
12
+ * ── Why ──────────────────────────────────────────────────────────────────────
13
+ * `<name>.summary.txt` is written for humans and then parsed by machines. The release
14
+ * test reaches into it with `RegExp(r'law \(domainHash\): ([0-9a-f]{64})')`; a preflight
15
+ * does the same. Reword the line and the regex silently yields null — a gate that fails
16
+ * OPEN. That is the same defect class the kernel removed this era: one fact, two
17
+ * representations, and the derived copy drifts. (Two model-policy files disagreeing cost
18
+ * a release build the day this was written.)
19
+ *
20
+ * ── The giant ────────────────────────────────────────────────────────────────
21
+ * A compile output is BUILD PROVENANCE: *this artifact, with this digest, was produced
22
+ * by this builder from these inputs*. That has a specified shape already —
23
+ * in-toto Statement v1 (`https://in-toto.io/Statement/v1`) carrying a SLSA Provenance v1
24
+ * predicate (`https://slsa.dev/provenance/v1`). Existing verifiers understand it; agents
25
+ * do not have to learn a Nomos dialect to read it; and it is the natural carrier for a
26
+ * signature later (wrap in DSSE, sign with the same device keys the ledger already uses).
27
+ *
28
+ * NOTE ON JSON: in-toto statements are JSON *by specification*. Emitting JSON because a
29
+ * standard mandates it is the opposite of inventing a bespoke format — the objection this
30
+ * file answers was never "JSON", it was "a dialect only we can read".
31
+ *
32
+ * The prose summary stays: humans should keep reading a summary. What changes is that
33
+ * machines stop parsing it — both are projections of the same in-memory facts, so they
34
+ * cannot disagree.
35
+ */
36
+
37
+ /** One artifact this compile produced, named by digest. */
38
+ export interface ProvenanceSubject {
39
+ readonly name: string;
40
+ readonly digest: { readonly sha256: string };
41
+ }
42
+
43
+ export interface BuildProvenanceInput {
44
+ /** Package name from the project config. */
45
+ readonly packageName: string;
46
+ /** `sha256(package bytes)` — the composed typed USDA closure identity. */
47
+ readonly domainHash: string;
48
+ /** The transports the domainHash addresses (law archive, package asset, …). */
49
+ readonly artifacts: readonly { readonly name: string; readonly sha256?: string }[];
50
+ /** Per-domain compiled surface, already computed for the summary. */
51
+ readonly domains: readonly {
52
+ readonly domain: string;
53
+ readonly identityHash?: string;
54
+ readonly aggregates: readonly string[];
55
+ readonly directives: readonly string[];
56
+ readonly queries: readonly string[];
57
+ readonly counts: readonly string[];
58
+ readonly sums: readonly string[];
59
+ }[];
60
+ /** Compiler identity, so a consumer can tell which toolchain produced this. */
61
+ readonly builder: { readonly id: string; readonly version: string };
62
+ /** Source law modules, by feature — the external parameters of the build. */
63
+ readonly sourceModules?: readonly string[];
64
+ }
65
+
66
+ /**
67
+ * Build the in-toto Statement. PURE — takes facts, returns the document, writes nothing,
68
+ * reads no clock. A timestamp would make two compiles of identical inputs produce
69
+ * different bytes, which would defeat the point: this document is itself reproducible,
70
+ * so it can be compared across machines exactly like the artifact it describes.
71
+ */
72
+ export function buildProvenanceStatement(input: BuildProvenanceInput): Record<string, unknown> {
73
+ const subject: ProvenanceSubject[] = [
74
+ // The law closure identity is THE subject: `sha256(package bytes) = domainHash`.
75
+ { name: `${input.packageName}.law`, digest: { sha256: input.domainHash } },
76
+ ...input.artifacts
77
+ .filter((a): a is { name: string; sha256: string } => typeof a.sha256 === "string")
78
+ .map((a) => ({ name: a.name, digest: { sha256: a.sha256 } })),
79
+ ];
80
+
81
+ return {
82
+ _type: "https://in-toto.io/Statement/v1",
83
+ subject,
84
+ predicateType: "https://slsa.dev/provenance/v1",
85
+ predicate: {
86
+ buildDefinition: {
87
+ buildType: "https://nomos.cafe/buildtypes/domain-package/v1",
88
+ externalParameters: {
89
+ packageName: input.packageName,
90
+ ...(input.sourceModules === undefined
91
+ ? {}
92
+ : { sourceModules: [...input.sourceModules].sort() }),
93
+ },
94
+ // What the compile RESOLVED — the surface each domain actually exposes. A
95
+ // consumer diffing two provenances sees the law's shape change without
96
+ // parsing USDA or prose.
97
+ resolvedDependencies: input.domains.map((d) => ({
98
+ uri: `nomos:domain/${d.domain}`,
99
+ ...(d.identityHash === undefined ? {} : { digest: { sha256: d.identityHash } }),
100
+ annotations: {
101
+ aggregates: [...d.aggregates].sort(),
102
+ directives: [...d.directives].sort(),
103
+ queries: [...d.queries].sort(),
104
+ counts: [...d.counts].sort(),
105
+ sums: [...d.sums].sort(),
106
+ },
107
+ })),
108
+ },
109
+ runDetails: {
110
+ builder: { id: input.builder.id, version: { githolon: input.builder.version } },
111
+ // No startedOn/finishedOn: see the note above on reproducibility.
112
+ metadata: { invocationId: input.domainHash },
113
+ },
114
+ },
115
+ };
116
+ }
117
+
118
+ /** Canonical bytes: sorted keys, 2-space indent, trailing newline. Byte-stable. */
119
+ export function renderProvenance(statement: Record<string, unknown>): string {
120
+ const sortKeys = (value: unknown): unknown => {
121
+ if (Array.isArray(value)) return value.map(sortKeys);
122
+ if (value !== null && typeof value === "object") {
123
+ return Object.fromEntries(
124
+ Object.keys(value as Record<string, unknown>)
125
+ .sort()
126
+ .map((k) => [k, sortKeys((value as Record<string, unknown>)[k])]),
127
+ );
128
+ }
129
+ return value;
130
+ };
131
+ return `${JSON.stringify(sortKeys(statement), null, 2)}\n`;
132
+ }
@@ -185,6 +185,7 @@ import {
185
185
  import { assertUsdaRelationshipIntegrity } from "./usda_relationship_integrity.js";
186
186
  import { assertPublicPackageImports } from "./package_source_imports.js";
187
187
  import { assertPackageFeatureTopology } from "./package_feature_topology.js";
188
+ import { buildProvenanceStatement, renderProvenance } from "./build_provenance.js";
188
189
  import { packageDependencyUsageFindings } from "./package_dependency_usage.js";
189
190
  import {
190
191
  PlanSourceSliceProgram,
@@ -1653,7 +1654,7 @@ const NOMOS_TYPES_DEP = "^0.8.5";
1653
1654
  // DomainNotInstalledForSession, engine.follow, pendingConflicts lanes) — the generated client
1654
1655
  // REQUIRES this surface. 0.48.1 fixes NomosSession.watchPendingConflicts delegation.
1655
1656
  const NOMOS_CLIENT_DEP = "^0.64.17";
1656
- const NOMOS_FLUTTER_DEP = "^0.63.25";
1657
+ const NOMOS_FLUTTER_DEP = "^0.63.26";
1657
1658
  // DRIFT TRIPWIRE: pubspec_pins.test.ts asserts these equal the CURRENT versions in dsl/dart/pubspec.yaml
1658
1659
  // and dsl/dart_types/pubspec.yaml — a Dart release without this bump fails the suite, so tenants never
1659
1660
  // land back in dependency_overrides (the exact co2 report this closes, third occurrence).
@@ -5214,6 +5215,35 @@ async function main(): Promise<void> {
5214
5215
  ].join("\n");
5215
5216
  writeFileSync(path.join(outDir, `${cfg.name}.summary.txt`), summaryTxt, "utf8");
5216
5217
 
5218
+ // THE MACHINE-READABLE TWIN. The prose above is for humans; everything that reads a
5219
+ // compile result programmatically should read this instead of mining the summary with
5220
+ // a regex (a gate that fails OPEN the moment the wording changes). Both are projections
5221
+ // of the SAME in-memory facts, so they cannot disagree. In-toto Statement v1 + SLSA
5222
+ // Provenance v1 — a specified shape with existing verifiers, not a Nomos dialect.
5223
+ const provenance = buildProvenanceStatement({
5224
+ packageName: cfg.name,
5225
+ domainHash,
5226
+ artifacts: [
5227
+ { name: path.basename(lawUsdzPath) },
5228
+ ...(packageAssetPath === undefined ? [] : [{ name: path.basename(packageAssetPath) }]),
5229
+ ],
5230
+ domains: summary.domains.map((d) => ({
5231
+ domain: d.domain,
5232
+ ...(d.identityHash === undefined ? {} : { identityHash: d.identityHash }),
5233
+ aggregates: d.aggregates,
5234
+ directives: d.directives,
5235
+ queries: d.queries,
5236
+ counts: d.counts,
5237
+ sums: d.sums,
5238
+ })),
5239
+ builder: { id: "https://github.com/Captain-App/nomos2", version: dslVersion },
5240
+ });
5241
+ writeFileSync(
5242
+ path.join(outDir, `${cfg.name}.provenance.json`),
5243
+ renderProvenance(provenance),
5244
+ "utf8",
5245
+ );
5246
+
5217
5247
  // ── 5. the typed TS client (#10 — the web sibling of codegen_dart), with the
5218
5248
  // deployed law's content hash baked in (emitted AFTER the package is hashed) ──
5219
5249
  const clientPath = path.join(outDir, `${cfg.name}.client.mjs`);