@githolon/dsl 0.1.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.
Files changed (53) hide show
  1. package/LICENSE.md +36 -0
  2. package/compile_package.mjs +50 -0
  3. package/package.json +59 -0
  4. package/src/aggregate.ts +167 -0
  5. package/src/authoring.ts +119 -0
  6. package/src/build_package.ts +636 -0
  7. package/src/certified_read.ts +313 -0
  8. package/src/codegen_dart.ts +2732 -0
  9. package/src/codegen_dot.ts +466 -0
  10. package/src/codegen_provider_dart.ts +358 -0
  11. package/src/codegen_ts.ts +365 -0
  12. package/src/codegen_usda.ts +388 -0
  13. package/src/combined.ts +195 -0
  14. package/src/compile_engine.ts +567 -0
  15. package/src/compile_package_main.ts +496 -0
  16. package/src/compose.ts +317 -0
  17. package/src/count.ts +218 -0
  18. package/src/ctx.ts +57 -0
  19. package/src/derived.ts +138 -0
  20. package/src/directive.ts +306 -0
  21. package/src/drivers.ts +95 -0
  22. package/src/emits_guard.ts +123 -0
  23. package/src/engine_entry.ts +449 -0
  24. package/src/exists.ts +170 -0
  25. package/src/extremum.ts +227 -0
  26. package/src/fields.ts +291 -0
  27. package/src/framework/bootstrap.ts +22 -0
  28. package/src/framework/disclosure.ts +108 -0
  29. package/src/framework/domain_lifecycle.ts +108 -0
  30. package/src/framework/identity.ts +537 -0
  31. package/src/framework/impure_capability.ts +643 -0
  32. package/src/framework/rbac.ts +418 -0
  33. package/src/framework/repair.ts +150 -0
  34. package/src/framework/sync_lifecycle.ts +125 -0
  35. package/src/framework/workspace_invariant.ts +128 -0
  36. package/src/framework/workspaces.ts +817 -0
  37. package/src/index.ts +317 -0
  38. package/src/manifest.ts +947 -0
  39. package/src/ops.ts +145 -0
  40. package/src/ordered_read.ts +228 -0
  41. package/src/predicate.ts +203 -0
  42. package/src/query/compile.ts +0 -0
  43. package/src/query/relations.ts +144 -0
  44. package/src/query.ts +151 -0
  45. package/src/read.ts +54 -0
  46. package/src/relation.ts +189 -0
  47. package/src/report/csv.ts +54 -0
  48. package/src/report.ts +401 -0
  49. package/src/spatial.ts +115 -0
  50. package/src/sum.ts +194 -0
  51. package/src/usd.ts +563 -0
  52. package/src/wire.ts +149 -0
  53. package/src/wire_encode.ts +250 -0
