aontu 0.52.0 → 0.53.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 (273) hide show
  1. package/README.md +88 -0
  2. package/bin/aontu-mcp.js +4 -0
  3. package/dist/agentsmd.d.ts +16 -0
  4. package/dist/agentsmd.js +107 -0
  5. package/dist/agentsmd.js.map +1 -0
  6. package/dist/aontu.d.ts +14 -3
  7. package/dist/aontu.js +145 -4
  8. package/dist/aontu.js.map +1 -1
  9. package/dist/cli.d.ts +44 -1
  10. package/dist/cli.js +2401 -44
  11. package/dist/cli.js.map +1 -1
  12. package/dist/ctx.d.ts +16 -0
  13. package/dist/ctx.js +44 -0
  14. package/dist/ctx.js.map +1 -1
  15. package/dist/diff.d.ts +22 -0
  16. package/dist/diff.js +141 -0
  17. package/dist/diff.js.map +1 -0
  18. package/dist/err.d.ts +3 -1
  19. package/dist/err.js +48 -8
  20. package/dist/err.js.map +1 -1
  21. package/dist/graph.d.ts +16 -0
  22. package/dist/graph.js +73 -0
  23. package/dist/graph.js.map +1 -0
  24. package/dist/hcanon.d.ts +3 -0
  25. package/dist/hcanon.js +146 -0
  26. package/dist/hcanon.js.map +1 -0
  27. package/dist/hints.js +223 -5
  28. package/dist/hints.js.map +1 -1
  29. package/dist/jsonschema.d.ts +20 -0
  30. package/dist/jsonschema.js +391 -0
  31. package/dist/jsonschema.js.map +1 -0
  32. package/dist/lang.js +698 -35
  33. package/dist/lang.js.map +1 -1
  34. package/dist/lsp.d.ts +9 -2
  35. package/dist/lsp.js +262 -46
  36. package/dist/lsp.js.map +1 -1
  37. package/dist/mcp-server.d.ts +20 -0
  38. package/dist/mcp-server.js +147 -0
  39. package/dist/mcp-server.js.map +1 -0
  40. package/dist/mcp.d.ts +42 -0
  41. package/dist/mcp.js +814 -0
  42. package/dist/mcp.js.map +1 -0
  43. package/dist/mod-tool.d.ts +58 -0
  44. package/dist/mod-tool.js +498 -0
  45. package/dist/mod-tool.js.map +1 -0
  46. package/dist/mod.d.ts +31 -0
  47. package/dist/mod.js +250 -0
  48. package/dist/mod.js.map +1 -0
  49. package/dist/patch.d.ts +44 -0
  50. package/dist/patch.js +506 -0
  51. package/dist/patch.js.map +1 -0
  52. package/dist/provenance.d.ts +40 -0
  53. package/dist/provenance.js +335 -0
  54. package/dist/provenance.js.map +1 -0
  55. package/dist/query.d.ts +27 -0
  56. package/dist/query.js +294 -0
  57. package/dist/query.js.map +1 -0
  58. package/dist/reach.d.ts +14 -0
  59. package/dist/reach.js +140 -0
  60. package/dist/reach.js.map +1 -0
  61. package/dist/relation.d.ts +19 -0
  62. package/dist/relation.js +305 -0
  63. package/dist/relation.js.map +1 -0
  64. package/dist/report-sarif.d.ts +14 -0
  65. package/dist/report-sarif.js +102 -0
  66. package/dist/report-sarif.js.map +1 -0
  67. package/dist/site.d.ts +4 -0
  68. package/dist/site.js +31 -0
  69. package/dist/site.js.map +1 -1
  70. package/dist/std.d.ts +1 -0
  71. package/dist/std.js +73 -0
  72. package/dist/std.js.map +1 -0
  73. package/dist/subsume.d.ts +39 -0
  74. package/dist/subsume.js +526 -0
  75. package/dist/subsume.js.map +1 -0
  76. package/dist/trim.d.ts +19 -0
  77. package/dist/trim.js +155 -0
  78. package/dist/trim.js.map +1 -0
  79. package/dist/tsconfig.tsbuildinfo +1 -1
  80. package/dist/type.d.ts +17 -1
  81. package/dist/type.js.map +1 -1
  82. package/dist/unify.d.ts +3 -1
  83. package/dist/unify.js +287 -18
  84. package/dist/unify.js.map +1 -1
  85. package/dist/utility.d.ts +9 -1
  86. package/dist/utility.js +122 -1
  87. package/dist/utility.js.map +1 -1
  88. package/dist/val/AggFuncVal.d.ts +33 -0
  89. package/dist/val/AggFuncVal.js +202 -0
  90. package/dist/val/AggFuncVal.js.map +1 -0
  91. package/dist/val/ArithFuncVal.d.ts +31 -0
  92. package/dist/val/ArithFuncVal.js +62 -0
  93. package/dist/val/ArithFuncVal.js.map +1 -0
  94. package/dist/val/BagVal.d.ts +5 -0
  95. package/dist/val/BagVal.js +96 -5
  96. package/dist/val/BagVal.js.map +1 -1
  97. package/dist/val/CloseFuncVal.js +9 -1
  98. package/dist/val/CloseFuncVal.js.map +1 -1
  99. package/dist/val/ConjunctVal.d.ts +1 -1
  100. package/dist/val/ConjunctVal.js +19 -0
  101. package/dist/val/ConjunctVal.js.map +1 -1
  102. package/dist/val/ConstraintVal.d.ts +48 -1
  103. package/dist/val/ConstraintVal.js +1501 -110
  104. package/dist/val/ConstraintVal.js.map +1 -1
  105. package/dist/val/CopyFuncVal.d.ts +1 -2
  106. package/dist/val/CopyFuncVal.js +7 -0
  107. package/dist/val/CopyFuncVal.js.map +1 -1
  108. package/dist/val/Decimal.d.ts +1 -0
  109. package/dist/val/Decimal.js +13 -0
  110. package/dist/val/Decimal.js.map +1 -1
  111. package/dist/val/DeprecateFuncVal.d.ts +11 -0
  112. package/dist/val/DeprecateFuncVal.js +47 -0
  113. package/dist/val/DeprecateFuncVal.js.map +1 -0
  114. package/dist/val/DisjunctVal.js +130 -21
  115. package/dist/val/DisjunctVal.js.map +1 -1
  116. package/dist/val/EachFuncVal.d.ts +15 -0
  117. package/dist/val/EachFuncVal.js +75 -0
  118. package/dist/val/EachFuncVal.js.map +1 -0
  119. package/dist/val/ExpectVal.d.ts +1 -0
  120. package/dist/val/ExpectVal.js +41 -4
  121. package/dist/val/ExpectVal.js.map +1 -1
  122. package/dist/val/FeatureVal.js +1 -1
  123. package/dist/val/FeatureVal.js.map +1 -1
  124. package/dist/val/FilterFuncVal.d.ts +15 -0
  125. package/dist/val/FilterFuncVal.js +91 -0
  126. package/dist/val/FilterFuncVal.js.map +1 -0
  127. package/dist/val/FuncBaseVal.d.ts +6 -1
  128. package/dist/val/FuncBaseVal.js +178 -2
  129. package/dist/val/FuncBaseVal.js.map +1 -1
  130. package/dist/val/HideFuncVal.js.map +1 -1
  131. package/dist/val/IdFuncVal.d.ts +13 -0
  132. package/dist/val/IdFuncVal.js +54 -0
  133. package/dist/val/IdFuncVal.js.map +1 -0
  134. package/dist/val/JunctionVal.js +7 -1
  135. package/dist/val/JunctionVal.js.map +1 -1
  136. package/dist/val/KeyFuncVal.d.ts +1 -1
  137. package/dist/val/KeyFuncVal.js +38 -30
  138. package/dist/val/KeyFuncVal.js.map +1 -1
  139. package/dist/val/ListVal.js +117 -17
  140. package/dist/val/ListVal.js.map +1 -1
  141. package/dist/val/LowerFuncVal.js.map +1 -1
  142. package/dist/val/MapVal.js +102 -8
  143. package/dist/val/MapVal.js.map +1 -1
  144. package/dist/val/MatchFuncVal.d.ts +15 -0
  145. package/dist/val/MatchFuncVal.js +107 -0
  146. package/dist/val/MatchFuncVal.js.map +1 -0
  147. package/dist/val/MoveFuncVal.js.map +1 -1
  148. package/dist/val/NilVal.js +24 -0
  149. package/dist/val/NilVal.js.map +1 -1
  150. package/dist/val/OpBaseVal.d.ts +1 -1
  151. package/dist/val/OpBaseVal.js +24 -2
  152. package/dist/val/OpBaseVal.js.map +1 -1
  153. package/dist/val/OpenFuncVal.js +4 -1
  154. package/dist/val/OpenFuncVal.js.map +1 -1
  155. package/dist/val/PackFuncVal.d.ts +15 -0
  156. package/dist/val/PackFuncVal.js +108 -0
  157. package/dist/val/PackFuncVal.js.map +1 -0
  158. package/dist/val/PathFuncVal.js.map +1 -1
  159. package/dist/val/PlaceVal.d.ts +13 -0
  160. package/dist/val/PlaceVal.js +131 -0
  161. package/dist/val/PlaceVal.js.map +1 -0
  162. package/dist/val/PlusOpVal.js +11 -2
  163. package/dist/val/PlusOpVal.js.map +1 -1
  164. package/dist/val/PrefFuncVal.js.map +1 -1
  165. package/dist/val/PrefVal.d.ts +2 -2
  166. package/dist/val/PrefVal.js +78 -23
  167. package/dist/val/PrefVal.js.map +1 -1
  168. package/dist/val/RefVal.d.ts +1 -1
  169. package/dist/val/RefVal.js +158 -30
  170. package/dist/val/RefVal.js.map +1 -1
  171. package/dist/val/ReferFuncVal.d.ts +36 -0
  172. package/dist/val/ReferFuncVal.js +303 -0
  173. package/dist/val/ReferFuncVal.js.map +1 -0
  174. package/dist/val/ScalarKindVal.d.ts +1 -2
  175. package/dist/val/ScalarKindVal.js +0 -11
  176. package/dist/val/ScalarKindVal.js.map +1 -1
  177. package/dist/val/TopVal.js.map +1 -1
  178. package/dist/val/TypeFuncVal.js.map +1 -1
  179. package/dist/val/UpperFuncVal.js.map +1 -1
  180. package/dist/val/Val.d.ts +9 -2
  181. package/dist/val/Val.js +150 -4
  182. package/dist/val/Val.js.map +1 -1
  183. package/dist/val/VarVal.js.map +1 -1
  184. package/dist/val/arith.d.ts +6 -0
  185. package/dist/val/arith.js +170 -0
  186. package/dist/val/arith.js.map +1 -0
  187. package/dist/vet.d.ts +45 -0
  188. package/dist/vet.js +776 -0
  189. package/dist/vet.js.map +1 -0
  190. package/dist/walk.d.ts +2 -0
  191. package/dist/walk.js +91 -0
  192. package/dist/walk.js.map +1 -0
  193. package/grammar/aontu.gbnf +130 -0
  194. package/grammar/aontu.lark +113 -0
  195. package/package.json +30 -15
  196. package/skill/SKILL.md +37 -0
  197. package/skill/error-codes.md +62 -0
  198. package/skill/examples.md +99 -0
  199. package/skill/grammar-card.md +57 -0
  200. package/src/agentsmd.ts +135 -0
  201. package/src/aontu.ts +192 -4
  202. package/src/cli.ts +2858 -71
  203. package/src/ctx.ts +81 -0
  204. package/src/diff.ts +196 -0
  205. package/src/err.ts +52 -8
  206. package/src/graph.ts +135 -0
  207. package/src/hcanon.ts +169 -0
  208. package/src/hints.ts +271 -5
  209. package/src/jsonschema.ts +511 -0
  210. package/src/lang.ts +779 -37
  211. package/src/lsp.ts +281 -47
  212. package/src/mcp-server.ts +187 -0
  213. package/src/mcp.ts +993 -0
  214. package/src/mod-tool.ts +679 -0
  215. package/src/mod.ts +344 -0
  216. package/src/patch.ts +624 -0
  217. package/src/provenance.ts +430 -0
  218. package/src/query.ts +379 -0
  219. package/src/reach.ts +184 -0
  220. package/src/relation.ts +395 -0
  221. package/src/report-sarif.ts +137 -0
  222. package/src/site.ts +36 -1
  223. package/src/std.ts +73 -0
  224. package/src/subsume.ts +690 -0
  225. package/src/trim.ts +195 -0
  226. package/src/tsconfig.json +10 -4
  227. package/src/type.ts +51 -2
  228. package/src/unify.ts +311 -16
  229. package/src/utility.ts +139 -1
  230. package/src/val/AggFuncVal.ts +319 -0
  231. package/src/val/ArithFuncVal.ts +108 -0
  232. package/src/val/BagVal.ts +101 -4
  233. package/src/val/CloseFuncVal.ts +9 -1
  234. package/src/val/ConjunctVal.ts +20 -0
  235. package/src/val/ConstraintVal.ts +1699 -116
  236. package/src/val/CopyFuncVal.ts +7 -1
  237. package/src/val/Decimal.ts +15 -0
  238. package/src/val/DeprecateFuncVal.ts +84 -0
  239. package/src/val/DisjunctVal.ts +139 -28
  240. package/src/val/EachFuncVal.ts +133 -0
  241. package/src/val/ExpectVal.ts +43 -6
  242. package/src/val/FeatureVal.ts +1 -1
  243. package/src/val/FilterFuncVal.ts +154 -0
  244. package/src/val/FuncBaseVal.ts +200 -3
  245. package/src/val/HideFuncVal.ts +0 -2
  246. package/src/val/IdFuncVal.ts +91 -0
  247. package/src/val/JunctionVal.ts +7 -1
  248. package/src/val/KeyFuncVal.ts +39 -35
  249. package/src/val/ListVal.ts +125 -18
  250. package/src/val/LowerFuncVal.ts +0 -1
  251. package/src/val/MapVal.ts +110 -8
  252. package/src/val/MatchFuncVal.ts +176 -0
  253. package/src/val/MoveFuncVal.ts +0 -2
  254. package/src/val/NilVal.ts +25 -0
  255. package/src/val/OpBaseVal.ts +26 -3
  256. package/src/val/OpenFuncVal.ts +4 -2
  257. package/src/val/PackFuncVal.ts +175 -0
  258. package/src/val/PathFuncVal.ts +0 -1
  259. package/src/val/PlaceVal.ts +193 -0
  260. package/src/val/PlusOpVal.ts +11 -2
  261. package/src/val/PrefFuncVal.ts +0 -1
  262. package/src/val/PrefVal.ts +79 -36
  263. package/src/val/RefVal.ts +163 -30
  264. package/src/val/ReferFuncVal.ts +387 -0
  265. package/src/val/ScalarKindVal.ts +0 -13
  266. package/src/val/TopVal.ts +0 -1
  267. package/src/val/TypeFuncVal.ts +0 -2
  268. package/src/val/UpperFuncVal.ts +0 -1
  269. package/src/val/Val.ts +213 -3
  270. package/src/val/VarVal.ts +0 -1
  271. package/src/val/arith.ts +316 -0
  272. package/src/vet.ts +992 -0
  273. package/src/walk.ts +99 -0
