aontu 0.62.0 → 0.63.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 (356) hide show
  1. package/README.md +1 -1
  2. package/dist/agentsmd.js +0 -27
  3. package/dist/agentsmd.js.map +1 -1
  4. package/dist/alias.js.map +1 -1
  5. package/dist/allow.js +0 -92
  6. package/dist/allow.js.map +1 -1
  7. package/dist/aontu.d.ts +1 -1
  8. package/dist/aontu.js +1 -79
  9. package/dist/aontu.js.map +1 -1
  10. package/dist/aontumodel.d.ts +4 -0
  11. package/dist/aontumodel.js +33 -0
  12. package/dist/aontumodel.js.map +1 -0
  13. package/dist/cli.js +101 -620
  14. package/dist/cli.js.map +1 -1
  15. package/dist/ctx.js +0 -48
  16. package/dist/ctx.js.map +1 -1
  17. package/dist/diff.js +0 -32
  18. package/dist/diff.js.map +1 -1
  19. package/dist/err.js +0 -40
  20. package/dist/err.js.map +1 -1
  21. package/dist/escape.js +0 -45
  22. package/dist/escape.js.map +1 -1
  23. package/dist/exactjson.d.ts +0 -35
  24. package/dist/exactjson.js +0 -131
  25. package/dist/exactjson.js.map +1 -1
  26. package/dist/format.js +13 -203
  27. package/dist/format.js.map +1 -1
  28. package/dist/grammar.d.ts +9 -0
  29. package/dist/grammar.js +54 -0
  30. package/dist/grammar.js.map +1 -0
  31. package/dist/graph.js +0 -26
  32. package/dist/graph.js.map +1 -1
  33. package/dist/hcanon.js +0 -82
  34. package/dist/hcanon.js.map +1 -1
  35. package/dist/helpdoc.js +1 -1
  36. package/dist/helpdoc.js.map +1 -1
  37. package/dist/hints.d.ts +0 -6
  38. package/dist/hints.js +54 -55
  39. package/dist/hints.js.map +1 -1
  40. package/dist/jsonschema.js +0 -114
  41. package/dist/jsonschema.js.map +1 -1
  42. package/dist/keyorder.d.ts +0 -7
  43. package/dist/keyorder.js +0 -41
  44. package/dist/keyorder.js.map +1 -1
  45. package/dist/lang.js +17 -915
  46. package/dist/lang.js.map +1 -1
  47. package/dist/lower.js +11 -61
  48. package/dist/lower.js.map +1 -1
  49. package/dist/lsp-server.js +0 -16
  50. package/dist/lsp-server.js.map +1 -1
  51. package/dist/lsp.d.ts +1 -1
  52. package/dist/lsp.js +12 -159
  53. package/dist/lsp.js.map +1 -1
  54. package/dist/mcp-server.js +0 -26
  55. package/dist/mcp-server.js.map +1 -1
  56. package/dist/mcp.js +0 -113
  57. package/dist/mcp.js.map +1 -1
  58. package/dist/mod-tool.js +0 -130
  59. package/dist/mod-tool.js.map +1 -1
  60. package/dist/mod.js +0 -162
  61. package/dist/mod.js.map +1 -1
  62. package/dist/patch.js +0 -217
  63. package/dist/patch.js.map +1 -1
  64. package/dist/provenance.js +0 -140
  65. package/dist/provenance.js.map +1 -1
  66. package/dist/query.js +0 -75
  67. package/dist/query.js.map +1 -1
  68. package/dist/reach.js +0 -43
  69. package/dist/reach.js.map +1 -1
  70. package/dist/relation.js +0 -61
  71. package/dist/relation.js.map +1 -1
  72. package/dist/render.js +20 -135
  73. package/dist/render.js.map +1 -1
  74. package/dist/report-sarif.d.ts +0 -11
  75. package/dist/report-sarif.js +0 -28
  76. package/dist/report-sarif.js.map +1 -1
  77. package/dist/sig.js +0 -35
  78. package/dist/sig.js.map +1 -1
  79. package/dist/sigdecl.js +1 -1
  80. package/dist/sigdecl.js.map +1 -1
  81. package/dist/siggate.js +0 -4
  82. package/dist/siggate.js.map +1 -1
  83. package/dist/site.js +3 -29
  84. package/dist/site.js.map +1 -1
  85. package/dist/subsume.d.ts +0 -10
  86. package/dist/subsume.js +0 -137
  87. package/dist/subsume.js.map +1 -1
  88. package/dist/template.d.ts +2 -1
  89. package/dist/template.js +58 -138
  90. package/dist/template.js.map +1 -1
  91. package/dist/trim.js +0 -41
  92. package/dist/trim.js.map +1 -1
  93. package/dist/tsconfig.tsbuildinfo +1 -1
  94. package/dist/type.js.map +1 -1
  95. package/dist/unify.js +12 -242
  96. package/dist/unify.js.map +1 -1
  97. package/dist/utility.js +0 -22
  98. package/dist/utility.js.map +1 -1
  99. package/dist/val/AbnfFuncVal.d.ts +18 -0
  100. package/dist/val/AbnfFuncVal.js +132 -0
  101. package/dist/val/AbnfFuncVal.js.map +1 -0
  102. package/dist/val/AbsentVal.d.ts +11 -0
  103. package/dist/val/AbsentVal.js +30 -0
  104. package/dist/val/AbsentVal.js.map +1 -0
  105. package/dist/val/AggFuncVal.d.ts +10 -1
  106. package/dist/val/AggFuncVal.js +104 -116
  107. package/dist/val/AggFuncVal.js.map +1 -1
  108. package/dist/val/ArithFuncVal.js +0 -12
  109. package/dist/val/ArithFuncVal.js.map +1 -1
  110. package/dist/val/BagVal.js +1 -78
  111. package/dist/val/BagVal.js.map +1 -1
  112. package/dist/val/BigDecimalVal.js +0 -16
  113. package/dist/val/BigDecimalVal.js.map +1 -1
  114. package/dist/val/BigIntegerVal.js +0 -16
  115. package/dist/val/BigIntegerVal.js.map +1 -1
  116. package/dist/val/CloseFuncVal.js +0 -9
  117. package/dist/val/CloseFuncVal.js.map +1 -1
  118. package/dist/val/CmpFuncVal.js +2 -59
  119. package/dist/val/CmpFuncVal.js.map +1 -1
  120. package/dist/val/ConjunctVal.js +0 -29
  121. package/dist/val/ConjunctVal.js.map +1 -1
  122. package/dist/val/ConstraintVal.js +0 -500
  123. package/dist/val/ConstraintVal.js.map +1 -1
  124. package/dist/val/ContainerKindVal.js +0 -2
  125. package/dist/val/ContainerKindVal.js.map +1 -1
  126. package/dist/val/CopyFuncVal.js +0 -3
  127. package/dist/val/CopyFuncVal.js.map +1 -1
  128. package/dist/val/Decimal.js +0 -179
  129. package/dist/val/Decimal.js.map +1 -1
  130. package/dist/val/DeprecateFuncVal.js.map +1 -1
  131. package/dist/val/DisjunctVal.js +0 -152
  132. package/dist/val/DisjunctVal.js.map +1 -1
  133. package/dist/val/EachFuncVal.js +0 -3
  134. package/dist/val/EachFuncVal.js.map +1 -1
  135. package/dist/val/EmitFuncVal.d.ts +1 -1
  136. package/dist/val/EmitFuncVal.js +6 -119
  137. package/dist/val/EmitFuncVal.js.map +1 -1
  138. package/dist/val/ExpectVal.js +0 -62
  139. package/dist/val/ExpectVal.js.map +1 -1
  140. package/dist/val/FilterFuncVal.js +0 -25
  141. package/dist/val/FilterFuncVal.js.map +1 -1
  142. package/dist/val/FuncBaseVal.d.ts +1 -0
  143. package/dist/val/FuncBaseVal.js +7 -127
  144. package/dist/val/FuncBaseVal.js.map +1 -1
  145. package/dist/val/GraphAtomVal.js +0 -15
  146. package/dist/val/GraphAtomVal.js.map +1 -1
  147. package/dist/val/HideFuncVal.js +0 -13
  148. package/dist/val/HideFuncVal.js.map +1 -1
  149. package/dist/val/IntegerVal.js +0 -61
  150. package/dist/val/IntegerVal.js.map +1 -1
  151. package/dist/val/JunctionVal.js +0 -20
  152. package/dist/val/JunctionVal.js.map +1 -1
  153. package/dist/val/KeyFuncVal.js +0 -46
  154. package/dist/val/KeyFuncVal.js.map +1 -1
  155. package/dist/val/ListVal.js +0 -57
  156. package/dist/val/ListVal.js.map +1 -1
  157. package/dist/val/LowerFuncVal.js +0 -11
  158. package/dist/val/LowerFuncVal.js.map +1 -1
  159. package/dist/val/MapVal.js +0 -151
  160. package/dist/val/MapVal.js.map +1 -1
  161. package/dist/val/MatchFuncVal.js +0 -27
  162. package/dist/val/MatchFuncVal.js.map +1 -1
  163. package/dist/val/{FormFuncVal.d.ts → MaybeFuncVal.d.ts} +5 -5
  164. package/dist/val/MaybeFuncVal.js +50 -0
  165. package/dist/val/MaybeFuncVal.js.map +1 -0
  166. package/dist/val/MoveFuncVal.js +0 -18
  167. package/dist/val/MoveFuncVal.js.map +1 -1
  168. package/dist/val/NilVal.js +0 -60
  169. package/dist/val/NilVal.js.map +1 -1
  170. package/dist/val/NomFuncVal.js +8 -42
  171. package/dist/val/NomFuncVal.js.map +1 -1
  172. package/dist/val/NumberVal.js +0 -15
  173. package/dist/val/NumberVal.js.map +1 -1
  174. package/dist/val/OpBaseVal.d.ts +1 -0
  175. package/dist/val/OpBaseVal.js +3 -15
  176. package/dist/val/OpBaseVal.js.map +1 -1
  177. package/dist/val/PackFuncVal.js +0 -34
  178. package/dist/val/PackFuncVal.js.map +1 -1
  179. package/dist/val/PathFuncVal.js +0 -6
  180. package/dist/val/PathFuncVal.js.map +1 -1
  181. package/dist/val/PathVal.js +0 -41
  182. package/dist/val/PathVal.js.map +1 -1
  183. package/dist/val/PlaceVal.js +0 -25
  184. package/dist/val/PlaceVal.js.map +1 -1
  185. package/dist/val/PlusOpVal.d.ts +1 -7
  186. package/dist/val/PlusOpVal.js +13 -74
  187. package/dist/val/PlusOpVal.js.map +1 -1
  188. package/dist/val/PrefFuncVal.js +0 -1
  189. package/dist/val/PrefFuncVal.js.map +1 -1
  190. package/dist/val/PrefVal.js +0 -167
  191. package/dist/val/PrefVal.js.map +1 -1
  192. package/dist/val/RecurseVal.js +0 -55
  193. package/dist/val/RecurseVal.js.map +1 -1
  194. package/dist/val/RefVal.js +0 -282
  195. package/dist/val/RefVal.js.map +1 -1
  196. package/dist/val/ReferFuncVal.js +0 -232
  197. package/dist/val/ReferFuncVal.js.map +1 -1
  198. package/dist/val/ScalarKindVal.js +0 -49
  199. package/dist/val/ScalarKindVal.js.map +1 -1
  200. package/dist/val/ScalarVal.js +0 -11
  201. package/dist/val/ScalarVal.js.map +1 -1
  202. package/dist/val/StrFuncVal.js +0 -18
  203. package/dist/val/StrFuncVal.js.map +1 -1
  204. package/dist/val/SuperFuncVal.js +0 -32
  205. package/dist/val/SuperFuncVal.js.map +1 -1
  206. package/dist/val/TopVal.js +0 -1
  207. package/dist/val/TopVal.js.map +1 -1
  208. package/dist/val/TranslateFuncVal.js +1 -3
  209. package/dist/val/TranslateFuncVal.js.map +1 -1
  210. package/dist/val/UpperFuncVal.js +0 -11
  211. package/dist/val/UpperFuncVal.js.map +1 -1
  212. package/dist/val/Val.d.ts +1 -0
  213. package/dist/val/Val.js +2 -133
  214. package/dist/val/Val.js.map +1 -1
  215. package/dist/val/VarVal.js +0 -12
  216. package/dist/val/VarVal.js.map +1 -1
  217. package/dist/val/arith.js +0 -37
  218. package/dist/val/arith.js.map +1 -1
  219. package/dist/val/caserange.js +0 -61
  220. package/dist/val/caserange.js.map +1 -1
  221. package/dist/val/members.js +0 -6
  222. package/dist/val/members.js.map +1 -1
  223. package/dist/val/numcmp.js +0 -11
  224. package/dist/val/numcmp.js.map +1 -1
  225. package/dist/val/numkind.js +0 -145
  226. package/dist/val/numkind.js.map +1 -1
  227. package/dist/val/valutil.js +0 -16
  228. package/dist/val/valutil.js.map +1 -1
  229. package/dist/vet.js +0 -461
  230. package/dist/vet.js.map +1 -1
  231. package/dist/view.js +0 -414
  232. package/dist/view.js.map +1 -1
  233. package/dist/walk.js +0 -41
  234. package/dist/walk.js.map +1 -1
  235. package/grammar/aontu.abnf +8 -6
  236. package/grammar/aontu.gbnf +4 -4
  237. package/grammar/aontu.lark +4 -4
  238. package/grammar/aontu.tmLanguage.json +1 -1
  239. package/package.json +4 -2
  240. package/src/agentsmd.ts +0 -35
  241. package/src/alias.ts +0 -39
  242. package/src/allow.ts +1 -96
  243. package/src/aontu.ts +3 -110
  244. package/src/aontumodel.ts +32 -0
  245. package/src/cli.ts +113 -682
  246. package/src/ctx.ts +0 -103
  247. package/src/diff.ts +0 -40
  248. package/src/err.ts +0 -40
  249. package/src/escape.ts +0 -46
  250. package/src/exactjson.ts +0 -131
  251. package/src/format.ts +14 -257
  252. package/src/grammar.ts +72 -0
  253. package/src/graph.ts +0 -61
  254. package/src/hcanon.ts +0 -82
  255. package/src/helpdoc.ts +1 -1
  256. package/src/hints.ts +66 -57
  257. package/src/jsonschema.ts +0 -123
  258. package/src/keyorder.ts +0 -42
  259. package/src/lang.ts +19 -931
  260. package/src/lower.ts +12 -62
  261. package/src/lsp-server.ts +0 -16
  262. package/src/lsp.ts +12 -180
  263. package/src/mcp-server.ts +0 -31
  264. package/src/mcp.ts +0 -130
  265. package/src/mod-tool.ts +0 -158
  266. package/src/mod.ts +0 -178
  267. package/src/patch.ts +0 -232
  268. package/src/provenance.ts +0 -183
  269. package/src/query.ts +0 -84
  270. package/src/reach.ts +0 -53
  271. package/src/relation.ts +0 -84
  272. package/src/render.ts +20 -172
  273. package/src/report-sarif.ts +0 -48
  274. package/src/sig.ts +0 -35
  275. package/src/sigdecl.ts +1 -1
  276. package/src/siggate.ts +0 -30
  277. package/src/site.ts +3 -29
  278. package/src/subsume.ts +1 -161
  279. package/src/template.ts +69 -140
  280. package/src/trim.ts +0 -53
  281. package/src/type.ts +2 -45
  282. package/src/unify.ts +13 -251
  283. package/src/utility.ts +0 -31
  284. package/src/val/AbnfFuncVal.ts +181 -0
  285. package/src/val/AbsentVal.ts +54 -0
  286. package/src/val/AggFuncVal.ts +152 -188
  287. package/src/val/ArithFuncVal.ts +0 -20
  288. package/src/val/BagVal.ts +1 -78
  289. package/src/val/BigDecimalVal.ts +0 -16
  290. package/src/val/BigIntegerVal.ts +0 -16
  291. package/src/val/CloseFuncVal.ts +0 -9
  292. package/src/val/CmpFuncVal.ts +4 -166
  293. package/src/val/ConjunctVal.ts +0 -33
  294. package/src/val/ConstraintVal.ts +2 -537
  295. package/src/val/ContainerKindVal.ts +0 -18
  296. package/src/val/CopyFuncVal.ts +0 -5
  297. package/src/val/Decimal.ts +1 -185
  298. package/src/val/DeprecateFuncVal.ts +0 -10
  299. package/src/val/DisjunctVal.ts +0 -157
  300. package/src/val/EachFuncVal.ts +0 -40
  301. package/src/val/EmitFuncVal.ts +8 -208
  302. package/src/val/ExpectVal.ts +0 -62
  303. package/src/val/FilterFuncVal.ts +0 -55
  304. package/src/val/FuncBaseVal.ts +9 -130
  305. package/src/val/GraphAtomVal.ts +0 -42
  306. package/src/val/HideFuncVal.ts +0 -15
  307. package/src/val/IntegerVal.ts +0 -61
  308. package/src/val/JunctionVal.ts +0 -20
  309. package/src/val/KeyFuncVal.ts +0 -48
  310. package/src/val/ListVal.ts +0 -59
  311. package/src/val/LowerFuncVal.ts +0 -12
  312. package/src/val/MapVal.ts +0 -151
  313. package/src/val/MatchFuncVal.ts +0 -59
  314. package/src/val/MaybeFuncVal.ts +86 -0
  315. package/src/val/MoveFuncVal.ts +0 -20
  316. package/src/val/NilVal.ts +0 -60
  317. package/src/val/NomFuncVal.ts +8 -95
  318. package/src/val/NumberVal.ts +0 -16
  319. package/src/val/OpBaseVal.ts +4 -17
  320. package/src/val/PackFuncVal.ts +0 -63
  321. package/src/val/PathFuncVal.ts +0 -32
  322. package/src/val/PathVal.ts +0 -66
  323. package/src/val/PlaceVal.ts +0 -45
  324. package/src/val/PlusOpVal.ts +18 -75
  325. package/src/val/PrefFuncVal.ts +0 -1
  326. package/src/val/PrefVal.ts +0 -179
  327. package/src/val/RecurseVal.ts +0 -81
  328. package/src/val/RefVal.ts +1 -285
  329. package/src/val/ReferFuncVal.ts +0 -255
  330. package/src/val/ScalarKindVal.ts +0 -50
  331. package/src/val/ScalarVal.ts +0 -12
  332. package/src/val/StrFuncVal.ts +0 -44
  333. package/src/val/SuperFuncVal.ts +0 -42
  334. package/src/val/TopVal.ts +0 -1
  335. package/src/val/TranslateFuncVal.ts +1 -51
  336. package/src/val/UpperFuncVal.ts +0 -12
  337. package/src/val/Val.ts +3 -192
  338. package/src/val/VarVal.ts +0 -15
  339. package/src/val/arith.ts +0 -92
  340. package/src/val/caserange.ts +0 -62
  341. package/src/val/members.ts +0 -23
  342. package/src/val/numcmp.ts +1 -27
  343. package/src/val/numkind.ts +0 -149
  344. package/src/val/valutil.ts +0 -16
  345. package/src/vet.ts +1 -582
  346. package/src/view.ts +0 -507
  347. package/src/walk.ts +0 -41
  348. package/dist/std.d.ts +0 -3
  349. package/dist/std.js +0 -672
  350. package/dist/std.js.map +0 -1
  351. package/dist/val/FormFuncVal.js +0 -55
  352. package/dist/val/FormFuncVal.js.map +0 -1
  353. package/dist/val/NamerFuncVal.d.ts +0 -12
  354. package/dist/val/NamerFuncVal.js +0 -176
  355. package/dist/val/NamerFuncVal.js.map +0 -1
  356. package/src/std.ts +0 -683