package/src/sum.ts ADDED
@@ -0,0 +1,194 @@
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
+ * `sum(id, field)` builder — the NUMERIC AGGREGATION sibling of `count`.
10
+ *
11
+ * A `sum` declares a NAMED, MAINTAINED running total of an `int`-kind field across
12
+ * every aggregate of the `of`-type (optionally filtered by a `.where(pred)` predicate
13
+ * and partitioned by a `.by(field)` group-by). The result is ONE number per group,
14
+ * maintained incrementally as the workspace folds — NEVER a `SUM(*)` scan (the same
15
+ * O(1) perf invariant as `count`).
16
+ *
17
+ * The TYPE-STATE mirrors `count.ts` exactly:
18
+ * `sum(id, field)` → `TypelessSum` (only `.of` available)
19
+ * `.of(agg)` → `Sum` builder (`.where`, `.by` available; grand-total usable)
20
+ * `.where(p)` → `Sum` with predicate baked in (`.by` still available)
21
+ * `.by(k)` → `SumDecl` (finished, grouped declaration)
22
+ *
23
+ * Both a bare `Sum` (grand-total) and a grouped `SumDecl` satisfy `AnySum` — what
24
+ * `DomainModule.sums` accepts. `finishSum` normalizes either to a `SumDecl`.
25
+ *
26
+ * VALIDATION RULE (manifest-load, not type-level): the `sumField` parameter MUST be
27
+ * an `int`-kind field of the `of`-aggregate. The DSL type system cannot enforce this
28
+ * at the `sum(id, sumField)` call site (the aggregate is not yet known), but
29
+ * `AggregateSchemas::parse` (readmodel/src/manifest.rs) performs a no-fallback reject
30
+ * if the field is absent or non-int on the declared aggregate.
31
+ *
32
+ * ORDER-SENSITIVE GUARDRAIL: sum exposes NO `.first`/`.take`/`.orderBy`. Same
33
+ * rationale as `count.ts`. Assert the absence; do NOT add dead methods (LAW 3).
34
+ *
35
+ * SUM-OF-0 AMBIGUITY (documented, acceptable for Slice 1): a group whose running
36
+ * total reaches 0 is pruned from the `sums` table and reads as 0 — indistinguishable
37
+ * from an absent group. A future `exists` primitive (Slice 2) handles the distinction.
38
+ */
39
+ import type { AggregateHandle } from "./aggregate.js";
40
+ import type { Field } from "./fields.js";
41
+ import { type Predicate, type CanonicalPred, predBuilder, canonicalizePred } from "./predicate.js";
42
+
43
+ /**
44
+ * A FINISHED sum declaration (the read-engine's input shape, analogous to
45
+ * {@link CountDecl}): an id, the aggregate TYPE it tallies, the FIELD being summed,
46
+ * the OPTIONAL predicate, and the OPTIONAL group-by field.
47
+ */
48
+ export interface SumDecl {
49
+ readonly id: string;
50
+ /** The aggregate TYPE id the sum tallies, e.g. `ListingAggregate`. */
51
+ readonly of: string;
52
+ /**
53
+ * The `int`-kind field being summed, e.g. `"quantity"` or `"itemValue"`. MUST
54
+ * be an `int`-kind field of the `of`-aggregate (validated at manifest-load).
55
+ */
56
+ readonly sumField: string;
57
+ /**
58
+ * The optional predicate: ONLY aggregates satisfying this predicate contribute
59
+ * to the sum. ABSENT ⇒ every aggregate of the `of`-type is summed.
60
+ */
61
+ readonly where?: CanonicalPred;
62
+ /**
63
+ * The group-by field name. ABSENT ⇒ a grand total across all (matching)
64
+ * aggregates of the `of`-type (one synthetic group).
65
+ */
66
+ readonly by?: string;
67
+ }
68
+
69
+ /**
70
+ * The `Sum` BUILDER: it has named its `of`-type (and summed field), so `.where(...)`
71
+ * and `.by(...)` are available. The `F` type parameter carries the `of`-aggregate's
72
+ * field map so `.where(p => p.field("status").eq("active"))` is keyof-checked.
73
+ */
74
+ export interface Sum<F extends Record<string, Field> = Record<string, Field>> {
75
+ readonly id: string;
76
+ /** The aggregate TYPE id the sum tallies. */
77
+ readonly of: string;
78
+ /** The `int`-kind field being summed. */
79
+ readonly sumField: string;
80
+ /**
81
+ * Attach an optional PREDICATE: only aggregates satisfying the predicate contribute
82
+ * to the sum. Returns a new `Sum` with the predicate baked in; `.by(...)` is still
83
+ * available.
84
+ */
85
+ where(fn: (p: ReturnType<typeof predBuilder<F>>) => Predicate<F>): Sum<F>;
86
+ /**
87
+ * Partition the sum by a GROUP-BY field. Every distinct value of `groupField`
88
+ * maintains its own running total. Returns a finished `SumDecl`.
89
+ */
90
+ by(groupField: string): SumDecl;
91
+ }
92
+
93
+ /**
94
+ * The INITIAL, un-typed sum — its ONLY method is `.of(...)`. A `sum(id, field)`
95
+ * without `.of(...)` cannot be used as a declaration: the aggregate type is not
96
+ * optional.
97
+ */
98
+ export interface TypelessSum {
99
+ readonly id: string;
100
+ /** The `int`-kind field to sum. */
101
+ readonly sumField: string;
102
+ /**
103
+ * Declare the aggregate TYPE whose `sumField` values are summed. Takes a typed
104
+ * HANDLE (never a string id). Returns the `Sum` builder (the only shape exposing
105
+ * `.where` and `.by`), which is already a usable grand-total sum.
106
+ */
107
+ of<F extends Record<string, Field>>(aggregate: AggregateHandle<string, F>): Sum<F>;
108
+ }
109
+
110
+ /**
111
+ * Either form a domain may declare in `DomainModule.sums`. `Sum<any>` for the same
112
+ * reason as `AnyCount = CountDecl | Count<any>`: `Sum<F>` is invariant in `F`
113
+ * (the `where` method), so `Sum<SpecificFields>` is not assignable to
114
+ * `Sum<Record<string,Field>>`. The consumer only accesses `id`/`of`/`sumField`/`by`
115
+ * string fields and the `_where` slot — it never calls `.where(fn)` — so `any` is safe.
116
+ */
117
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
118
+ export type AnySum = SumDecl | Sum<any>;
119
+
120
+ /** Narrow: a `Sum` builder exposes a `by` METHOD; a `SumDecl` does not. */
121
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
122
+ function isSumBuilder(s: AnySum): s is Sum<any> {
123
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
124
+ return typeof (s as Sum<any>).by === "function";
125
+ }
126
+
127
+ /**
128
+ * Normalize an `AnySum` to a finished `SumDecl`. The grand-total builder (bare
129
+ * `.of(...)`) becomes `{id, of, sumField}` (no `by`); a grouped `.by(...)` result is
130
+ * already a `SumDecl` and passes through. A `.where(pred)` result transfers the
131
+ * canonical predicate.
132
+ */
133
+ export function finishSum(s: AnySum): SumDecl {
134
+ if (isSumBuilder(s)) {
135
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
136
+ const b = s as any;
137
+ const w: CanonicalPred | undefined = b._where;
138
+ return {
139
+ id: b.id,
140
+ of: b.of,
141
+ sumField: b.sumField,
142
+ ...(w !== undefined ? { where: w } : {}),
143
+ };
144
+ }
145
+ return s;
146
+ }
147
+
148
+ /** Internal factory so `.where(...)` can return a new Sum without duplicating impl. */
149
+ function makeSum<F extends Record<string, Field>>(
150
+ id: string,
151
+ ofType: string,
152
+ sumField: string,
153
+ where: CanonicalPred | undefined,
154
+ ): Sum<F> {
155
+ // Same exactOptionalPropertyTypes pattern as makeCount: spread `_where` only when
156
+ // defined so the key is absent (not `undefined`) in the predicate-free case.
157
+ const s = {
158
+ id,
159
+ of: ofType,
160
+ sumField,
161
+ ...(where !== undefined ? { _where: where } : {}),
162
+ where(fn: (p: ReturnType<typeof predBuilder<F>>) => Predicate<F>): Sum<F> {
163
+ const pred = fn(predBuilder<F>());
164
+ const canonical = canonicalizePred(pred as Predicate<Record<string, Field>>);
165
+ return makeSum<F>(id, ofType, sumField, canonical);
166
+ },
167
+ by(groupField: string): SumDecl {
168
+ return {
169
+ id,
170
+ of: ofType,
171
+ sumField,
172
+ ...(where !== undefined ? { where } : {}),
173
+ by: groupField,
174
+ };
175
+ },
176
+ } as unknown as Sum<F>;
177
+ return s;
178
+ }
179
+
180
+ /**
181
+ * Begin a sum declaration. `id` is the sum's canonical name (e.g.
182
+ * `"totalItemValuePerSite"`); `sumField` is the `int`-kind field on the `of`-aggregate
183
+ * whose values are accumulated. Returns a `TypelessSum`: until `.of(aggregate)` is
184
+ * called, the aggregate type is unknown and no usable declaration exists.
185
+ */
186
+ export function sum(id: string, sumField: string): TypelessSum {
187
+ return {
188
+ id,
189
+ sumField,
190
+ of<F extends Record<string, Field>>(aggregate: AggregateHandle<string, F>): Sum<F> {
191
+ return makeSum<F>(id, aggregate.id, sumField, undefined);
192
+ },
193
+ };
194
+ }