@@ -13,7 +13,6 @@ import {
13
13
 
14
14
  import { makeNilErr } from '../err'
15
15
 
16
- import { NilVal } from '../val/NilVal'
17
16
 
18
17
 
19
18
  import {
@@ -66,6 +65,13 @@ class CopyFuncVal extends FuncBaseVal {
66
65
  // console.log('WALK', val)
67
66
  val.mark.type = false
68
67
  val.mark.hide = false
68
+ // `copy()` CLEARS IDENTITY (G4 phase 1, clearing rule 2),
69
+ // consistent with its clearing of the marks: a copy of an
70
+ // entity is a second value shaped like it, and leaving the id
71
+ // on would merge the copy straight back into the original —
72
+ // making `copy()` a no-op for exactly the values it exists to
73
+ // detach.
74
+ val.entity = undefined
69
75
  return val
70
76
  })
71
77
  }
@@ -176,6 +176,21 @@ class Decimal {
176
176
  }
177
177
 
178
178
 
179
+ // D6 -- EXACT MULTIPLICATION. Multiply the coefficients, ADD the
180
+ // scales: (a/10^s)(b/10^t) is ab/10^(s+t), with no alignment step and
181
+ // no rounding mode, exactly as add() has none.
182
+ //
183
+ // The result leaves the budget far more readily than a sum does --
184
+ // scales add rather than taking the maximum, and coefficient digits
185
+ // add too -- so squaring a value at half the budget is already over
186
+ // it. Every caller must test with decimalOverBudget() and report
187
+ // `decimal_budget`, for the same reason add()'s callers must: at the
188
+ // limit, refusing is the only answer that is not a rounded one.
189
+ multiply(peer: Decimal): Decimal {
190
+ return new Decimal(this.unscaled * peer.unscaled, this.scale + peer.scale)
191
+ }
192
+
193
+
179
194
  // Exact ceiling and floor, for `upper()`/`lower()`. Coefficient