@@ -1,36 +1,5 @@
1
1
  /* Copyright (c) 2025 Richard Rodger, MIT License */
2
2
 
3
- /*
4
- * The constraint algebra's residual value (G1 phase 1: bounds and neq;
5
- * docs/reference-language.md, "The constraint algebra"). A
6
- * ConstraintVal is the normal form of any meet of Band A atoms over
7
- * one domain: an interval (endpoints with open/closed flags), an
8
- * exclusion set (from neq), and an optional numeric-leaf kind
9
- * narrowing (from meeting `integer` etc.). Its rules, decided in
10
- * phase 0 and mirrored by go/constraint.go:
11
- *
12
- * - Order is a property of the number line: a numeric bound admits
13
- * ANY numeric leaf at an admissible position, compared exactly
14
- * (numcmp.ts), and never narrows the peer's leaf by itself.
15
- * - Endpoints keep their written leaf (canon renders the stored
16
- * scalar); two endpoints at the SAME point keep the tower-lowest
17
- * leaf. No endpoint rewriting, ever (lazy endpoints).
18
- * - neq excludes by scalar identity — leaf AND value.
19
- * - Emptiness is decided eagerly where it is exact: empty interval,
20
- * integral gap under an integer/biginteger narrowing, point
21
- * deletion under a narrowed leaf, domain mixing. Representability
22
- * holes of the int64-window integer leaf are deliberately NOT
23
- * modelled (sound — no false conflicts; incomplete — those
24
- * contradictions surface against data), matching the algebra's
25
- * regex-approximation philosophy.
26
- * - Canonical atom order: kind, lower bound, upper bound, neq
27
- * (arguments sorted); `parse(canon(v)) == v` holds because the
28
- * reparse is a conjunct of atoms that normalises back to the
29
- * identical residual.
30
- *
31
- * A constraint violation raises the registered `constraint` code
32
- * (class conflict), with the admissible set in NilVal.details.
33
- */
34
3
 
