aontu 0.52.1 → 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 (272) 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 +96 -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 +13 -0
  13. package/dist/ctx.js +43 -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 +38 -7
  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 +167 -4
  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 +512 -69
  33. package/dist/lang.js.map +1 -1
  34. package/dist/lsp.d.ts +9 -2
  35. package/dist/lsp.js +262 -47
  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 +2 -1
  83. package/dist/unify.js +253 -36
  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 +7 -1
  103. package/dist/val/ConstraintVal.js +490 -40
  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.js +27 -4
  120. package/dist/val/ExpectVal.js.map +1 -1
  121. package/dist/val/FeatureVal.js +1 -1
  122. package/dist/val/FeatureVal.js.map +1 -1
  123. package/dist/val/FilterFuncVal.d.ts +15 -0
  124. package/dist/val/FilterFuncVal.js +91 -0
  125. package/dist/val/FilterFuncVal.js.map +1 -0
  126. package/dist/val/FuncBaseVal.d.ts +6 -1
  127. package/dist/val/FuncBaseVal.js +171 -1
  128. package/dist/val/FuncBaseVal.js.map +1 -1
  129. package/dist/val/HideFuncVal.js.map +1 -1
  130. package/dist/val/IdFuncVal.d.ts +13 -0
  131. package/dist/val/IdFuncVal.js +54 -0
  132. package/dist/val/IdFuncVal.js.map +1 -0
  133. package/dist/val/JunctionVal.js +7 -1
  134. package/dist/val/JunctionVal.js.map +1 -1
  135. package/dist/val/KeyFuncVal.d.ts +1 -1
  136. package/dist/val/KeyFuncVal.js +38 -30
  137. package/dist/val/KeyFuncVal.js.map +1 -1
  138. package/dist/val/ListVal.js +101 -14
  139. package/dist/val/ListVal.js.map +1 -1
  140. package/dist/val/LowerFuncVal.js.map +1 -1
  141. package/dist/val/MapVal.js +93 -8
  142. package/dist/val/MapVal.js.map +1 -1
  143. package/dist/val/MatchFuncVal.d.ts +15 -0
  144. package/dist/val/MatchFuncVal.js +107 -0
  145. package/dist/val/MatchFuncVal.js.map +1 -0
  146. package/dist/val/MoveFuncVal.js.map +1 -1
  147. package/dist/val/NilVal.js +24 -0
  148. package/dist/val/NilVal.js.map +1 -1
  149. package/dist/val/OpBaseVal.d.ts +1 -1
  150. package/dist/val/OpBaseVal.js +19 -1
  151. package/dist/val/OpBaseVal.js.map +1 -1
  152. package/dist/val/OpenFuncVal.js +4 -1
  153. package/dist/val/OpenFuncVal.js.map +1 -1
  154. package/dist/val/PackFuncVal.d.ts +15 -0
  155. package/dist/val/PackFuncVal.js +108 -0
  156. package/dist/val/PackFuncVal.js.map +1 -0
  157. package/dist/val/PathFuncVal.js.map +1 -1
  158. package/dist/val/PlaceVal.d.ts +13 -0
  159. package/dist/val/PlaceVal.js +131 -0
  160. package/dist/val/PlaceVal.js.map +1 -0
  161. package/dist/val/PlusOpVal.js +11 -2
  162. package/dist/val/PlusOpVal.js.map +1 -1
  163. package/dist/val/PrefFuncVal.js.map +1 -1
  164. package/dist/val/PrefVal.d.ts +2 -2
  165. package/dist/val/PrefVal.js +78 -23
  166. package/dist/val/PrefVal.js.map +1 -1
  167. package/dist/val/RefVal.d.ts +1 -1
  168. package/dist/val/RefVal.js +89 -7
  169. package/dist/val/RefVal.js.map +1 -1
  170. package/dist/val/ReferFuncVal.d.ts +36 -0
  171. package/dist/val/ReferFuncVal.js +303 -0
  172. package/dist/val/ReferFuncVal.js.map +1 -0
  173. package/dist/val/ScalarKindVal.d.ts +1 -2
  174. package/dist/val/ScalarKindVal.js +0 -11
  175. package/dist/val/ScalarKindVal.js.map +1 -1
  176. package/dist/val/TopVal.js.map +1 -1
  177. package/dist/val/TypeFuncVal.js.map +1 -1
  178. package/dist/val/UpperFuncVal.js.map +1 -1
  179. package/dist/val/Val.d.ts +8 -1
  180. package/dist/val/Val.js +150 -1
  181. package/dist/val/Val.js.map +1 -1
  182. package/dist/val/VarVal.js.map +1 -1
  183. package/dist/val/arith.d.ts +6 -0
  184. package/dist/val/arith.js +170 -0
  185. package/dist/val/arith.js.map +1 -0
  186. package/dist/vet.d.ts +45 -0
  187. package/dist/vet.js +776 -0
  188. package/dist/vet.js.map +1 -0
  189. package/dist/walk.d.ts +2 -0
  190. package/dist/walk.js +91 -0
  191. package/dist/walk.js.map +1 -0
  192. package/grammar/aontu.gbnf +130 -0
  193. package/grammar/aontu.lark +113 -0
  194. package/package.json +21 -6
  195. package/skill/SKILL.md +37 -0
  196. package/skill/error-codes.md +62 -0
  197. package/skill/examples.md +99 -0
  198. package/skill/grammar-card.md +57 -0
  199. package/src/agentsmd.ts +135 -0
  200. package/src/aontu.ts +135 -4
  201. package/src/cli.ts +2858 -71
  202. package/src/ctx.ts +73 -1
  203. package/src/diff.ts +196 -0
  204. package/src/err.ts +42 -7
  205. package/src/graph.ts +135 -0
  206. package/src/hcanon.ts +169 -0
  207. package/src/hints.ts +208 -4
  208. package/src/jsonschema.ts +511 -0
  209. package/src/lang.ts +570 -70
  210. package/src/lsp.ts +281 -48
  211. package/src/mcp-server.ts +187 -0
  212. package/src/mcp.ts +993 -0
  213. package/src/mod-tool.ts +679 -0
  214. package/src/mod.ts +344 -0
  215. package/src/patch.ts +624 -0
  216. package/src/provenance.ts +430 -0
  217. package/src/query.ts +379 -0
  218. package/src/reach.ts +184 -0
  219. package/src/relation.ts +395 -0
  220. package/src/report-sarif.ts +137 -0
  221. package/src/site.ts +36 -1
  222. package/src/std.ts +73 -0
  223. package/src/subsume.ts +690 -0
  224. package/src/trim.ts +195 -0
  225. package/src/tsconfig.json +10 -4
  226. package/src/type.ts +51 -2
  227. package/src/unify.ts +274 -36
  228. package/src/utility.ts +139 -1
  229. package/src/val/AggFuncVal.ts +319 -0
  230. package/src/val/ArithFuncVal.ts +108 -0
  231. package/src/val/BagVal.ts +101 -4
  232. package/src/val/CloseFuncVal.ts +9 -1
  233. package/src/val/ConjunctVal.ts +20 -0
  234. package/src/val/ConstraintVal.ts +542 -43
  235. package/src/val/CopyFuncVal.ts +7 -1
  236. package/src/val/Decimal.ts +15 -0
  237. package/src/val/DeprecateFuncVal.ts +84 -0
  238. package/src/val/DisjunctVal.ts +139 -28
  239. package/src/val/EachFuncVal.ts +133 -0
  240. package/src/val/ExpectVal.ts +28 -6
  241. package/src/val/FeatureVal.ts +1 -1
  242. package/src/val/FilterFuncVal.ts +154 -0
  243. package/src/val/FuncBaseVal.ts +192 -1
  244. package/src/val/HideFuncVal.ts +0 -2
  245. package/src/val/IdFuncVal.ts +91 -0
  246. package/src/val/JunctionVal.ts +7 -1
  247. package/src/val/KeyFuncVal.ts +39 -35
  248. package/src/val/ListVal.ts +108 -15
  249. package/src/val/LowerFuncVal.ts +0 -1
  250. package/src/val/MapVal.ts +99 -8
  251. package/src/val/MatchFuncVal.ts +176 -0
  252. package/src/val/MoveFuncVal.ts +0 -2
  253. package/src/val/NilVal.ts +25 -0
  254. package/src/val/OpBaseVal.ts +20 -1
  255. package/src/val/OpenFuncVal.ts +4 -2
  256. package/src/val/PackFuncVal.ts +175 -0
  257. package/src/val/PathFuncVal.ts +0 -1
  258. package/src/val/PlaceVal.ts +193 -0
  259. package/src/val/PlusOpVal.ts +11 -2
  260. package/src/val/PrefFuncVal.ts +0 -1
  261. package/src/val/PrefVal.ts +79 -36
  262. package/src/val/RefVal.ts +91 -8
  263. package/src/val/ReferFuncVal.ts +387 -0
  264. package/src/val/ScalarKindVal.ts +0 -13
  265. package/src/val/TopVal.ts +0 -1
  266. package/src/val/TypeFuncVal.ts +0 -2
  267. package/src/val/UpperFuncVal.ts +0 -1
  268. package/src/val/Val.ts +205 -2
  269. package/src/val/VarVal.ts +0 -1
  270. package/src/val/arith.ts +316 -0
  271. package/src/vet.ts +992 -0
  272. 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.',