180
195
  // arithmetic only -- Math.ceil of this value would mean rounding it to
181
196
  // binary64 first, which for a leaf that exists to escape binary64 is
@@ -0,0 +1,84 @@
1
+ /* Copyright (c) 2025 Richard Rodger, MIT License */
2
+
3
+ // The deprecation mark (G3 phase 4,
4
+ // docs/capability-review/g3-subsumption-evolution.md): a function-form
5
+ // builtin, `deprecate(x, m)`, that unifies EXACTLY as `x` while the
6
+ // record `m` rides the result through meets. The record's keys are
7
+ // msg, use and since — all optional, all strings; `use` is a path
8
+ // spelled as a STRING, because a live reference would resolve and
9
+ // unify, which is not wanted. Boolean ValMarks cannot hold a record,
10
+ // so the Val carries one optional field (Val.deprecation), propagated
11
+ // by the same channel as the marks (propagateMarks) and rendered back
12
+ // reparseably by canon (canonRiders).
13
+
14
+ import type {
15
+ Val,
16
+ ValSpec,
17
+ } from '../type'
18
+
19
+ import {
20
+ AontuContext,
21
+ } from '../ctx'
22
+
23
+ import { makeNilErr } from '../err'
24
+
25
+ import { FuncBaseVal } from './FuncBaseVal'
26
+
27
+
28
+ // The record's whole vocabulary. Other keys are DROPPED, not carried:
29
+ // the record is a contract the tooling reads (vet, the LSP tag, the
30
+ // breaking downgrade), and a bag of free-form keys would be a second,
31
+ // unspecified metadata channel.
32
+ const DEPRECATION_KEYS = ['msg', 'use', 'since']
33
+
34
+
35
+ class DeprecateFuncVal extends FuncBaseVal {
36
+ isDeprecateFunc = true
37
+
38
+ constructor(
39
+ spec: ValSpec,
40
+ ctx?: AontuContext
41
+ ) {
42
+ super(spec, ctx)
43
+ }
44
+
45
+ make(_ctx: AontuContext, spec: ValSpec): Val {
46
+ return new DeprecateFuncVal(spec)
47
+ }
48
+
49
+ funcname() {
50
+ return 'deprecate'
51
+ }
52
+
53
+ resolve(ctx: AontuContext, args: Val[]) {
54
+ let out = args[0] ?? makeNilErr(ctx, 'arg', this)
55
+
56
+ // A nil ARGUMENT is returned unchanged, never marked: marking it
57
+ // makes the bag's marked-child skip drop it (the type()/hide()
58
+ // lesson — refusal over corruption, D7).
59
+ if (out.isNil) {
60
+ return out
61
+ }
62
+
63
+ out = out.clone(ctx)
64
+
65
+ const record: Record<string, string> = {}
66
+ const m: any = args[1]
67
+ if (true === m?.isMap && null != m.peg) {
68
+ for (const key of DEPRECATION_KEYS) {
69
+ const v = m.peg[key]
70
+ if (true === v?.isScalar && 'string' === typeof v.peg) {
71
+ record[key] = v.peg
72
+ }
73
+ }
74
+ }
75
+ out.deprecation = record
76
+
77
+ return out
78
+ }
79
+ } /* node:coverage ignore next 6 */
80
+
81
+
82
+ export {
83
+ DeprecateFuncVal,
84
+ }
@@ -13,7 +13,7 @@ import {
13
13
 
14
14
  import { AontuContext } from '../ctx'
15
15
 
16
- import { makeNilErr } from '../err'
16
+ import { AontuError, descErr, makeNilErr } from '../err'
17
17
  import { unite } from '../unify'
18
18
 
19
19
  import {
@@ -30,8 +30,8 @@ import {
30
30
  top
31
31
  } from './top'
32
32
 
33
- import { NilVal, TRIAL_NIL } from '../val/NilVal'
34
- import { PrefVal } from '../val/PrefVal'
33
+ import { TRIAL_NIL } from '../val/NilVal'
34
+ import { PrefVal, prefInnerPeg } from '../val/PrefVal'
35
35
  import { JunctionVal } from '../val/JunctionVal'
36
36
 
37
37
 
@@ -102,6 +102,7 @@ class DisjunctVal extends JunctionVal {
102
102
  // leaving ctx._trialMode=true would collapse every subsequent real
103
103
  // error in this ctx to the shared TRIAL_NIL sentinel.
104
104
  ctx._trialMode = true
105
+ let gate: number[] | undefined = undefined
105
106
  try {
106
107
  for (let vI = 0; vI < this.peg.length; vI++) {
107
108
  const v = this.peg[vI]
@@ -117,9 +118,60 @@ class DisjunctVal extends JunctionVal {
117
118
  // sentinel instead of allocating a fresh NilVal per trial.
118
119
  oval[vI] = TRIAL_NIL
119
120
  }
121
+ else if (v instanceof PrefVal &&
122
+ !(peer as any).isPref && !peer.isTop &&
123
+ true === (prefInnerPeg(v) as any).isScalar) {
124
+ // A candidate for the admission gate below: a non-pref,
125
+ // non-top peer met a scalar preference inside this
126
+ // disjunction.
127
+ ; (gate = gate ?? []).push(vI)
128
+ }
120
129
 
121
130
  done = done && DONE === oval[vI].dc
122
131
  }
132
+
133
+ // THE ADMISSION GATE (ADR-004). A peer that meets a preference
134
+ // INSIDE a disjunction must be admitted by the disjunction: by
135
+ // some sibling alternative (whose own trial above already
136
+ // answers that), or by the preferred value itself (the pref
137
+ // branch's own admitted set). The pref's kind gate alone used to
138
+ // decide, so a same-kind concrete peer replaced the default with
139
+ // the alternatives never consulted -- `k:*'auto'|'literal'|'data'`
140
+ // plus `k:'autoo'` answered "autoo", and `*8080|(integer&neq(80))`
141
+ // admitted 80 (use-cases/BUGS.md §1-2). An inadmissible override
142
+ // now fails the pref member's trial, and when every member is
143
+ // gone the meet is the existing `|:empty` refusal.
144
+ //
145
+ // SCALAR preferred values only, exactly the kind gate's own
146
+ // boundary (test/spec/pref.tsv, "THE GATE IS A SCALAR GATE"): a
147
+ // structural or kind-peg default stays ungated. A deliberately
148
+ // open default remains spellable as `*x|top` -- the top branch
149
+ // admits every override (the apidef machine-emitted idiom).
150
+ if (undefined !== gate) {
151
+ for (const gI of gate) {
152
+ let admitted = false
153
+ for (let kI = 0; kI < oval.length && !admitted; kI++) {
154
+ // Sibling alternatives only: a pref member cannot admit
155
+ // its own override (post-rankPrefs at most one pref
156
+ // stands at this level, so this is defensive).
157
+ admitted = kI !== gI && !oval[kI].isNil &&
158
+ !(this.peg[kI] as any).isPref
159
+ }
160
+ if (!admitted) {
161
+ const admitErr: any[] = []
162
+ ctx.err = admitErr
163
+ // The trial is against a CLONE: the preferred value must
164
+ // stay pristine for the surviving preference (the
165
+ // MatchFuncVal.resolve precedent).
166
+ const met = unite(ctx,
167
+ prefInnerPeg(this.peg[gI] as PrefVal).clone(ctx), peer,
168
+ 'dj-admit')
169
+ if (0 < admitErr.length || met.isNil) {
170
+ oval[gI] = TRIAL_NIL
171
+ }
172
+ }
173
+ }
174
+ }
123
175
  }
124
176
  finally {
125
177
  ctx._trialMode = savedTrialMode
@@ -128,6 +180,33 @@ class DisjunctVal extends JunctionVal {
128
180
 
129
181
  // // // console.log('DISJUNCT-unify-B', this.id, oval.map(v => v.canon))
130
182
 
183
+ // A PREFERENCE CONJOINED WITH A DISJUNCTION IS A PREFERENCE ON THE
184
+ // ALTERNATIVE IT NAMES: `(A|B) & *A` is `*A|B`, the same value the
185
+ // direct spelling `*A|B` denotes. Distribution carries the peer to
186
+ // each member, and a scalar preference meeting a concrete same-kind
187
+ // member is replaced BY that member (the kind gate) -- so the
188
+ // preference simply vanished, and `specversion: ("1.0"|"1.1") &
189
+ // *"1.0"`, the enum-with-default written the other way round, held
190
+ // no default at all. The old generation fold hid it by folding the
191
+ // members together; ADR-007 does not, and a disjunction that has
192
+ // lost its default is not the value the author wrote.
193
+ //
194
+ // A preference naming no alternative is dropped, as it is today: it
195
+ // has nothing to prefer, and the default-validity lint is what
196
+ // reports that shape.
197
+ if (true === (peer as any).isPref) {
198
+ const want: any = prefInnerPeg(peer as PrefVal)
199
+ for (let vI = 0; vI < oval.length; vI++) {
200
+ const got: any = oval[vI]
201
+ if (!got.isNil && true !== got.isPref && got.same(want)) {
202
+ const wrapped = new PrefVal({ peg: got }, ctx)
203
+ wrapped.rank = (peer as PrefVal).rank
204
+ ;(peer as PrefVal).place(wrapped)
205
+ oval[vI] = wrapped
206
+ }
207
+ }
208
+ }
209
+
131
210
  // Remove duplicates, and normalize
132
211
  if (1 < oval.length) {
133
212
  for (let vI = 0; vI < oval.length; vI++) {
@@ -150,10 +229,14 @@ class DisjunctVal extends JunctionVal {
150
229
  }
151
230
 
152
231
  // // // console.log('DISJUNCT-unify-D', this.id, oval.map(v => v.canon))
153
-
154
- oval = oval.filter(v => !v.isNil)
155
232
  }
156
233
 
234
+ // Outside the 1<length block: a SINGLE-member disjunction (e.g. a
235
+ // rankPrefs collapse) whose one member fails the trial or the
236
+ // admission gate must reach the `|:empty` refusal below, not
237
+ // return the trial sentinel as if it were the answer.
238
+ oval = oval.filter(v => !v.isNil)
239
+
157
240
  let out: Val
158
241
 
159
242
  if (1 == oval.length) {
@@ -164,6 +247,14 @@ class DisjunctVal extends JunctionVal {
164
247
  }
165
248
  else {
166
249
  out = new DisjunctVal({ peg: oval }, ctx)
250
+ // A NARROWED DISJUNCTION IS STILL THAT DISJUNCTION. The meet mints
251
+ // a fresh value, which used to arrive unsited and file-less -- so
252
+ // every finding naming a disjunction that had met anything
253
+ // pointed at row -1 with no file, and an agent handed the report
254
+ // had nowhere to go (the review's finding F). `place` copies the
255
+ // whole site, position and url together, which is what tells the
256
+ // report which document it came from.
257
+ this.place(out)
167
258
  }
168
259
 
169
260
  out.dc = done ? DONE : this.dc + 1
@@ -177,7 +268,11 @@ class DisjunctVal extends JunctionVal {
177
268
  }
178
269
 
179
270
 
180
- rankPrefs(ctx: AontuContext) {
271
+ // Answers the sole surviving preference when ranking collapsed the
272
+ // disjunction to one -- which the RECURSIVE call below consumes to
273
+ // lift a nested disjunct's winner into this one. Undefined when
274
+ // more than one alternative survives, so the type says both.
275
+ rankPrefs(ctx: AontuContext): PrefVal | undefined {
181
276
  let lastpref: PrefVal | undefined = undefined
182
277
  let lastprefI = -1
183
278
 
@@ -214,7 +309,7 @@ class DisjunctVal extends JunctionVal {
214
309
  }
215
310
  }
216
311
  else if (v.isDisjunct) {
217
- let subrank: any = v.rankPrefs(ctx)
312
+ const subrank = (v as DisjunctVal).rankPrefs(ctx)
218
313
  if (subrank instanceof PrefVal) {
219
314
  this.peg[vI] = subrank
220
315
  lastpref = subrank
@@ -231,6 +326,8 @@ class DisjunctVal extends JunctionVal {
231
326
  if (1 === this.peg.length && this.peg[0] instanceof PrefVal) {
232
327
  return this.peg[0]
233
328
  }
329
+
330
+ return undefined
234
331
  }
235
332
 
236
333
 
@@ -246,35 +343,49 @@ class DisjunctVal extends JunctionVal {
246
343
  }
247
344
 
248
345
 
346
+ // AN UNRESOLVED DISJUNCTION IS NOT A VALUE (ADR-007).
347
+ //
348
+ // Generation used to FOLD the surviving members together with unify
349
+ // and emit the result. That answer is in no branch of the
350
+ // disjunction: `({x:1}|{y:2}) & {z:3}` generated `{x:1,y:2,z:3}`, a
351
+ // map the model never admits, and `1|2` died as a scalar_value
352
+ // CONFLICT -- the conflict of the fold, not of anything the author
353
+ // wrote. The second half is what made vet decorative: vet's
354
+ // incompleteness check keeps incomplete-class findings, so a missing
355
+ // required enum field (`role: 'a'|'b'` with no data) arrived as a
356
+ // conflict, was filtered out, and vetted VALID with zero findings
357
+ // (use-cases/BUGS.md §13, the review's finding C).
358
+ //
359
+ // What remains after unification is what the model still admits, so
360
+ // more than one surviving alternative means the truth is not yet
361
+ // settled -- incomplete, the same class a bare `string` residue
362
+ // answers, and the same answer CUE gives for a non-concrete export.
363
+ // A preference resolves it (that is what `*` is for), and so does a
364
+ // single surviving member.
249
365
  gen(ctx: AontuContext) {
250
- // TODO: move this to main unify
251
-
252
- // console.log('DJ-GEN', this.peg.map((p: any) => p.canon), ctx.err)
253
-
254
366
  if (0 < this.peg.length) {
367
+ // Ranking may not have run when gen is reached without a prior
368
+ // unify (a library caller generating a freshly parsed tree), and
369
+ // it is what guarantees at most one preference stands here.
370
+ if (!this.prefsRanked) {
371
+ this.rankPrefs(ctx)
372
+ }
255
373
 
256
- let vals = this.peg.filter((v: Val) => v instanceof PrefVal)
257
- // // // console.log('DJ-GEN-VALS-A', vals.map((p: any) => p.canon))
374
+ const prefs = this.peg.filter((v: Val) => v instanceof PrefVal)
258
375
 
259
- vals = 0 === vals.length ? this.peg : vals
376
+ if (0 === prefs.length && 1 < this.peg.length) {
377
+ const nerr = makeNilErr(ctx, 'disjunct_no_gen', this)
378
+ descErr(nerr, ctx)
379
+ ctx?.adderr(nerr)
260
380
 
261
- let val = vals[0]
381
+ if (null == ctx || !ctx.collect) {
382
+ throw new AontuError(nerr.msg, [nerr])
383
+ }
262
384
 
263
- // TODO: over unifies complex types like maps
264
- // ({x:1}|{y:2})&{z:3} should be {"x":1,"z":3}|{"y":2,"z":3} not { x:1, z:3, y:2 }
265
- for (let vI = 1; vI < vals.length; vI++) {
266
- // Index `vals`, not `this.peg`: when the pref members are not the
267
- // leading entries the two arrays differ, and folding against
268
- // this.peg[vI] would unify the wrong (or a repeated) member.
269
- let valnext = val.unify(vals[vI], ctx)
270
- // // // console.log('DJ-GEN-VALS-NEXT', valnext.canon)
271
- val = valnext
385
+ return undefined
272
386
  }
273
387
 
274
- // console.log('DJ-GEN-VALS-B', val.canon)
275
- const out = val.gen(ctx)
276
- // console.log('DJ-GEN-VALS-C', out)
277
- return out
388
+ return (0 < prefs.length ? prefs[0] : this.peg[0]).gen(ctx)
278
389
  }
279
390
 
280
391
  return super.gen(ctx)
@@ -0,0 +1,133 @@
1
+ /* Copyright (c) 2025 Richard Rodger, MIT License */
2
+
3
+ // GENERATION: `each(data, tmpl)` (G8 phase 1,
4
+ // docs/capability-review/g8-generation.md). One element of the result
5
+ // list per child of `data`, each of them that child met with `tmpl`.
6
+ // Written with one argument, `each(m)` is a map's children as a list.
7
+ //
8
+ // ports: {http: 80, https: 443}
9
+ // open: each($.ports, integer) -> [80, 443]
10
+ //
11
+ // ORDER IS FIXED, and fixed the way canon already fixes it: source
12
+ // order for a list, sorted-key order for a map (`cmpCodePoint`, the
13
+ // comparator `MapVal.canon` and the Go port's marshalling use). A
14
+ // generated list whose order depended on insertion history would differ
15
+ // between two runs of the same document, and between the two ports --
16
+ // the one thing the shared spec exists to prevent.
17
+ //
18
+ // The element is the source child CLONED, not shared: it is a second
19
+ // position holding that value, and a position is where path-dependent
20
+ // content resolves. What the clone keeps is the identity, if the child
21
+ // carries one (G4 phase 1) -- a listed entity is still that entity, and
22
+ // the merge that follows is the point.
23
+
24
+ import type {
25
+ Val,
26
+ ValSpec,
27
+ } from '../type'
28
+
29
+ import {
30
+ AontuContext,
31
+ } from '../ctx'
32
+
33
+ import { unite } from '../unify'
34
+ import { makeNilErr } from '../err'
35
+ import { ListVal } from './ListVal'
36
+ import { FuncBaseVal } from './FuncBaseVal'
37
+ import { repathInstance } from './Val'
38
+ import { fillPlace } from './PlaceVal'
39
+ import { cmpCodePoint } from '../keyorder'
40
+
41
+
42
+ // The children a data bag holds, in the order the result must carry
43
+ // them, or the code naming what is wrong with the argument.
44
+ function dataValues(data: Val | undefined): Val[] | string {
45
+ const d: any = data
46
+
47
+ if (true === d?.isMap) {
48
+ return Object.keys(d.peg).sort(cmpCodePoint).map((k: string) => d.peg[k])
49
+ }
50
+
51
+ if (true === d?.isList) {
52
+ return [...(d.peg as Val[])]
53
+ }
54
+
55
+ return 'each_data'
56
+ }
57
+
58
+
59
+ class EachFuncVal extends FuncBaseVal {
60
+ isEachFunc = true
61
+
62
+ // THE STAGING RULE, for the reason given in PackFuncVal.
63
+ staged = true
64
+
65
+ constructor(
66
+ spec: ValSpec,
67
+ ctx?: AontuContext
68
+ ) {
69
+ super(spec, ctx)
70
+ }
71
+
72
+
73
+
74
+ funcname() {
75
+ return 'each'
76
+ }
77
+
78
+
79
+ // The template is not an argument to drive (see PackFuncVal.prepare).
80
+ prepare(_ctx: AontuContext, _args: Val[]) {
81
+ return null
82
+ }
83
+
84
+
85
+ unify(peer: Val, ctx: AontuContext): Val {
86
+ // ONE argument is driven: the data. The template is not (see
87
+ // prepare above), and driveStagedArgs answers whether the data has
88
+ // settled -- the other half of "ready to fire".
89
+ const ready = this.driveStagedArgs(ctx, 1)
90
+
91
+ if (!ready || !ctx.settle) {
92
+ return this.residuate(peer, ctx)
93
+ }
94
+
95
+ return super.unify(peer, ctx)
96
+ }
97
+
98
+
99
+ resolve(ctx: AontuContext, args: Val[]) {
100
+ const vals = dataValues(args?.[0])
101
+ if ('string' === typeof vals) {
102
+ return makeNilErr(ctx, vals, this)
103
+ }
104
+
105
+ const tmpl: Val | undefined = args?.[1]
106
+ const peg: Val[] = []
107
+
108
+ for (let i = 0; i < vals.length; i++) {
109
+ const elctx = ctx.descend(String(i))
110
+ const el = vals[i].clone(elctx)
111
+ // The template is CLONED per element, never shared — a FULL
112
+ // instance to the leaves (`dup`, ADR-005): see PackFuncVal.resolve.
113
+ // `_` inside the template binds the source child (G8 phase 3),
114
+ // which for `each` is the element itself.
115
+ let inst: Val | undefined = undefined
116
+ if (undefined !== tmpl) {
117
+ inst = tmpl.clone(elctx, { dup: true })
118
+ repathInstance(inst, inst.path)
119
+ }
120
+ peg.push(undefined === inst ? el :
121
+ unite(elctx, el, fillPlace(inst, vals[i], elctx), 'each'))
122
+ }
123
+
124
+ return new ListVal({ peg }, ctx)
125
+ }
126
+
127
+ } /* node:coverage ignore next 7 */
128
+
129
+
130
+ export {
131
+ dataValues,
132
+ EachFuncVal,
133
+ }
@@ -16,7 +16,6 @@ import {
16
16
  import { unite } from '../unify'
17
17
 
18
18
  import {
19
- propagateMarks,
20
19
  explainOpen,
21
20
  ec,
22
21
  explainClose,
@@ -35,6 +34,21 @@ class ExpectVal extends FeatureVal {
35
34
  parent?: Val
36
35
  key?: string
37
36
 
37
+ // An expectation canons as THE EXPECTATION ITSELF -- the peg the peer
38
+ // must satisfy. Val.canon's default was the empty string, which
39
+ // rendered a key with no value (`{"r":}`): text that is not a document
40
+ // and could not be reparsed, breaking canon's round-trip contract in
41
+ // both engines (issue #43).
42
+ //
43
+ // Not `top`, which was the first fix here and was wrong. An ExpectVal
44
+ // is created for EVERY peer-introduced non-generable key, not just for
45
+ // `&:` spread children -- `m:{x:1} m:{y:string}` makes one at `y` with
46
+ // no spread in sight -- so rendering `top` erased the `string` and the
47
+ // canon reparsed into a document that accepts values the original
48
+ // rejects. A canon that silently drops a constraint is worse than one
49
+ // that fails to parse. Go's ExpectVal.Canon renders the same peg.
50
+ get canon() { return this.peg.canon }
51
+
38
52
  constructor(
39
53
  spec: ValSpec,
40
54
  ctx?: AontuContext
@@ -42,21 +56,42 @@ class ExpectVal extends FeatureVal {
42
56
  super(spec, ctx)
43
57
  }
44
58
 
59
+ // PURE, deliberately (the unequal-spread crosswire, BUGS.md §6-§7).
60
+ // The old body accumulated `this.peer` IN PLACE, which was invisible
61
+ // while an expectation only ever lived at one destination -- but the
62
+ // spread-combination meet (MapVal.unify's 'map-self' unite) bakes an
63
+ // ExpectVal INTO the combined template, and a path-independent
64
+ // template is SHARED across every destination (spreadClone tier 1).
65
+ // One stateful node in a shared template unified each sibling's own
66
+ // data with the next sibling's ($.w.y.r: "Cannot unify value: 6 with
67
+ // value: 5", both values sibling data). An expectation now answers
68
+ // with a NEW node when it must keep accumulated state, so a shared
69
+ // template's expect stays exactly what was written.
45
70
  unify(peer: Val, ctx: AontuContext): Val {
46
71
  const te = ctx.explain && explainOpen(ctx, ctx.explain, 'Expect', this, peer)
47
72
 
48
- let out = this
73
+ let out: Val = this
49
74
 
50
75
  if (!peer.isTop) {
51
- this.peer = undefined === this.peer ? peer :
76
+ const acc = undefined === this.peer ? peer :
52
77
  unite(te ? ctx.clone({ explain: ec(te, 'PEER') }) : ctx, this.peer, peer, 'expect-peer')
53
78
 
54
79
  const peeru =
55
- unite(te ? ctx.clone({ explain: ec(te, 'EXPECT') }) : ctx, this.peer, this.peg, 'expect-self')
80
+ unite(te ? ctx.clone({ explain: ec(te, 'EXPECT') }) : ctx, acc, this.peg, 'expect-self')
56
81
 
57
82
  if (peeru.isGenable) {
58
83
  out = peeru
59
84
  }
85
+ else {
86
+ // Still an expectation: carry the accumulated peer forward in a
87
+ // fresh node stored at THIS destination by the caller, leaving
88
+ // `this` -- possibly a shared template's child -- untouched.
89
+ const e = new ExpectVal({ peg: this.peg }, ctx)
90
+ e.key = this.key
91
+ e.parent = this.parent
92
+ e.peer = acc
93
+ out = e
94
+ }
60
95
  }
61
96
 
62
97
  out.dc = DONE
@@ -68,8 +103,10 @@ class ExpectVal extends FeatureVal {
68
103
 
69
104
 
70
105
  gen(ctx: AontuContext) {
71
- // Unresolved expect cannot be generated, so always an error.
72
- let nil = makeNilErr(
106
+ // Unresolved expect cannot be generated, so always an error. The
107
+ // CALL is the point -- it records the failure on ctx -- and there
108
+ // is no value to bind: generation answers nothing.
109
+ makeNilErr(
73
110
  ctx,
74
111
  'expect',
75
112
  this.peg,
@@ -40,7 +40,7 @@ abstract class FeatureVal extends Val {
40
40
  descErr(nerr, ctx)
41
41
  ctx?.adderr(nerr)
42
42
 
43
- if (null == ctx || !ctx?.collect) {
43
+ if (null == ctx || !ctx.collect) {
44
44
  const aerr = new AontuError(nerr.msg, [nerr])
45
45
  throw aerr
46
46
  }