35
4
  import type {
36
5
  Val,
@@ -92,7 +61,7 @@ type Bound = {
92
61
  }
93
62
 
94
63
  type ReAtom = {
95
- v: any // the stored pattern StringVal (canon renders the literal)
64
+ v: any
96
65
  src: string // the pattern text AS WRITTEN — canon and dedup use this,
97
66
  // never the normalised form, because canon round-trips
98
67
  // source and G6's hash will be taken over canon
@@ -115,7 +84,7 @@ type ConstraintState = {
115
84
  count?: ConstraintState // the COUNT residual (length()), itself a residual
116
85
  // over the integer domain -- the count atom reuses
117
86
  // this same algebra recursively
118
- uniq: boolean // members must be pairwise distinct (unique())
87
+ uniq: boolean
119
88
  uniqBy: string[] // ... and distinct ON EACH OF THESE KEYS
120
89
  // (unique(k)), sorted and deduplicated
121
90
  musts: MustAtom[] // Band B checks, kept in written order, never simplified
@@ -126,73 +95,6 @@ type ConstraintState = {
126
95
  }
127
96
 
128
97
 
129
- // THE PATTERN SUBSET, AND HOW IT IS ENFORCED (G1 phase 2; ADR-003).
130
- //
131
- // `re(p)` must mean the same thing in both engines and cost about the
132
- // same, and the two host engines guarantee neither: TypeScript compiles
133
- // with JavaScript's backtracking RegExp, Go with RE2 — a different
134
- // language in a different complexity class, over a different alphabet.
135
- //
136
- // The enforcement is NORMALISATION, not refusal (ADR-003). Every
137
- // construct whose expansion is engine-defined is rewritten here, by
138
- // this function, into an explicit form that cannot be read two ways;
139
- // only the rewritten pattern reaches a host engine. The alternative —
140
- // refusing everything that might differ — was tried first and leaked
141
- // three times, because its correctness depended on this comment knowing
142
- // every difference between two large engines.
143
- //
144
- // Aontu therefore DEFINES the abbreviations rather than inheriting
145
- // either host's. The definitions are deliberately the small ASCII ones,
146
- // because a config value containing U+00A0 is a mistake to catch, not a
147
- // space to accept silently:
148
- //
149
- // \d [0-9] \D [^0-9]
150
- // \w [0-9A-Za-z_] \W [^0-9A-Za-z_]
151
- // \s [ \t\n\r\f\v] \S [^ \t\n\r\f\v]
152
- // . [^\n]
153
- // \A ^ \z $
154
- //
155
- // Neither host agreed with all of these before rewriting: JavaScript's
156
- // \s also matches U+00A0 and other Unicode spaces, RE2's omits \v, and
157
- // the two `.` sets differ by \r and the Unicode line separators. After
158
- // rewriting, both engines see one explicit class and cannot disagree.
159
- //
160
- // What is still REFUSED, and why refusal is right for these:
161
- //
162
- // 1. Constructs one engine simply lacks — backreferences and
163
- // lookaround (not in RE2, and not expressible as regular
164
- // expressions at all), POSIX classes, `\p{...}`, `\x{...}`, `\u`.
165
- // There is nothing to normalise them TO.
166
- // 2. `(?` other than `(?:` — named groups are spelled differently
167
- // (`(?P<n>` in RE2, `(?<n>` in JavaScript) and inline flags change
168
- // the meaning of everything after them.
169
- // 3. A quantifier applied to a group containing a quantifier or an
170
- // alternation. This one is about TIME, not meaning: `(a+)+$`
171
- // against twenty-nine characters takes 45 SECONDS in JavaScript
172
- // and 0.065s under RE2, and a regex match is counted by no
173
- // evaluator budget, so an untrusted schema could otherwise stall
174
- // the TypeScript evaluator indefinitely (docs/trust.md clause 2).
175
- // Normalisation cannot fix a complexity difference; only owning the
176
- // matcher could, which ADR-003 records as the future option.
177
- //
178
- // The alphabet is fixed separately, by compiling with the `u` flag:
179
- // JavaScript otherwise matches UTF-16 code units where RE2 matches code
180
- // points, so `^.$` accepted U+1D11E in Go and refused it in TypeScript.
181
- //
182
- // This function is mirrored statement for statement in go/constraint.go,
183
- // and `test/spec/files/regex-corpus.txt` pins that the two produce
184
- // byte-identical output for every pattern in a generated corpus.
185
-
186
- // The largest repeat count Aontu's pattern language admits. RE2 caps a
187
- // repeat at 1000 and refuses to compile past it, where JavaScript's
188
- // backtracking engine accepts any count -- so `re("^a{1001}$")` was
189
- // VALID in TypeScript and an `error` verdict in Go, a cross-port
190
- // verdict flip on a schema an agent could be handed
191
- // (status-2026-08-21.md section 4). Under ADR-003 the host's own
192
- // compile failure must never be what a user sees, so the bound is
193
- // Aontu's: at most RE_REPEAT_MAX, refused identically in both ports
194
- // before either engine compiles. Nested products beyond the cap were
195
- // already refused, by the quantified-group rule below.
196
98
  const RE_REPEAT_MAX = 1000
197
99
 
198
100
  // The normative expansions. These are Aontu's definitions, not either
@@ -201,28 +103,12 @@ const RE_CLASS_DIGIT = '0-9'
201
103
  const RE_CLASS_WORD = '0-9A-Za-z_'
202
104
  const RE_CLASS_SPACE = ' \\t\\n\\r\\f\\v'
203
105
 
204
- // Metacharacters that may be escaped to mean themselves, in both
205
- // engines. `-` is handled separately: it is legal escaped only INSIDE a
206
- // character class, because RE2 accepts `a\-b` and JavaScript's unicode
207
- // mode makes it a syntax error.
208
106
  const RE_ESCAPE_PUNCT = '\\.+*?()[]{}|^$/'
209
107
 
210
108
  // Escapes passed through unchanged: the control characters, the ASCII
211
109
  // word boundary, and `\xHH`. Each was probed in both engines.
212
110
  const RE_ESCAPE_PASS = 'tnrfv'
213
111
 
214
- // A counted quantifier `{n}`, `{n,}` or `{n,m}` starting at `src[at]`.
215
- // Two rules, both about what the hosts do NOT share:
216
- //
217
- // - A bound above RE_REPEAT_MAX: RE2 refuses to compile it, JavaScript
218
- // accepts it.
219
- // - A brace that does not open a well-formed counted quantifier at
220
- // all (`x{y}`, `a{`, `{,5}`): JavaScript compiled with the `u` flag
221
- // makes it a SYNTAX ERROR, while RE2 reads it as a literal brace, so
222
- // `re("^x{y}$")` was `constraint_pattern` in TypeScript and a plain
223
- // unresolved value in Go -- the same class of verdict flip as the
224
- // repeat cap, found by sweeping around it. A literal brace is
225
- // written escaped (`a\\{1001\\}`), which both engines share.
226
112
  function repeatWhy(src: string, at: number): [string, number] {
227
113
  const bad = (what: string): [string, number] => [
228
114
  'a ' + what + ', which the two engines do not read the same way', -1]
@@ -367,10 +253,6 @@ function normaliseRe(src: string): [string, string] {
367
253
  let inClass = false
368
254
  const out: string[] = []
369
255
 
370
- // One frame per open group, recording whether it contains a quantifier
371
- // or an alternation. A group carrying either may not itself be
372
- // quantified; containment is transitive, so a frame hands its flags up
373
- // to its parent when it closes.
374
256
  const groups: { q: boolean, alt: boolean }[] = []
375
257
  const mark = (k: 'q' | 'alt') => {
376
258
  if (0 < groups.length) {
@@ -395,14 +277,6 @@ function normaliseRe(src: string): [string, string] {
395
277
  return ['', why]
396
278
  }
397
279
  out.push(emit)
398
- // `\b` AND `\B` ARE ASSERTIONS TOO, and quantifying one is the
399
- // same disagreement `^{1}` is: JavaScript under `u` calls it a
400
- // syntax error, RE2 quantifies the assertion happily. The rule
401
- // said "`\b` and `\B` quantify identically in both and are left
402
- // alone" and that was measured wrong -- `re("\\b{1}x")` is
403
- // `constraint_pattern` in TypeScript and an accepted schema in
404
- // Go. Only OUTSIDE a class: inside one, `\b` is a backspace in
405
- // both engines and repeats like any other character.
406
280
  if (!inClass && ('b' === src[i + 1] || 'B' === src[i + 1])) {
407
281
  anchorPrev = true
408
282
  }
@@ -410,9 +284,6 @@ function normaliseRe(src: string): [string, string] {
410
284
  continue
411
285
  }
412
286
 
413
- // A POSIX class opener, anywhere: the form lives inside an ordinary
414
- // class (`[[:alpha:]]`), and refusing it everywhere is one rule
415
- // rather than two.
416
287
  if ('[' === c && ':' === src[i + 1]) {
417
288
  return ['', 'a POSIX class ([:...:]), which JavaScript does not have']
418
289
  }
@@ -482,12 +353,6 @@ function normaliseRe(src: string): [string, string] {
482
353
  }
483
354
 
484
355
  if ('*' === c || '+' === c || '?' === c || '{' === c) {
485
- // Nothing to repeat. JavaScript under the `u` flag makes this a
486
- // SYNTAX ERROR, where RE2 quantifies the assertion happily and
487
- // matches, so `re("^{1}")` was `constraint_pattern` in
488
- // TypeScript and an accepted schema in Go. The four assertions
489
- // behave alike here -- `^`, `$`, `\b` and `\B` -- so the rule
490
- // names all four.
491
356
  if (afterAnchor) {
492
357
  return ['', 'a quantifier applied to `^`, `$`, `\\b` or ' +
493
358
  '`\\B`, which has nothing to repeat']
@@ -504,10 +369,6 @@ function normaliseRe(src: string): [string, string] {
504
369
  continue
505
370
  }
506
371
 
507
- // A `}` that closes no counted quantifier: JavaScript under `u`
508
- // refuses it as a lone quantifier bracket, RE2 reads it as a
509
- // literal. Written escaped inside a class (`[}]`) it is a literal
510
- // in both, which is the spelling that survives.
511
372
  if ('}' === c) {
512
373
  if (i !== repeatEnd) {
513
374
  return ['', 'a `}` that closes no counted quantifier, which ' +
@@ -544,20 +405,11 @@ function stringLeaf(v: any): boolean {
544
405
  return true === v?.isScalar && 'string' === typeof v.peg && v.isString
545
406
  }
546
407
 
547
- // The VALUE-admission widening of stringLeaf: a path value is a string
548
- // with more structure (path <: string, ADR-016), so the string-domain
549
- // constraints admit one -- `refer() & re("auth$")` must still check a
550
- // link whose value is now a path. The ARGUMENT sites keep the strict
551
- // test: a pattern, a bound or an exclusion is spelled with a plain
552
- // string, never a path.
553
408
  function stringishLeaf(v: any): boolean {
554
409
  return stringLeaf(v) || (true === v?.isScalar && true === v.isPath)
555
410
  }
556
411
 
557
412
 
558
- // Scalar identity: leaf AND value, the lattice's own rule (1 and 1.0
559
- // are different scalars). Exact numeric comparison decides the value
560
- // half for numeric leaves.
561
413
  function sameScalar(a: any, b: any): boolean {
562
414
  if (numericLeaf(a) && numericLeaf(b)) {
563
415
  return towerRank(a) === towerRank(b) && 0 === cmpNumeric(a, b)
@@ -589,20 +441,6 @@ function leafMarker(v: any): any {
589
441
  }
590
442
 
591
443
 
592
- // Conjunct sort order for an atom that must see the WHOLE value.
593
- // Every other value sorts below the container default (99999), so such
594
- // an atom is the LAST term to fold: `a:length(2) a:{x:1} a:{y:2}` must
595
- // count the MERGED map, and a constraint that folded at 50000 would
596
- // count `{x:1}` alone and refuse the layering that is the whole point
597
- // of the language.
598
- //
599
- // The order atoms keep the low slot: `min(2) & 1 & 2` may decide as
600
- // soon as it sees a scalar, because meeting more scalars can only
601
- // narrow. Meeting more containers GROWS the member set, which is why
602
- // the two orders differ.
603
- //
604
- // Three atoms are late: `length` and `unique` (they count members), and
605
- // `must` (an evaluate-only check against the finished value).
606
444
  const LATE_CJO = 150000
607
445
 
608
446
  function lateAtom(atom: string): boolean {
@@ -655,16 +493,6 @@ class ConstraintVal extends FeatureVal {
655
493
  }
656
494
  else if (spec.atom) {
657
495
  const args = atomArgs(spec.atom, (spec.peg as any[]) ?? [])
658
- // An argument that is not yet concrete — a reference, an
659
- // arithmetic expression, a conjunct of atoms — makes the whole
660
- // atom PENDING rather than invalid (G1 phase 4). It is resolved
661
- // in unify, where there is a ctx to resolve through, and the
662
- // residual is built from the settled arguments. Only a settled
663
- // argument of the wrong shape is an `invalid-arg`.
664
- // The effectful-argument refusal happens HERE, on the written
665
- // form, and not in fromAtom: settling is what runs the effect, so
666
- // by the time fromAtom sees a settled `move($.b)` the move has
667
- // already happened and the argument is just its result.
668
496
  if ('must' === spec.atom && args.some((a: any) => holdsMove(a))) {
669
497
  this.invalid = 'invalid-arg'
670
498
  }
@@ -694,27 +522,11 @@ class ConstraintVal extends FeatureVal {
694
522
  }
695
523
 
696
524
 
697
- // Normalise one atom call into state. Every argument here is already
698
- // SETTLED — the constructor routes an unsettled one to `pending` —
699
- // so a shape this cannot use is a genuine `invalid-arg`, not a
700
- // not-yet.
701
525
  private fromAtom(atom: string, args: any[]): void {
702
- // Mark the residual invalid. It answers NOTHING: every caller
703
- // spells its exit `return bad(...)` and none reads a value, so a
704
- // return type would be a value nobody consumes -- and a routine
705
- // that answers on some paths and not others is the shape a reader
706
- // (and a static analyser) has to stop and check.
707
526
  const bad = (why: string): void => {
708
527
  this.invalid = why
709
528
  }
710
529
 
711
- // `unique()` is a property of the container -- not a comparison
712
- // against a value -- so with no argument it says the members are
713
- // pairwise DISTINCT. THE ONE ARGUMENT IS A PROJECTOR (the review's
714
- // finding I: "unique()-by-field is reserved but absent", and the
715
- // arity was reserved for exactly this): `unique(port)` says no two
716
- // members share a `port`, which is how "no two services share a
717
- // port" and "event ids are unique" are said.
718
530
  if ('unique' === atom) {
719
531
  if (0 === args.length) {
720
532
  this.uniq = true
@@ -727,12 +539,6 @@ class ConstraintVal extends FeatureVal {
727
539
  return
728
540
  }
729
541
 
730
- // `must(c, msg)` is Band B: an evaluate-only check against the
731
- // finished value, carrying the author's own message. It is KEPT,
732
- // never simplified and never consulted for emptiness or
733
- // subsumption — Band B is opaque by construction, which is exactly
734
- // what makes it the honest channel for a rule the algebra cannot
735
- // reason about (docs/reference-language.md, "Band B: `must`").
736
542
  if ('must' === atom) {
737
543
  if (2 !== args.length) {
738
544
  return bad('arg')
@@ -740,11 +546,6 @@ class ConstraintVal extends FeatureVal {
740
546
  if (!stringLeaf(args[1])) {
741
547
  return bad('invalid-arg')
742
548
  }
743
- // A check carrying a nil can never be satisfied, so it is refused
744
- // as an ARGUMENT rather than left to fail against every value with
745
- // the author's message attached -- which would blame the data for
746
- // a mistake in the check. `must([1-x],m)` is the reachable case: a
747
- // degenerate expression leaves a nil inside the written list.
748
549
  if (holdsNil(args[0])) {
749
550
  return bad('invalid-arg')
750
551
  }
@@ -785,8 +586,6 @@ class ConstraintVal extends FeatureVal {
785
586
  return bad('invalid-arg')
786
587
  }
787
588
  const src = a.peg as string
788
- // Normalise BEFORE compiling: the host engines only ever see a
789
- // pattern that cannot be read two ways (ADR-003).
790
589
  const [norm, why] = normaliseRe(src)
791
590
  if ('' !== why) {
792
591
  this.invalidWhy = why
@@ -794,23 +593,9 @@ class ConstraintVal extends FeatureVal {
794
593
  }
795
594
  let re: RegExp
796
595
  try {
797
- // The `u` flag is REQUIRED for parity, not an optimisation.
798
- // Without it JavaScript matches UTF-16 code units while RE2
799
- // matches code points, so `re("^.$")` accepted U+1D11E in Go
800
- // and refused it in TypeScript (and `^..$` did the reverse).
801
- // With it, `.` and every quantifier count code points in both.
802
- // It also makes JavaScript refuse the identity escapes this
803
- // scanner rejects by hand, which is defence in depth rather
804
- // than a substitute: RE2 accepts some of them, so the scanner
805
- // is what keeps the two ports agreeing.
806
596
  re = new RegExp(norm, 'u')
807
597
  }
808
598
  catch (e: any) {
809
- // The host engine refuses what the subset scanner passed — a
810
- // malformed quantifier, an unbalanced group. Same refusal under
811
- // the same code: the author gets one rule, not two. The message
812
- // is the host's, so it is NOT pinned by a shared row; the code
813
- // and the located frame are.
814
599
  this.invalidWhy = 'not a valid pattern'
815
600
  return bad('constraint_pattern')
816
601
  }
@@ -819,16 +604,6 @@ class ConstraintVal extends FeatureVal {
819
604
  return
820
605
  }
821
606
 
822
- // `length` is the other non-ORDER atom: its argument constrains the
823
- // COUNT, not the value, so it is itself a residual over the integer
824
- // domain (docs/reference-language.md, "`length` semantics"). It is
825
- // resolved HERE, at construction, by walking the written argument
826
- // rather than by unifying it: the func-paren handler builds atoms
827
- // without an AontuContext, so there is nothing to fold a nested
828
- // conjunct through. Walking is enough because a length argument is by
829
- // definition a meet of concrete Band A atoms; anything else (a
830
- // reference, an expression) is refused rather than deferred, the
831
- // same discipline min/max apply to their own arguments.
832
607
  if ('length' === atom) {
833
608
  const arg = countArgState(a)
834
609
  if (null == arg) {
@@ -868,15 +643,6 @@ class ConstraintVal extends FeatureVal {
868
643
  // residual is stable and the ladder is total.
869
644
  let out: Val
870
645
 
871
- // A rel residual or a graph atom HOLDS constraints for the value
872
- // they stand for (RELATIONS P1/P2): hand the drive over before
873
- // any settling, exactly as a container does, so `rel(t) & re(x)`
874
- // reads the same in either order. Reached through the INCLUDE
875
- // flow (a loaded schema's conjunct re-drives with the constraint
876
- // on the left) -- inline documents route rel/atom peers through
877
- // unite's b-drives first, which is why use-cases/12-relations
878
- // refused without this arm while every inline row stayed green;
879
- // pinned by constraint-hands-drive-to-rel-and-atom.
880
646
  if (true === (peer as any)?.isRel
881
647
  || true === (peer as any)?.isGraphAtom) {
882
648
  out = (peer as any).unify(this, ctx)
@@ -908,15 +674,6 @@ class ConstraintVal extends FeatureVal {
908
674
  }
909
675
  /* node:coverage ignore next 12 */
910
676
  else {
911
- // Every other shape: no order, no membership, nothing to count —
912
- // a conflict of the constraint family. The ladder above is total
913
- // in practice: every remaining Val kind either sorts BELOW a
914
- // constraint in a conjunct (conjunct, disjunct, pref, ref) and so
915
- // drives the meet from its own side, or resolves to a
916
- // scalar/container before a constraint sees it (func, op, var,
917
- // expect). The arm is kept because "in practice" depends on the
918
- // cjo table, and a future value class would land here rather than
919
- // falling out of unify with no result.
920
677
  out = this.fail(ctx, peer)
921
678
  }
922
679
 
@@ -926,17 +683,6 @@ class ConstraintVal extends FeatureVal {
926
683
  }
927
684
 
928
685
 
929
- // Resolve a pending atom's arguments and, once they have all settled,
930
- // become the residual they describe (G1 phase 4).
931
- //
932
- // This is the residuation discipline FuncBaseVal already follows for
933
- // its own operands: push each unsettled argument one step by unifying
934
- // it with `top`, and if any is still moving, mark not-done and defer
935
- // — either as this same pending atom (against a `top` peer) or
936
- // wrapped with the peer in a conjunct the next pass will re-enter.
937
- // Nothing is decided from a half-resolved argument, which is what
938
- // keeps `min($.lo)` from reporting a conflict against a bound that
939
- // has not arrived yet.
940
686
  private settle(peer: Val, ctx: AontuContext): Val {
941
687
  const TOP = top()
942
688
  const pend = this.pending as { atom: string, args: any[] }
@@ -946,9 +692,6 @@ class ConstraintVal extends FeatureVal {
946
692
  for (const arg of pend.args) {
947
693
  let next = arg
948
694
  if (true !== arg?.done) {
949
- // Charged to the depth budget: this recurses without going
950
- // through `unite`, so the counter would otherwise stay flat
951
- // while the stack grows (the rule FuncBaseVal follows).
952
695
  next = withDepth(ctx, arg, TOP, () => arg.unify(TOP, ctx))
953
696
  }
954
697
  settled = settled && true === next?.done
@@ -1001,9 +744,6 @@ class ConstraintVal extends FeatureVal {
1001
744
  return this.fail(ctx, peer)
1002
745
  }
1003
746
  if (null != this.count) {
1004
- // Only a string among the scalars has a length, and it is counted
1005
- // in CODE POINTS -- not UTF-16 units (this host's native count)
1006
- // and not bytes (Go's). Iterating a string yields code points.
1007
747
  if (!stringishLeaf(peer)) {
1008
748
  return this.fail(ctx, peer)
1009
749
  }
@@ -1022,31 +762,11 @@ class ConstraintVal extends FeatureVal {
1022
762
  }
1023
763
 
1024
764
 
1025
- // Band B, applied to a finished value. Each check is a plain
1026
- // unification against a CLONE of the peer: `must` reports, it never
1027
- // contributes: whatever the check would have added to the value is
1028
- // discarded, and `peer` is returned untouched by the callers.
1029
- //
1030
- // The trial runs in an isolated collect context so a failing check
1031
- // leaves nothing on the caller's error list — only the located nil
1032
- // this returns, carrying the author's own message.
1033
- // `final` is the generation-time reading (see settleContainer): a
1034
- // must whose own check is a SIZING atom inherits that atom's
1035
- // provisionality, because `must(length(2), …)` against a map that may
1036
- // still gain members has not failed yet -- it has not been answered.
1037
- // Without this the must would decide against whatever the container
1038
- // held when it first settled, which is the very defect the sizing
1039
- // atoms were fixed for (use-cases/BUGS.md §16, §17).
1040
765
  private checkMusts(
1041
766
  peer: any, ctx: AontuContext, final?: boolean): Val | undefined {
1042
767
  for (const m of this.musts) {
1043
768
  const trial = ctx.clone({ err: [], collect: true })
1044
769
  let got: any = unite(trial, m.v.clone(trial), peer.clone(trial), 'must')
1045
- // A must whose check is a SIZING atom answers a residue rather
1046
- // than a verdict, because the atom is waiting for members that
1047
- // may still arrive. Before generation that residue IS the answer
1048
- // -- the must has not failed, it has not been asked yet -- and at
1049
- // generation it is settled, because nothing more can arrive.
1050
770
  const residue = sizingResidue(got)
1051
771
  if (undefined !== residue) {
1052
772
  if (true !== final) {
@@ -1066,27 +786,11 @@ class ConstraintVal extends FeatureVal {
1066
786
  }
1067
787
 
1068
788
 
1069
- // THE FINAL READING of a sizing atom over a container: the same
1070
- // checks admitContainer makes, with the provisional ones taken as
1071
- // decided. Called from ConjunctVal.gen, which is where no more
1072
- // members can arrive. Returns the container (to generate) or the
1073
- // constraint's own nil (to report).
1074
789
  settleContainer(peer: any, ctx: AontuContext): Val {
1075
790
  return this.admitContainer(peer, ctx, true)
1076
791
  }
1077
792
 
1078
793
 
1079
- // Membership for a container peer. Only the SIZING atoms have anything
1080
- // to say about a map or a list; every other atom is scalar-domain and
1081
- // refuses one.
1082
- //
1083
- // The members that count are the members that GENERATE
1084
- // (docs/reference-language.md, "`length` semantics"), and rather than
1085
- // mirror generation's filter — type/hide marks, optional keys that
1086
- // drop, empty optional values — this asks generation itself, in an
1087
- // isolated collect context so nothing leaks into the caller's errors.
1088
- // A mirror would be a second copy of a filter that has already grown
1089
- // subtle, free to drift from it; asking is correct by construction.
1090
794
  private admitContainer(
1091
795
  peer: any, ctx: AontuContext, final?: boolean): Val {
1092
796
  // A scalar-domain residual has no reading over a container.
@@ -1106,13 +810,6 @@ class ConstraintVal extends FeatureVal {
1106
810
  return bad
1107
811
  }
1108
812
 
1109
- // A MUST OVER A CONTAINER RESIDUATES with the atoms, for the same
1110
- // reason (use-cases/BUGS.md §17): `must({t: max(60)}, …)` beside a
1111
- // `{t: integer}` schema was answered against the schema layer
1112
- // ALONE, and discharged before the data it was written to judge
1113
- // ever arrived. It is decided at generation, where the value is
1114
- // whole -- unless there is nothing else on the constraint AND the
1115
- // reading is already final.
1116
813
  if (!this.uniq && 0 === this.uniqBy.length && null == this.count) {
1117
814
  if (true === final || 0 === this.musts.length) {
1118
815
  return peer
@@ -1122,43 +819,12 @@ class ConstraintVal extends FeatureVal {
1122
819
 
1123
820
  const members = emittedMembers(peer, ctx)
1124
821
  if (null == members) {
1125
- // NOT COUNTABLE YET IS NOT A PASS. A container that cannot
1126
- // generate cannot be counted, and a SCHEMA is exactly that: the
1127
- // members of `{a: integer}` are types, so nothing is emitted and
1128
- // nothing can be counted. Discharging the atom here was the §16
1129
- // defect wearing its other face -- `length(min(2)) & {a: integer}`
1130
- // dropped its bound while still alone, so the data half of a
1131
- // `vet` meet was never measured at all and short data vetted
1132
- // clean against a bound the evaluator enforces.
1133
- //
1134
- // At generation the reading IS final: a container that still
1135
- // cannot generate has its own error, and that error is the one
1136
- // worth reporting, so it passes through untouched.
1137
822
  if (true === final) {
1138
823
  return peer
1139
824
  }
1140
825
  return this.hold(peer, ctx)
1141
826
  }
1142
827
 
1143
- // MONOTONE READINGS ONLY (the review's finding C, use-cases/BUGS.md
1144
- // §16). Members ACCUMULATE under unification -- a meet adds keys and
1145
- // never removes them -- so a settled container is settled ON ITS
1146
- // OWN and not against every value that may still contribute. The
1147
- // schema half of a `vet` meet, a document that is about to receive
1148
- // an `@` include, a bag a later `pack` will fill: each settles, and
1149
- // an atom that decided there decided too early.
1150
- //
1151
- // So a verdict is taken only when MORE MEMBERS CANNOT CHANGE IT:
1152
- // - an upper bound VIOLATED is permanent -> refuse now;
1153
- // satisfied is provisional -> keep the atom, re-check later.
1154
- // - a lower bound SATISFIED is permanent -> that part may go;
1155
- // violated is provisional -> keep the atom (which is why
1156
- // `length(min(1))` beside a template no longer kills the schema
1157
- // it was written for).
1158
- // - a DUPLICATE is permanent -> refuse now; distinctness is
1159
- // provisional -> keep the atom.
1160
- // Anything provisional residuates, exactly as an unsettled
1161
- // container does above, and the two spellings then agree.
1162
828
  const count = null == this.count ? undefined : this.count
1163
829
  const n = members.length
1164
830
  if (null != count) {
@@ -1179,11 +845,6 @@ class ConstraintVal extends FeatureVal {
1179
845
  }
1180
846
 
1181
847
  if (this.uniq) {
1182
- // Members compare by CANONICAL FORM, which reduces to scalar
1183
- // identity for scalars (so [1, 1.0] is distinct) and gives
1184
- // structural equality for container members without a second
1185
- // rule. A generated value could not express the first: `1` and
1186
- // `1.0` generate the same JSON number.
1187
848
  const seen = new Set<string>()
1188
849
  for (const m of members) {
1189
850
  const key = m.canon
@@ -1194,10 +855,6 @@ class ConstraintVal extends FeatureVal {
1194
855
  }
1195
856
  }
1196
857
 
1197
- // ... and the same test per PROJECTED key. A member that has no such
1198
- // key FAILS the constraint rather than being skipped: distinctness
1199
- // it cannot be shown to have is distinctness it does not have, and
1200
- // skipping would let one keyless record hide a duplicate.
1201
858
  for (const field of this.uniqBy) {
1202
859
  const seen = new Set<string>()
1203
860
  for (const m of members) {
@@ -1225,32 +882,10 @@ class ConstraintVal extends FeatureVal {
1225
882
  if (spent) {
1226
883
  return peer
1227
884
  }
1228
- // DONE, unlike the unsettled case above. The container HAS settled;
1229
- // the atom is kept only because a LATER value could still add
1230
- // members, and a residue that reported itself unresolved would
1231
- // leave every enclosing value unresolved with it -- a `type()`
1232
- // waiting on its argument for ever, and use case 09's whole
1233
- // registry with it.
1234
- // The ATOM is done too, not just the conjunct. An earlier pass may
1235
- // have set `dc = 0` on the unsettled branch above, and a conjunct
1236
- // recomputes its own doneness from its terms on every later meet --
1237
- // so a stale 0 here would drag the residue, and every value holding
1238
- // it, back to unresolved for ever.
1239
885
  return this.hold(peer, ctx)
1240
886
  }
1241
887
 
1242
888
 
1243
- // The atom kept on a value whose reading is still provisional.
1244
- // DONE, unlike the unsettled container above: the value HAS settled;
1245
- // the atom is kept only because a LATER value could still add
1246
- // members, and a residue that reported itself unresolved would leave
1247
- // every enclosing value unresolved with it -- a `type()` waiting on
1248
- // its argument for ever, and use case 09's whole registry with it.
1249
- // The ATOM is done too, not just the conjunct. An earlier pass may
1250
- // have set `dc = 0` on the unsettled branch, and a conjunct
1251
- // recomputes its own doneness from its terms on every later meet --
1252
- // so a stale 0 here would drag the residue, and every value holding
1253
- // it, back to unresolved for ever.
1254
889
  private hold(peer: any, ctx: AontuContext): Val {
1255
890
  this.dc = DONE
1256
891
  const held: any = new ConjunctVal({ peg: [this, peer] }, ctx)
@@ -1259,16 +894,6 @@ class ConstraintVal extends FeatureVal {
1259
894
  }
1260
895
 
1261
896
 
1262
- // Meet with a kind: `number` (or `string` on the string domain) is
1263
- // already implied by an ORDER atom's argument; a numeric LEAF narrows
1264
- // the residual; anything else has an empty intersection with the
1265
- // constraint's domain.
1266
- //
1267
- // A sizing residual (`length`, `unique`) has no domain of its own -- a
1268
- // count says nothing about what is counted -- so a kind here SETS one
1269
- // rather than merely agreeing with it: `string & length(3)` is a
1270
- // three-character string, and `number & length(3)` is empty because a
1271
- // number has no length (stateEmpty decides that, not this).
1272
897
  private meetKind(peer: any, ctx: AontuContext): Val {
1273
898
  const marker = peer.peg
1274
899
  const merged = this.cloneState()
@@ -1328,14 +953,7 @@ class ConstraintVal extends FeatureVal {
1328
953
  null == peer.count ? this.count : meetCount(this.count, peer.count)
1329
954
  // `unique()` is idempotent: two of them are one.
1330
955
  merged.uniq = this.uniq || peer.uniq
1331
- // `unique(a) & unique(b)` is BOTH, not the later one: each names a
1332
- // key on which the members must differ, and dropping either would
1333
- // silently weaken the constraint. Sorted and deduplicated, so the
1334
- // meet is commutative and `unique(a) & unique(a)` is one atom.
1335
956
  merged.uniqBy = [...new Set([...this.uniqBy, ...peer.uniqBy])].sort()
1336
- // Band B checks accumulate in written order and are never merged,
1337
- // deduplicated or reordered: each carries its own author message,
1338
- // and two checks with the same shape may still say different things.
1339
957
  merged.musts = [...this.musts, ...peer.musts]
1340
958
 
1341
959
  return this.finish(merged, ctx, peer)
@@ -1353,10 +971,6 @@ class ConstraintVal extends FeatureVal {
1353
971
  out.site.row = this.site.row
1354
972
  out.site.col = this.site.col
1355
973
  out.site.url = this.site.url
1356
- // Marks ratchet across a meet (the propagateMarks rule): a fresh
1357
- // residual must carry both operands' type/hide marks, or a
1358
- // `type(min(0)) & max(10)` merge would silently unmark the field
1359
- // (the Go fold re-ratchets from its terms; this is the TS twin).
1360
974
  propagateMarks(this, out)
1361
975
  propagateMarks(peer, out)
1362
976
  return out
@@ -1432,9 +1046,6 @@ class ConstraintVal extends FeatureVal {
1432
1046
  }
1433
1047
 
1434
1048
 
1435
- // The tighter of two like-direction bounds: the higher lower bound (or
1436
- // lower upper bound); on the same point the OPEN bound wins, and on a
1437
- // full tie the tower-lowest endpoint spelling survives.
1438
1049
  function tighter(
1439
1050
  domain: 'number' | 'string',
1440
1051
  a: Bound | undefined,
@@ -1475,13 +1086,6 @@ function dedupSorted(domain: 'number' | 'string', neqs: any[]): any[] {
1475
1086
  }
1476
1087
 
1477
1088
 
1478
- // Is this value, or anything inside it, a nil? A written argument that
1479
- // holds one can never be satisfied, so the atom refuses it as an
1480
- // argument rather than reporting a mystery failure against every peer.
1481
- // Every caller passes a Val: `args[0]` comes from atomArgs, and the
1482
- // walk below descends only into container pegs, which hold Vals. The
1483
- // null/non-Val guard this function used to open with was therefore
1484
- // unreachable, and the coverage gate said so.
1485
1089
  function holdsNil(v: any): boolean {
1486
1090
  if (true === v.isNil) {
1487
1091
  return true
@@ -1501,12 +1105,6 @@ function holdsNil(v: any): boolean {
1501
1105
  }
1502
1106
 
1503
1107
 
1504
- // Whether a value, or anything inside it, is an effectful call — one
1505
- // whose evaluation changes a node OTHER than the one being computed.
1506
- // `move()` is the only builtin that does: it hides its resolution
1507
- // target in place. Band B refuses one as an argument, because settling
1508
- // it runs the effect against the live root before `must`'s trial clone
1509
- // is taken, and a check that mutates cannot be report-only.
1510
1108
  function holdsMove(v: any): boolean {
1511
1109
  if (true === v.isFunc && 'move' === v.funcname?.()) {
1512
1110
  return true
@@ -1526,15 +1124,6 @@ function holdsMove(v: any): boolean {
1526
1124
  }
1527
1125
 
1528
1126
 
1529
- // The written arguments of an atom, flattened.
1530
- //
1531
- // A multi-argument call arrives from the func-paren grammar as ONE
1532
- // entry holding the comma group, and `neq([3,1,2])` means the same as
1533
- // `neq(3,1,2)`. The group is always a ListVal by the time it reaches
1534
- // here -- the func-paren handler rawToVals every argument (issue #49) --
1535
- // so there is no raw-array case to unwrap. Flattening happens before
1536
- // the settled check, because an unsettled member hiding inside the
1537
- // group would otherwise make the atom look ready.
1538
1127
  function atomArgs(atom: string, args: any[]): any[] {
1539
1128
  if (('neq' === atom || 'must' === atom) && 1 === args.length &&
1540
1129
  true === (args[0] as any)?.isList) {
@@ -1544,19 +1133,11 @@ function atomArgs(atom: string, args: any[]): any[] {
1544
1133
  }
1545
1134
 
1546
1135
 
1547
- // The canonical rendering of a residual, in the fixed atom order:
1548
- // kind, lower bound, upper bound, neq, re, length, unique. Taken over the
1549
- // STATE rather than the Val because `length`'s argument is a residual too,
1550
- // and renders by exactly the same rules.
1551
1136
  function canonState(s: ConstraintState): string {
1552
1137
  const parts: string[] = []
1553
1138
  if (null != s.kind) {
1554
1139
  parts.push((s.kind as any).name.toLowerCase())
1555
1140
  }
1556
- // An ORDER atom's argument implies the domain, so it is not spelled
1557
- // out. A SIZING residual carries no order, and there `string` is the
1558
- // only thing saying what is being sized -- drop it and the reparse
1559
- // would admit lists and maps too.
1560
1141
  else if ('string' === s.domain &&
1561
1142
  null == s.lo && null == s.hi && 0 === s.neqs.length && 0 === s.res.length) {
1562
1143
  parts.push('string')
@@ -1574,19 +1155,11 @@ function canonState(s: ConstraintState): string {
1574
1155
  parts.push('re(' + r.v.canon + ')')
1575
1156
  }
1576
1157
  if (null != s.count) {
1577
- // Rendered UNABRIDGED, implied parts and all: `length(3)` canonicalises
1578
- // to `length(integer&min(3)&max(3))` because that IS the residual the
1579
- // count must satisfy, and canon is a normal form (G6 hashes it),
1580
- // not a pretty-printer. Abbreviating would mean a second set of
1581
- // rules for when the implied `integer & min(0)` may be dropped.
1582
1158
  parts.push('length(' + canonState(s.count) + ')')
1583
1159
  }
1584
1160
  if (s.uniq) {
1585
1161
  parts.push('unique()')
1586
1162
  }
1587
- // After the bare atom, and sorted: canon is a normal form, so two
1588
- // documents writing the same keys in different orders must render
1589
- // the same string.
1590
1163
  for (const key of s.uniqBy) {
1591
1164
  parts.push('unique(' + JSON.stringify(key) + ')')
1592
1165
  }
@@ -1601,15 +1174,6 @@ function canonState(s: ConstraintState): string {
1601
1174
  }
1602
1175
 
1603
1176
 
1604
- // SUBSUMPTION over two residuals (G3, the query built on the table in
1605
- // docs/reference-language.md "Subsumption"): does every value `s`
1606
- // admits pass `g` too? Implemented here because the compare machinery
1607
- // (cmpVal, sameScalar, the recursive count state) is this module's.
1608
- //
1609
- // Three-valued: true / false / 'undecided'. `must` on the GENERAL side
1610
- // is undecided by construction (a Band B predicate is opaque — G3 maps
1611
- // the table's "never" to the query's honest sub_evaluate_only); every
1612
- // other approximation folds toward false, the safe direction.
1613
1177
  function constraintStateSubsumes(
1614
1178
  g: {
1615
1179
  domain?: 'number' | 'string', kind?: any, lo?: Bound, hi?: Bound,
@@ -1683,11 +1247,6 @@ function constraintStateSubsumes(
1683
1247
  }
1684
1248
  }
1685
1249
 
1686
- // `unique()` subsumes only itself on that axis: a general uniqueness
1687
- // demand admits no container the unconstrained specific also admits.
1688
- // ... and a general `unique(k)` needs the same key on the specific
1689
- // side: distinctness on `port` says nothing about distinctness on
1690
- // `name`.
1691
1250
  if (g.uniqBy.some((k: string) => !s.uniqBy.includes(k))) {
1692
1251
  return false
1693
1252
  }
@@ -1723,9 +1282,6 @@ function constraintAdmitsScalar(
1723
1282
  if (g.uniq || 0 < g.uniqBy.length) {
1724
1283
  return false
1725
1284
  }
1726
- // A count residual admits by LENGTH, which is the meet's business;
1727
- // the query answers false (the safe direction) rather than
1728
- // reimplementing the sizing walk here.
1729
1285
  if (null != (g as any).count) {
1730
1286
  return false
1731
1287
  }
@@ -1733,10 +1289,6 @@ function constraintAdmitsScalar(
1733
1289
  }
1734
1290
 
1735
1291
 
1736
- // Does this residual's ORDER and MEMBERSHIP part admit the scalar? The
1737
- // sizing atoms are deliberately not consulted: `admit` applies them to
1738
- // the peer's length, and the count check applies this same function to
1739
- // the count.
1740
1292
  function stateAdmits(s: ConstraintState, peer: any): boolean {
1741
1293
  const domainOf = numericLeaf(peer) ? 'number' :
1742
1294
  stringishLeaf(peer) ? 'string' : undefined
@@ -1774,10 +1326,6 @@ function stateAdmits(s: ConstraintState, peer: any): boolean {
1774
1326
  return false
1775
1327
  }
1776
1328
  }
1777
- // Every accumulated pattern must match: the meet of two `re` atoms
1778
- // is conjunction, and matching is UNANCHORED in both engines
1779
- // (JS RegExp.test, Go regexp.MatchString), so `re("el")` admits
1780
- // "hello". Anchor with ^ and $ to mean the whole string.
1781
1329
  for (const r of s.res) {
1782
1330
  if (!r.re.test(peer.peg)) {
1783
1331
  return false
@@ -1787,13 +1335,7 @@ function stateAdmits(s: ConstraintState, peer: any): boolean {
1787
1335
  }
1788
1336
 
1789
1337
 
1790
- // The eager emptiness rules. Each is EXACT -- it reports empty only
1791
- // where no value could satisfy the residual -- so the algebra stays
1792
- // sound; the incompleteness it accepts is documented in
1793
- // docs/reference-language.md, "Emptiness".
1794
1338
  function stateEmpty(s: ConstraintState): boolean {
1795
- // Two disagreeing kind narrowings inside a length argument, recorded by
1796
- // meetCount because that meet has no ctx to fail through.
1797
1339
  if (s.clash) {
1798
1340
  return true
1799
1341
  }
@@ -1832,10 +1374,6 @@ function stateEmpty(s: ConstraintState): boolean {
1832
1374
  }
1833
1375
  }
1834
1376
 
1835
- // Point deletion under a narrowed leaf: a closed point interval
1836
- // whose single value of the narrowed leaf is excluded is empty
1837
- // (integer & min(3) & max(3) & neq(3)). Without a narrowing the
1838
- // point survives in the other leaves.
1839
1377
  if (null != s.kind && null != s.lo && null != s.hi &&
1840
1378
  !s.lo.open && !s.hi.open &&
1841
1379
  0 === cmpVal(d, s.lo.v, s.hi.v)) {
@@ -1846,10 +1384,6 @@ function stateEmpty(s: ConstraintState): boolean {
1846
1384
  }
1847
1385
  }
1848
1386
 
1849
- // Sizing over the number domain: a number has neither a length nor
1850
- // members, so `integer & length(3)` and `min(2) & unique()` admit
1851
- // nothing. Uniqueness over the string domain is empty for the same
1852
- // reason -- a string's members are not values the algebra compares.
1853
1387
  if ('number' === d && (null != s.count || s.uniq ||
1854
1388
  0 < s.uniqBy.length)) {
1855
1389
  return true
@@ -1868,10 +1402,6 @@ function stateEmpty(s: ConstraintState): boolean {
1868
1402
  }
1869
1403
 
1870
1404
 
1871
- // The base every `length` argument meets: a count is a non-negative
1872
- // integer, whatever else the argument says (docs/reference-language.md,
1873
- // "`length` semantics" -- `length(c)` is empty iff `c & integer & min(0)`
1874
- // is).
1875
1405
  function countBase(): ConstraintState {
1876
1406
  return {
1877
1407
  domain: 'number',
@@ -1894,12 +1424,6 @@ function countVal(n: number): any {
1894
1424
  }
1895
1425
 
1896
1426
 
1897
- // The pure meet of two count residuals. Both are number-domain and
1898
- // carry no pattern or sizing atom of their own, so the merge is the
1899
- // interval/exclusion part alone. A kind disagreement becomes a `clash`
1900
- // rather than an error: this meet runs at construction, where there is
1901
- // no AontuContext to raise through, and an empty residual carries the
1902
- // same news to `unify`.
1903
1427
  function meetCount(a: ConstraintState, b: ConstraintState): ConstraintState {
1904
1428
  return {
1905
1429
  domain: 'number',
@@ -1919,18 +1443,6 @@ function meetCount(a: ConstraintState, b: ConstraintState): ConstraintState {
1919
1443
  }
1920
1444
 
1921
1445
 
1922
- // Read a WRITTEN `length` argument as a count residual, or undefined when
1923
- // it is not one. Accepted: an integer literal (an exact count), a
1924
- // numeric kind, a Band A residual over the number domain, and any
1925
- // conjunct of those. A conjunct never reaches here any more: an
1926
- // unsettled argument is held as `pending` and folded before the count
1927
- // reads it (G1 phase 4), so `length(min(2)&max(5))` arrives as the
1928
- // single residual it folds to.
1929
- //
1930
- // Anything else is refused rather than deferred. A reference or an
1931
- // expression would have to residuate, and the sizing atoms do not
1932
- // residuate on their ARGUMENT -- only on the peer whose members are
1933
- // still settling.
1934
1446
  function countArgState(arg: any): ConstraintState | undefined {
1935
1447
  if (numericLeaf(arg)) {
1936
1448
  return {
@@ -1982,18 +1494,7 @@ function countArgState(arg: any): ConstraintState | undefined {
1982
1494
  }
1983
1495
 
1984
1496
 
1985
- // A container is SETTLED when it and every child have converged. Until
1986
- // then the member set can still change — an optional key whose value is
1987
- // a still-resolving reference may yet generate — so a sizing atom must
1988
- // defer rather than decide (docs/reference-language.md, "`length`
1989
- // semantics"). Note that an optional holding a settled-but-ungenerable
1990
- // value, `{x:1,y?:number}`, IS settled: the map converges on the first
1991
- // pass and `y` is simply never emitted.
1992
1497
  function containerSettled(bag: any): boolean {
1993
- // The bag's OWN done-counter is enough: BagVal.unify sets it from the
1994
- // AND over its children, so an unsettled child already leaves the bag
1995
- // unsettled. Walking the children again would be a second, drifting
1996
- // copy of that rule.
1997
1498
  return true === bag.done
1998
1499
  }
1999
1500
 
@@ -2006,35 +1507,15 @@ function genable(child: any): boolean {
2006
1507
  true === child.isList || true === child.isPref ||
2007
1508
  true === child.isRef || true === child.isDisjunct ||
2008
1509
  true === child.isNil ||
2009
- // A settled sizing residue generates through ConjunctVal.gen, so it
2010
- // is a member like any other -- and a `length` that did not count
2011
- // its sibling's `unique` would be the early-fold defect again, one
2012
- // level up.
2013
1510
  undefined !== sizingResidue(child)
2014
1511
  }
2015
1512
 
2016
1513
 
2017
- // The children a bag would EMIT, mirroring the selection in
2018
- // `BagVal.gen` — type/hide marks skipped, non-generable residue and
2019
- // values that generate nothing dropped, optional keys dropped when
2020
- // they generate empty.
2021
- //
2022
- // It returns the member VALS rather than their generated values,
2023
- // because uniqueness compares canon and a generated value cannot
2024
- // express that distinction: `1` and `1.0` generate the same JSON number
2025
- // and canon differently. Counting uses the same list, so both sizing
2026
- // atoms see exactly one definition of "member".
2027
- //
2028
- // Returns undefined when a REQUIRED child is residue: the container's
2029
- // own `gen` raises there, and that error is the one worth reporting.
2030
1514
  function emittedMembers(bag: any, ctx: AontuContext): any[] | undefined {
2031
1515
  const out: any[] = []
2032
1516
 
2033
1517
  let entries = items(bag.peg)
2034
1518
  if (bag.isMap) {
2035
- // Code-point order, because the two ports disagree on raw key order
2036
- // — JavaScript hoists integer-like keys, Go keeps insertion order —
2037
- // and a duplicate report must name the same pair in both.
2038
1519
  entries = entries
2039
1520
  .slice()
2040
1521
  .sort((a: any, b: any) => cmpCodePoint(String(a[0]), String(b[0])))
@@ -2057,10 +1538,6 @@ function emittedMembers(bag: any, ctx: AontuContext): any[] | undefined {
2057
1538
  return undefined
2058
1539
  }
2059
1540
 
2060
- // Generation decides in an isolated collect context, so an
2061
- // unresolved inner value neither raises here nor pollutes the
2062
- // caller's errors — the same isolation BagVal.gen uses for an
2063
- // optional child.
2064
1541
  const cval = child.gen(ctx.clone({ err: [], collect: true }))
2065
1542
 
2066
1543
  if (undefined === cval || (optional && empty(cval))) {
@@ -2074,12 +1551,6 @@ function emittedMembers(bag: any, ctx: AontuContext): any[] | undefined {
2074
1551
  }
2075
1552
 
2076
1553
 
2077
- // Sort accumulated patterns by source in code-point order and drop
2078
- // exact duplicates. Patterns are NEVER simplified or compared for
2079
- // containment: deciding `re("a")` subsumes `re("a|b")` is regex
2080
- // containment, which the algebra deliberately does not do (emptiness
2081
- // stays approximate — sound, incomplete). Two spellings of one language
2082
- // therefore both survive, and both are tested.
2083
1554
  function dedupSortedRes(res: ReAtom[]): ReAtom[] {
2084
1555
  const sorted = [...res].sort((a, b) => cmpCodePoints(a.src, b.src))
2085
1556
  const out: ReAtom[] = []
@@ -2092,9 +1563,6 @@ function dedupSortedRes(res: ReAtom[]): ReAtom[] {
2092
1563
  }
2093
1564
 
2094
1565
 
2095
- // The atom classes registered in the parser's funcMap: each is a
2096
- // ConstraintVal that knows its atom name. Constructed by the
2097
- // func-paren handler as `new funcval({peg: args})`.
2098
1566
  class MinConstraintVal extends ConstraintVal {
2099
1567
  constructor(spec: ValSpec, ctx?: AontuContext) {
2100
1568
  super({ ...spec, atom: 'min' }, ctx)
@@ -2151,9 +1619,6 @@ class UniqueConstraintVal extends ConstraintVal {
2151
1619
 
2152
1620
 
2153
1621
  export {
2154
- // Exported for the differential corpus test (ADR-003): the two ports'
2155
- // normalisers must produce byte-identical output, and that can only be
2156
- // checked by calling them.
2157
1622
  normaliseRe,
2158
1623
  // Exported for the subsumption query (G3, ts/src/subsume.ts): the
2159
1624
  // residual-vs-residual and residual-vs-scalar rules live here beside