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
package/src/hcanon.ts ADDED
@@ -0,0 +1,169 @@
1
+ /* Copyright (c) 2025 Richard Rodger, MIT License */
2
+
3
+ // The HASH FORM (G6 phase 0, docs/capability-review/g6-distribution.md):
4
+ // exactly the unify-level canon with the additions that close its
5
+ // semantic gaps, so that two documents with the same hash form have the
6
+ // same meaning:
7
+ //
8
+ // - a CLOSED map or list renders wrapped: close({...}), close([...])
9
+ // (canon drops closedness);
10
+ // - the type/hide MARKS render as their builtin wrappers: type(x),
11
+ // hide(x) (canon drops marks).
12
+ //
13
+ // Both additions reuse existing parseable syntax, so the hash form
14
+ // remains valid Aontu source and round-trips:
15
+ // hcanon(unify(parse(hcanon(v)))) == hcanon(v) is a spec-suite property
16
+ // (test/spec/hcanon.tsv). User-facing canon is UNCHANGED — hcanon is a
17
+ // separate rendering.
18
+ //
19
+ // The marks PROPAGATE to every descendant at unification (walkMark), so
20
+ // a wrapper is emitted only where a mark STARTS: the walk carries the
21
+ // inherited marks down and a child whose mark the parent already
22
+ // carries renders bare. Without that, hide({a:1}) would render every
23
+ // leaf re-wrapped — still correct, never minimal, and not what the
24
+ // source said.
25
+ //
26
+ // canonHash (G6 phase 1) is the pin built on it:
27
+ // "aon1-" + base64url( SHA-256( UTF-8( hcanon(v) ) ) )
28
+ // (unpadded base64url, RFC 4648 section 5). The "aon1-" scheme id
29
+ // exists so a future semantically-stronger normal form is an upgrade,
30
+ // not a breakage. This is a CANONICAL-TEXT hash, not a semantic
31
+ // equivalence class: the failure direction is the safe one — a false
32
+ // "changed" forces a needless re-review; a false "unchanged" would need
33
+ // two hash forms with the same bytes and different meanings, which is
34
+ // exactly the gap the close/mark wrappers exist to shut.
35
+
36
+ import { createHash } from 'node:crypto'
37
+
38
+ import type { Val } from './val/Val'
39
+
40
+ import { cmpCodePoint } from './keyorder'
41
+
42
+
43
+ type HMarks = {
44
+ type: boolean
45
+ hide: boolean
46
+ }
47
+
48
+
49
+ // One node's rendering, carrying the marks the ANCESTORS already
50
+ // wrapped. Bags and junctions recurse structurally (their canon getters
51
+ // render children through plain canon, which would drop a nested
52
+ // close); everything else — scalars, kinds, funcs, refs, constraints —
53
+ // delegates to its own canon, whose text is already in cross-port
54
+ // parity. The non-Val arm mirrors MapVal.canon's raw-peg fallback and
55
+ // is unreachable through an evaluated tree (direct-tested, ADR-002).
56
+ function render(v: any, inh: HMarks): string {
57
+ if (true !== v?.isVal) {
58
+ return String(v)
59
+ }
60
+
61
+ const mtype = true === v.mark?.type
62
+ const mhide = true === v.mark?.hide
63
+ const inner: HMarks = {
64
+ type: inh.type || mtype,
65
+ hide: inh.hide || mhide,
66
+ }
67
+
68
+ let s: string
69
+ if (true === v.isMap) {
70
+ const keys = Object.keys(v.peg).sort(cmpCodePoint)
71
+ s = '{' +
72
+ (v.spread.cj ? '&:' + render(v.spread.cj, inner) +
73
+ (0 < keys.length ? ',' : '') : '') +
74
+ keys.map((k) =>
75
+ JSON.stringify(k) +
76
+ (v.optionalKeys.includes(k) ? '?' : '') +
77
+ ':' +
78
+ render(v.peg[k], inner)).join(',') +
79
+ '}'
80
+ if (true === v.closed) {
81
+ s = 'close(' + s + ')'
82
+ }
83
+ }
84
+ else if (true === v.isList) {
85
+ const keys = Object.keys(v.peg)
86
+ s = '[' +
87
+ (v.spread.cj ? '&:' + render(v.spread.cj, inner) +
88
+ (0 < keys.length ? ',' : '') : '') +
89
+ keys.map((k) => render(v.peg[k], inner)).join(',') +
90
+ ']'
91
+ if (true === v.closed) {
92
+ s = 'close(' + s + ')'
93
+ }
94
+ }
95
+ else if (true === v.isPref) {
96
+ s = '*' + render(v.peg, inner)
97
+ }
98
+ else if (true === v.isConjunct || true === v.isDisjunct) {
99
+ s = junctionText(v, true === v.isConjunct ? '&' : '|', inner)
100
+ }
101
+ else {
102
+ s = v.canon
103
+ }
104
+
105
+ // The IDENTITY is innermost, exactly as canon writes it (G4 phase
106
+ // 1). It is IN the hash — a node declared `id(svc/auth)` and the
107
+ // same node declared `id(svc/billing)` describe different systems,
108
+ // and a pin that could not tell them apart would be a pin on the
109
+ // shape rather than on the meaning.
110
+ const e = v.entity
111
+ if (null != e) {
112
+ s = 'id(' + JSON.stringify(e) + ')&' + s
113
+ }
114
+
115
+ if (mtype && !inh.type) {
116
+ s = 'type(' + s + ')'
117
+ }
118
+ if (mhide && !inh.hide) {
119
+ s = 'hide(' + s + ')'
120
+ }
121
+
122
+ // The deprecation record rides outermost, as canonRiders
123
+ // renders it (the wrappers are all reparseable calls, so order only
124
+ // has to be FIXED, and this matches the canon the G3 rows pinned).
125
+ const d = v.deprecation
126
+ if (null != d) {
127
+ const dkeys = Object.keys(d).sort()
128
+ const rec = dkeys.map((k) =>
129
+ JSON.stringify(k) + ':' + JSON.stringify(d[k])).join(',')
130
+ s = 'deprecate(' + s + ('' === rec ? '' : ',{' + rec + '}') + ')'
131
+ }
132
+
133
+ return s
134
+ }
135
+
136
+
137
+ // The JunctionVal.canon parenthesisation rule, kept: a member that is
138
+ // itself a junction with more than one term keeps its parens so the
139
+ // text reparses with the same structure (`(1|2)&3`, not the
140
+ // differently-parsing `1|2&3`). Post-unification junctions are
141
+ // flattened by norm, so no SOURCE reaches the wrapping arm -- it is
142
+ // pinned by direct tests over constructed Vals in both ports, because
143
+ // a hash form that could render ambiguously would be a pin that
144
+ // silently agrees with a document it should not.
145
+ function junctionText(v: any, sym: string, inner: HMarks): string {
146
+ return v.peg.map((m: any) =>
147
+ true === m?.isJunction && 1 < m.peg.length
148
+ ? '(' + render(m, inner) + ')'
149
+ : render(m, inner))
150
+ .join(sym)
151
+ }
152
+
153
+
154
+ // The hash form of an EVALUATED Val (unify first; parse-level canon
155
+ // parenthesisation differs between the ports and is excluded by
156
+ // construction — AGENTS.md).
157
+ export function hcanon(v: Val): string {
158
+ return render(v, { type: false, hide: false })
159
+ }
160
+
161
+
162
+ // The canon-hash pin. Scoped to the module evaluated STANDALONE: its
163
+ // own include closure resolved and unified at its own root, before any
164
+ // consumer context — which is what makes the pin transitive (an edit
165
+ // two includes deep changes the unified root, hence the hash).
166
+ export function canonHash(v: Val): string {
167
+ return 'aon1-' +
168
+ createHash('sha256').update(hcanon(v), 'utf8').digest('base64url')
169
+ }
package/src/hints.ts CHANGED
@@ -33,6 +33,12 @@ const hints: Record<string, string> = {
33
33
  'This value was present after unification, and cannot be generated\n' +
34
34
  'because it is not a literal value.',
35
35
 
36
+ disjunct_no_gen:
37
+ 'More than one alternative of this disjunction is still admitted, so\n' +
38
+ 'there is no single value to generate. Supply a value that selects\n' +
39
+ 'one alternative, or write a preference (*) to say which one holds\n' +
40
+ 'when nothing else does.',
41
+
36
42
 
37
43
  // TODO: extend errors to have details so we can name the key
38
44
  mapval_required: 'This map value is required.',
@@ -72,7 +78,58 @@ const hints: Record<string, string> = {
72
78
  ' max(65535) & 99999 -> nil # Above the bound;\n' +
73
79
  ' min(5) & max(3) -> nil # Empty at composition time;\n' +
74
80
  ' integer & above(1) & below(2) -> nil # No integer in the gap;\n' +
75
- ' neq(1) & 1.0 -> 1.0 # neq excludes leaf AND value.',
81
+ ' neq(1) & 1.0 -> 1.0 # neq excludes leaf AND value.\n' +
82
+ ' re("^a") & "abc" -> "abc" # Patterns are unanchored.',
83
+
84
+ must:
85
+ 'This value fails an evaluate-only check written with must().\n' +
86
+ 'The author\'s message is: {message}' +
87
+ '\n \n' +
88
+ 'must(c, msg) is Band B of the constraint algebra: the value must\n' +
89
+ 'unify with c, but the check itself is OPAQUE to the algebra -- it\n' +
90
+ 'never participates in emptiness or subsumption, and it never\n' +
91
+ 'contributes to the value. It is the honest channel for a domain\n' +
92
+ 'rule the algebra cannot reason about, which is why it carries a\n' +
93
+ 'message of its own.' +
94
+ '\n \nExamples:\n' +
95
+ ' must("gold"|"silver","tier") & "gold" -> "gold" # Admitted;\n' +
96
+ ' must("gold"|"silver","tier") & "lead" -> nil # ... reported\n' +
97
+ ' # with "tier";\n' +
98
+ ' min(0) & must(integer,"whole") & 3 -> 3 # Bands compose.',
99
+
100
+ constraint_pattern:
101
+ 'This re() pattern is outside the supported subset. It uses\n' +
102
+ '{reason}.\n' +
103
+ ' \n' +
104
+ 're() accepts classical regular expressions over Unicode code\n' +
105
+ 'points, with one meaning in both implementations:\n' +
106
+ ' \n' +
107
+ ' literals a \\. \\* \\xHH (escape . \\ + * ? ( ) [ ] { } | ^ $ /)\n' +
108
+ ' classes [abc] [^abc] [a-z]\n' +
109
+ ' abbreviations \\d \\D \\w \\W \\s \\S and .\n' +
110
+ ' repetition * + ? {n} {n,} {n,m} (lazy: *? +? ??)\n' +
111
+ ' grouping (...) (?:...) alternation a|b\n' +
112
+ ' anchors ^ $ \\A \\z \\b \\B\n' +
113
+ ' \n' +
114
+ 'Aontu DEFINES the abbreviations rather than inheriting either\n' +
115
+ 'host regex engine, so they mean the same in both ports:\n' +
116
+ ' \\d [0-9] \\w [0-9A-Za-z_] \\s [ \\t\\n\\r\\f\\v] . [^\\n]\n' +
117
+ 'Note \\s is these six ASCII characters only -- not U+00A0.\n' +
118
+ ' \n' +
119
+ 'NOT accepted, because no rewriting can make the two engines\n' +
120
+ 'agree:\n' +
121
+ ' backreferences (\\1, \\k<n>) and lookaround ((?=) (?!) (?<=))\n' +
122
+ ' named groups, inline flags, and any (?...) but (?:\n' +
123
+ ' POSIX classes [[:alpha:]], \\p{...}, \\x{...}, \\u\n' +
124
+ ' a quantifier on a group containing a quantifier or an\n' +
125
+ ' alternation -- (a+)+ backtracks exponentially in one port,\n' +
126
+ ' so write [ab]+ rather than (?:a|b)+' +
127
+ '\n \nExamples:\n' +
128
+ ' re("^[a-z][a-z0-9-]*$") # Fine;\n' +
129
+ ' re("^\\d{3}-\\d{4}$") # Fine;\n' +
130
+ ' re("(?:ab)+") # Fine (non-capturing group);\n' +
131
+ ' re("(?=x)y") # Refused (lookahead);\n' +
132
+ ' re("(a+)+") # Refused (nested quantifier).',
76
133
 
77
134
  budget_passes:
78
135
  'The evaluation budget of {limit} fixpoint passes was spent before\n' +
@@ -93,6 +150,44 @@ const hints: Record<string, string> = {
93
150
  // Parsing errors
94
151
  'parse_bad_src': 'Invalid source provided for parsing. The source must be a non-empty string.',
95
152
 
153
+ merge_conflict: 'A version-control conflict marker was found in the source. The\nfile still holds an unresolved merge: resolve it and remove the\n`<<<<<<<`, `=======` and `>>>>>>>` lines before unifying.\n \nExamples:\n <<<<<<< HEAD -> nil # A conflict marker, not a `<` operation;\n ======= -> nil # ... nor a chain of `=` characters;\n >>>>>>> other -> nil # ... nor a `>` operation.',
154
+
155
+ include_denied: 'An @"..." include was refused by the active trust profile\n(docs/trust.md). The document asked to read a source the evaluation\'s\ninclude capability does not allow: widen the capability if the read is\nintended, or remove the include if it is not.\n \nExamples:\n a:@"in-root.aon" -> {..} # Inside the confinement root: allowed;\n a:@"../secret.aon" -> nil # ... but escaping the root is denied;\n a:@"/etc/hostname" -> nil # ... and so is an absolute path outside it.',
156
+
157
+ func_arity: 'This function was called with the wrong number of arguments:\n{func} takes {want}, but was given {got}.\n \nExamples:\n upper(\"a\") -> \"A\" # One argument, which is what upper takes;\n upper(\"a\",\"b\") -> nil # ... so two is a mistake in the source;\n key() -> \"\" # key takes none, or one level count;\n neq(1,2,3) -> neq # ... and neq takes one or more exclusions.',
158
+
159
+ elided_value: 'A key or element was written with no value after the colon. An\nelided value is a mistake in the source rather than a null: write\n`null` if that is what was meant, or supply the value.\n \nExamples:\n a:null -> null # An explicit null, which is a value;\n a: -> nil # ... but nothing at all is not;\n a: b:1 -> {..} # A colon chain is not an elision;\n [1,] -> [1] # ... nor is a trailing comma.',
160
+
161
+ id_name: 'The argument to id() is not an entity name. A name is one or\nmore letters, digits, `_`, `-` or `/`, and NO dots: a dot separates\nan entity name from a path inside that entity, so a dotted name\nwould be ambiguous. A `-` must be quoted, because it is not a\nbare-text character.\n \nExamples:\n id(svc/auth) -> id # Letters, digits and `/` may be bare;\n id("team-pay") -> id # ... a `-` name must be quoted;\n id(svc.auth) -> nil # ... a dot is a path separator, not a name;\n id(1) -> nil # ... and a number is not a name at all.',
162
+
163
+ id_conflict: 'One value was declared to be two different entities. An id() says\nwhat a value IS, so two names on one node is a contradiction, not a\nmerge — the same kind of failure as unifying 1 with 2. Give the node\none name, or give the two names to two nodes.\n \nExamples:\n id(a) & id(a) & {} -> {..} # One entity, said twice;\n id(a) & {x:1} -> {..} # ... an entity with content;\n id(a) & id(b) & {} -> nil # ... but a node cannot be both.',
164
+
165
+ id_spread: 'A spread template stamps one id() onto every child. `&: id(x) & …`\nsays that EVERY child of the bag is the entity `x`, and identity\nmerging would then unify all of them into one. Use a\npath-dependent name — `id(key())` — to give each child its own,\nor move the id() to the one child that has it.\n \nExamples:\n {&: id(key()), a:{}, b:{}} -> {..} # A name per child;\n {a: id(x) & {}} -> {..} # ... or one named child;\n {&: id(x), a:{}, b:{}} -> nil # ... but not one name for all.',
166
+
167
+ refer_address: 'A refer() was given something that is not an entity address. An\naddress is an entity name, optionally followed by a dot-separated path\ninside that entity — and only a STRING can be one.\n \nExamples:\n refer() & "svc/auth" -> "svc/auth" # An entity;\n refer() & "svc/auth.port" -> ... # ... and a node inside it;\n refer() & "svc/auth." -> nil # ... but not a trailing dot;\n refer() & 1 -> nil # ... and not a number.',
168
+
169
+ refer_unresolved: 'A refer() address names no entity in this evaluation. Within one\nevaluation the document-set is fixed, so a link to nothing is an\nerror rather than something to resolve later: check the spelling, or\nadd the id() that was meant to declare it.\n \nExamples:\n a:id(svc/x)&{} b:refer()&"svc/x" -> "svc/x" # Declared, so it resolves;\n a:id(svc/x)&{p:1} b:refer()&"svc/x.p" -> "svc/x.p" # ... and so does a node inside it;\n b:refer()&"svc/nope" -> nil # ... but nothing declares this.',
170
+
171
+ pack_data: 'The first argument to pack() is not a bag. `pack` makes one child\nper child of its DATA, so the data has to have children: a list of\nnames, or a map whose keys are the names.\n \nExamples:\n pack([a,b], {x:1}) -> {..} # A list of names;\n pack({a:1,b:2}, {x:1}) -> {..} # ... or a map, keyed by its keys;\n pack(1, {x:1}) -> nil # ... but a scalar has no children.',
172
+
173
+ pack_key: 'A list packed by pack() holds something that is not a string. The\nelements of a packed list ARE the generated keys, and only a string\nis a key — an element keyed by its position would churn every\ngenerated child the moment the list was reordered.\n \nExamples:\n pack([a,b], {x:1}) -> {..} # Names;\n pack(["a b"], {x:1}) -> {..} # ... a quoted name is still a name;\n pack([1,2], {x:1}) -> nil # ... but a number is not one.',
174
+
175
+ each_data: 'The first argument to each() is not a bag. `each` makes one list\nelement per child of its DATA, so the data has to have children: a\nlist, or a map whose values become the elements in sorted-key order.\n \nExamples:\n each([1,2]) -> [..] # A list, in source order;\n each({b:2,a:1}) -> [..] # ... a map, in sorted-key order;\n each(1) -> nil # ... but a scalar has no children.',
176
+
177
+ filter_data: 'The first argument to filter() is not a bag. `filter` keeps the\nchildren of its DATA that already satisfy a condition, so the data\nhas to have children: a list, or a map.\n \nExamples:\n filter([1,x], integer) -> [..] # A list;\n filter({a:1,b:x}, integer) -> {..} # ... or a map, keys kept;\n filter(1, integer) -> nil # ... but a scalar has none.',
178
+
179
+ match_none: 'No pattern matched, and there is no default. `match` tries each\npattern in the order written and takes the first the value unifies\nwith; the value {value} unified with none of {tried}. Add a trailing\ndefault — the argument after the last pair — if the rest was meant\nto be allowed.\n \nExamples:\n match(1, integer, ok) -> "ok" # The first pattern matches;\n match(x, integer, ok, other) -> "other" # ... or the default does;\n match(x, integer, ok) -> nil # ... but nothing here does.',
180
+
181
+ place_pair: 'Two placeholders met, and neither has a value to fill the other.\n`_` is a HOLE: it is filled by whatever the call is unified with, so\na call holding one needs a peer that does not. Give one side a\nvalue.\n \nExamples:\n upper(_) & hello -> "HELLO" # The peer fills the hole;\n _ + 2 & 1 -> 3 # ... whatever the call is;\n upper(_) & lower(_) -> nil # ... but two holes fill nothing.',
182
+
183
+ pipe_target: 'The right-hand side of a `|>` is not a function. A pipe puts the\nvalue on its left in as the FIRST argument of the call on its\nright, so the right side has to be one: a call, or the bare name of\na built-in.\n \nExamples:\n hello |> upper -> "HELLO" # A bare name is the call;\n $.names |> pack({}) -> {..} # ... or a call with more arguments;\n 1 |> 2 -> nil # ... but a value is not a function.',
184
+
185
+ module_missing: 'A module import names a module that is not in this project. A\nmodule is resolved from LOCAL stores only -- `aon_vendor/` beside the\nproject\'s mod.aon, then the user cache -- because evaluation never\ntouches the network. Fetching is a separate step, and the message\nnames it.\n \nExamples:\n @"corp.example/s@1" -> nil # Not fetched: run aontu mod get;\n @"./local.aon" -> {..} # ... a local path is not a module;\n @"corp.example/s@1#aon1-…" -> {..} # ... and a pin does not fetch it either.',
186
+
187
+ module_integrity: 'A module resolved locally does not have the MEANING it was pinned\nto. The pin is a canon-hash -- the hash of the module unified\nstandalone -- so it survives comments, formatting and refactoring and\nbreaks on any semantic change in the module\'s transitive closure.\nVerification is always local: the registry\'s annotation is advisory.\n \nExamples:\n @"corp.example/s@1" -> {..} # No pin, no check;\n @"corp.example/s@1#aon1-x" -> nil # ... a pin that disagrees refuses;\n aontu hash <file> # ... and this is what it should be.',
188
+
189
+ module_depth: 'Module verification nested too deep. A pinned module is checked by\nEVALUATING it, and that evaluation resolves the module\'s own imports\n-- so a vendor tree that leads back to itself would recurse until the\nhost ran out of stack. The bound makes that a stated refusal rather\nthan a crash whose verdict depends on the machine.\n \nExamples:\n @"corp.example/s@1" -> {..} # Ordinary nesting is far below it;\n aontu mod vendor # ... rebuild a vendor tree that loops;\n aontu hash <file> # ... and check what it hashes to.',
190
+
96
191
  // Unification errors
97
192
  'unify_no_src': 'No source provided for unification. Cannot unify without source values.',
98
193
  'unify_no_res': 'Unification produced no result. The values could not be unified.',
@@ -142,12 +237,85 @@ const hints: Record<string, string> = {
142
237
  ' 1.0 + 0d2 -> nil # float with biginteger;\n' +
143
238
  ' 0d0.5 + 1.0 -> nil # ... and the same the other way round.',
144
239
 
240
+ pick_key:
241
+ 'A child of this bag has no key `{key}` to pick. Projection\n' +
242
+ 'refuses rather than skipping: a shorter list would make the\n' +
243
+ 'aggregate over it total a DIFFERENT set of records than the one\n' +
244
+ 'the author named, which is the failure an aggregate exists to\n' +
245
+ 'prevent. Give every child the key, or filter the bag first.' +
246
+ '\n \nExamples:\n' +
247
+ ' pick([{a:1},{a:2}], a) -> [1,2] # Every child has it;\n' +
248
+ ' pick([{a:1},{b:2}], a) -> nil # ... the second does not;\n' +
249
+ ' pick([[9],[8]], 0) -> [9,8] # A list child takes an index.',
250
+
251
+ aggregate_data:
252
+ 'This aggregate needs a BAG to fold: a list or a map. `sum`,\n' +
253
+ '`least` and `greatest` walk the children of the value they are\n' +
254
+ 'given, so a scalar, a kind or an unresolved reference is not\n' +
255
+ 'something they can total.' +
256
+ '\n \nExamples:\n' +
257
+ ' sum([1,2,3]) -> 6 # A list;\n' +
258
+ ' sum({a:1,b:2}) -> 3 # ... or a map, by sorted key;\n' +
259
+ ' sum(3) -> nil # A scalar is not a bag;\n' +
260
+ ' x:[1,2] sum($.x) -> 3 # A reference to one is fine.',
261
+
262
+ aggregate_empty:
263
+ 'There is no least or greatest element of an EMPTY bag. Addition\n' +
264
+ 'has an identity, so `sum([])` is 0; comparison has none, and\n' +
265
+ 'answering with a zero or an infinity would be inventing a value\n' +
266
+ 'the data does not contain. Guard the bag, or give it a floor with\n' +
267
+ 'a written element.' +
268
+ '\n \nExamples:\n' +
269
+ ' sum([]) -> 0 # Zero IS the empty sum;\n' +
270
+ ' least([]) -> nil # ... but nothing is the least of none;\n' +
271
+ ' least([0]) -> 0 # A written floor answers.',
272
+
273
+ divide_by_zero:
274
+ 'Division by zero. `div`, `mod` and `rem` refuse a zero divisor in\n' +
275
+ 'every numeric leaf, including binary floats: Aontu is a JSON\n' +
276
+ 'superset with no notation for an infinity, so there is no value\n' +
277
+ 'the operation could answer with. A definition that divides by zero\n' +
278
+ 'is wrong, and this says so where it is written rather than\n' +
279
+ 'somewhere downstream.' +
280
+ '\n \nExamples:\n' +
281
+ ' div(7, 0) -> nil # No answer exists;\n' +
282
+ ' mod(7, 0) -> nil # ... nor for the modulus;\n' +
283
+ ' div(7.0, 0.0) -> nil # ... and a float would say Infinity.',
284
+
285
+ inexact_divide:
286
+ 'Exact decimal division is not closed: one third has no finite\n' +
287
+ 'decimal form, so `div`, `mod` and `rem` refuse a `0d` operand\n' +
288
+ 'rather than round one. Two ways out. Scale to integers and divide\n' +
289
+ 'those -- which is the convention money should be carried in\n' +
290
+ 'anyway, minor units as an integer -- or use binary floats if an\n' +
291
+ 'approximation is acceptable here.' +
292
+ '\n \nExamples:\n' +
293
+ ' div(0d10.0, 0d4.0) -> nil # Refused, though this one terminates;\n' +
294
+ ' div(0d10, 0d4) -> 0d2 # A biginteger is not a decimal;\n' +
295
+ ' div(1000, 4) -> 250 # Integer cents, exact;\n' +
296
+ ' div(10.0, 4.0) -> 2.5 # ... or binary64, approximate;\n' +
297
+ ' mul(0d10.0, 0d4.0) -> 0d40.0 # Multiplication IS exact and stays.',
298
+
299
+ float_overflow:
300
+ 'This result is not a finite binary64 number, so it is not a value\n' +
301
+ 'Aontu can carry. There is no notation for an infinity or a NaN in\n' +
302
+ 'a JSON superset, and no JSON a generator could emit for one, so\n' +
303
+ 'the operation is refused where it is written rather than escaping\n' +
304
+ 'as an internal error or an unserialisable value.\n' +
305
+ 'Use the exact leaves (`0d`) if the magnitude is real rather than\n' +
306
+ 'an accident.' +
307
+ '\n \nExamples:\n' +
308
+ ' 1.0e308 + 1.0e308 -> nil # Overflows binary64;\n' +
309
+ ' mul(1.0e200, 1.0e200) -> nil # ... and so does this;\n' +
310
+ ' 0d1e308 + 0d1e308 -> 0d2e308 # Exact, and well inside budget.',
311
+
145
312
  inexact_integer_sum:
146
313
  'The `integer` leaf holds a value only when it is integral, within\n' +
147
- 'the int64 range, and exactly representable in binary64. This sum\n' +
148
- 'is not: {sum}.\n' +
149
- 'Aontu adds integers exactly and refuses to store a rounded answer\n' +
150
- '-- write `0d<digits>` for an exact integer beyond that window.' +
314
+ 'the int64 range, and exactly representable in binary64. This\n' +
315
+ 'result is not: {sum}.\n' +
316
+ 'Aontu computes integers exactly and refuses to store a rounded\n' +
317
+ 'answer -- write `0d<digits>` for an exact integer beyond that\n' +
318
+ 'window.' +
151
319
  '\n \nExamples:\n' +
152
320
  ' 4503599627370496 + 4503599627370496 -> 9007199254740992 # Exact;\n' +
153
321
  ' 4503599627370496 + 4503599627370497 -> nil # 2^53+1 is not;\n' +
@@ -236,6 +404,95 @@ const codeClasses: Record<string, string> = {
236
404
  syntax: 'parse',
237
405
  parse_unknown: 'parse',
238
406
  parse_bad_src: 'parse',
407
+ merge_conflict: 'parse',
408
+ include_denied: 'parse',
409
+
410
+ // G3 -- the subsumption query's report vocabulary (class compat):
411
+ // the compat_* codes are its findings, the sub_* codes its undecided
412
+ // reasons. Report-layer codes: no NilVal ever carries one, so they
413
+ // have no hint text.
414
+ compat_narrowed: 'compat',
415
+ compat_required_added: 'compat',
416
+ compat_default_changed: 'compat',
417
+ compat_marks_changed: 'compat',
418
+ sub_unresolved: 'compat',
419
+ sub_disjunct_distribution: 'compat',
420
+ sub_path_dependent_spread: 'compat',
421
+ sub_evaluate_only: 'compat',
422
+ sub_default_indeterminate: 'compat',
423
+ deprecated: 'compat',
424
+ pref_not_instance: 'compat',
425
+
426
+ // G7 phase 5 -- the overlay patch verb: an assignment that is not
427
+ // <path>=<value>. Class `parse`, because what is malformed IS
428
+ // source text; report-layer, so no NilVal carries it.
429
+ patch_assignment: 'parse',
430
+ patch_not_editable: 'reference',
431
+ patch_ambiguous: 'reference',
432
+ patch_span_mismatch: 'internal',
433
+
434
+ // G4 phase 1 -- the identity mark: a name that is not one, and two
435
+ // different names on one node. `id_name` is a parse-class refusal
436
+ // of the argument; `id_conflict` is a conflict like any other
437
+ // failed meet, because that is exactly what it is.
438
+ id_name: 'parse',
439
+ id_conflict: 'conflict',
440
+
441
+ // Clearing rule 3: a constant `id()` inside an `&:` template. Class
442
+ // `parse`, because what is wrong is the TEXT of the template rather
443
+ // than any pair of values it brought together.
444
+ id_spread: 'parse',
445
+
446
+ // G4 phase 2 -- the checked link: a string that is not an entity
447
+ // address (class `parse`, the text is wrong), and an address that
448
+ // names nothing in this evaluation (class `reference`, the same
449
+ // class as `no_path`, because it is the same kind of miss).
450
+ refer_address: 'parse',
451
+ refer_unresolved: 'reference',
452
+
453
+ // G8 phase 1 -- the generation combinators. All three are class
454
+ // `parse`: what is wrong is the CALL as written (data that is not a
455
+ // bag, a list element that is not a name), not any pair of values a
456
+ // meet brought together.
457
+ pack_data: 'parse',
458
+ pack_key: 'parse',
459
+ each_data: 'parse',
460
+
461
+ // G8 phase 2 -- selection. `filter_data` is class `parse` for the
462
+ // same reason `pack_data` is: the CALL names something with no
463
+ // children. `match_none` is class `conflict` -- the value and every
464
+ // pattern written for it disagreed, which is an ordinary failed
465
+ // meet, reported once for the whole form.
466
+ filter_data: 'parse',
467
+ match_none: 'conflict',
468
+
469
+ // G8 phase 3 -- the placeholder. Class `conflict`: two values met
470
+ // and neither could answer for the other, which is what every
471
+ // conflict is.
472
+ place_pair: 'conflict',
473
+
474
+ // G8 phase 4 -- the pipe. Class `parse`: a pipe is sugar resolved
475
+ // while reading the source, so a pipe into something that is not a
476
+ // call is wrong in the TEXT and no later pass can repair it.
477
+ pipe_target: 'parse',
478
+
479
+ // G6 phase 2 -- modules. Both are class `parse`: a module import is
480
+ // resolved while the source is READ, and neither a module that is
481
+ // absent nor one whose meaning disagrees with its pin can be
482
+ // repaired by any later pass.
483
+ module_missing: 'parse',
484
+ module_integrity: 'parse',
485
+ module_depth: 'budget',
486
+
487
+ // G4 phase 5 -- the relation graph checks. Class `conflict`: the
488
+ // model contradicts a property it declared for itself. Report-layer,
489
+ // so no NilVal carries either -- both are global and non-monotone,
490
+ // and a lattice citizen may not be falsified by more information.
491
+ relation_cycle: 'conflict',
492
+ relation_inverse_missing: 'conflict',
493
+ relation_target_unmet: 'conflict',
494
+ func_arity: 'parse',
495
+ elided_value: 'parse',
239
496
  unify_no_src: 'parse',
240
497
  incomplete_expression: 'parse',
241
498
  not_number: 'parse',
@@ -246,6 +503,8 @@ const codeClasses: Record<string, string> = {
246
503
  // (constraint covers the whole algebra family: membership failure,
247
504
  // empty meets at composition time, and domain/kind mixing.)
248
505
  constraint: 'conflict',
506
+ must: 'conflict',
507
+ constraint_pattern: 'conflict',
249
508
  scalar_value: 'conflict',
250
509
  scalar_kind: 'conflict',
251
510
  no_scalar_unify: 'conflict',
@@ -261,6 +520,12 @@ const codeClasses: Record<string, string> = {
261
520
  '|:empty-dist': 'conflict',
262
521
  exact_float_mix: 'conflict',
263
522
  inexact_integer_sum: 'conflict',
523
+ pick_key: 'conflict',
524
+ aggregate_data: 'conflict',
525
+ aggregate_empty: 'conflict',
526
+ divide_by_zero: 'conflict',
527
+ inexact_divide: 'conflict',
528
+ float_overflow: 'conflict',
264
529
  decimal_budget: 'conflict',
265
530
  lossy_integer_literal: 'conflict',
266
531
  arg: 'conflict',
@@ -279,6 +544,7 @@ const codeClasses: Record<string, string> = {
279
544
 
280
545
  // incomplete -- residue: the truth requires more than was supplied
281
546
  no_gen: 'incomplete',
547
+ disjunct_no_gen: 'incomplete',
282
548
  conjunct: 'incomplete',
283
549
  mapval_no_gen: 'incomplete',
284
550
  mapval_required: 'incomplete',