@@ -146,10 +152,42 @@ const hints: Record<string, string> = {
146
152
 
147
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.',
148
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
+
149
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.',
150
158
 
151
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.',
152
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
+
153
191
  // Unification errors
154
192
  'unify_no_src': 'No source provided for unification. Cannot unify without source values.',
155
193
  'unify_no_res': 'Unification produced no result. The values could not be unified.',
@@ -199,12 +237,85 @@ const hints: Record<string, string> = {
199
237
  ' 1.0 + 0d2 -> nil # float with biginteger;\n' +
200
238
  ' 0d0.5 + 1.0 -> nil # ... and the same the other way round.',
201
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
+
202
312
  inexact_integer_sum:
203
313
  'The `integer` leaf holds a value only when it is integral, within\n' +
204
- 'the int64 range, and exactly representable in binary64. This sum\n' +
205
- 'is not: {sum}.\n' +
206
- 'Aontu adds integers exactly and refuses to store a rounded answer\n' +
207
- '-- 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.' +
208
319
  '\n \nExamples:\n' +
209
320
  ' 4503599627370496 + 4503599627370496 -> 9007199254740992 # Exact;\n' +
210
321
  ' 4503599627370496 + 4503599627370497 -> nil # 2^53+1 is not;\n' +
@@ -294,6 +405,92 @@ const codeClasses: Record<string, string> = {
294
405
  parse_unknown: 'parse',
295
406
  parse_bad_src: 'parse',
296
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',
297
494
  func_arity: 'parse',
298
495
  elided_value: 'parse',
299
496
  unify_no_src: 'parse',
@@ -323,6 +520,12 @@ const codeClasses: Record<string, string> = {
323
520
  '|:empty-dist': 'conflict',
324
521
  exact_float_mix: 'conflict',
325
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',
326
529
  decimal_budget: 'conflict',
327
530
  lossy_integer_literal: 'conflict',
328
531
  arg: 'conflict',
@@ -341,6 +544,7 @@ const codeClasses: Record<string, string> = {
341
544
 
342
545
  // incomplete -- residue: the truth requires more than was supplied
343
546
  no_gen: 'incomplete',
547
+ disjunct_no_gen: 'incomplete',
344
548
  conjunct: 'incomplete',
345
549
  mapval_no_gen: 'incomplete',
346
550
  mapval_required: 'incomplete',