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
package/src/graph.ts CHANGED
@@ -1,22 +1,5 @@
1
1
  /* Copyright (c) 2025 Richard Rodger, MIT License */
2
2
 
3
- // THE DERIVED STRUCTURE (G4 phase 3,
4
- // docs/capability-review/g4-identity-relations.md): an evaluated
5
- // document has, besides its value, a GRAPH — the set of checked links,
6
- // each from one tree position to another.
7
- //
8
- // The graph is PATH-NATIVE (ADR-014). There is no second namespace to
9
- // index: a node's address is its path, so the entity index the first
10
- // design carried is exactly the set of paths already in the edges, and
11
- // the node a link starts at is derived from where the link sits rather
12
- // than declared by a mark.
13
- //
14
- // G4's deliverable is that this exists and is DETERMINISTIC. What is
15
- // built on it — impact analysis ("what reaches $.services.auth?"),
16
- // reachability, context-window-sized slices — is a traversal, and its
17
- // exposure as verbs and projections belongs to G7. Relation properties
18
- // (acyclicity, inverse consistency) are G4 phase 5's, and consume
19
- // exactly this edge set.
20
3
 
21
4
  import type { Val } from './type'
22
5
 
@@ -24,35 +7,17 @@ import { cmpCodePoint } from './keyorder'
24
7
 
25
8
 
26
9
  export type Edge = {
27
- // The node the link starts at, as a `$.dotted.path`: the link's own
28
- // position with the relation key and any list indices stripped. `$`
29
- // when the link sits at the top of the document.
30
10
  from: string
31
- // The RELATION: the key the link hangs under, so a link inside a
32
- // list (`dependsOn: [refer() & "$.a"]`) is an edge under `dependsOn`
33
- // rather than under `0`. A rel()-minted link carries its predicate
34
- // declared rather than inferred.
35
11
  key: string
36
- // The address, as the link spells it.
37
12
  to: string
38
13
  // Where the link is, as a `$.dotted.path`, so a report can point at
39
14
  // it.
40
15
  at: string
41
- // Set when the link sits inside a `hide()`-marked subtree. The link
42
- // is still checked and still an edge, but a figure that draws it
43
- // DISCLOSES what the document hides, so the view extractors skip it
44
- // and report it as `hidden_contribution`.
45
16
  hidden?: true
46
17
  }
47
18
 
48
19
  export type Graph = {
49
20
  edges: Edge[]
50
- // The positions of links written under an UNRESOLVED DISJUNCTION.
51
- // ADR-007: an unresolved disjunction is not a value, so a link
52
- // beneath one of its arms is not a fact and is not an edge -- but it
53
- // is not nothing either, and a figure that silently dropped it would
54
- // be the failure the views exist to avoid. Absent when there are
55
- // none, so a graph of a decided document is the shape it always was.
56
21
  disjunct?: string[]
57
22
  }
58
23
 
@@ -66,14 +31,6 @@ const formatPath = (path: string[]): string =>
66
31
  const isIndex = (seg: string): boolean => /^[0-9]+$/.test(seg)
67
32
 
68
33
 
69
- // The node a link starts at and the relation it hangs under, derived
70
- // from the link's own position.
71
- //
72
- // A DECLARED predicate (rel()-minted) is authoritative: the link is cut
73
- // at the key the rel() sat on, wherever that is on the way down, which
74
- // is what makes a MAP-valued relation report the relation rather than
75
- // the inner label. Without one the relation is INFERRED: strip the list
76
- // indices, and the first real key above the link is it.
77
34
  const cut = (
78
35
  at: string[], relkey: string | undefined
79
36
  ): { from: string, key: string } => {
@@ -92,11 +49,6 @@ const cut = (
92
49
  }
93
50
 
94
51
 
95
- // The graph of an evaluated tree. Walks POSITIONS, not values: a
96
- // reference or a spread can put one value object at several positions,
97
- // and a walk guarded by object identity would find the first and miss
98
- // every other place it is reached. The guard is therefore the ancestor
99
- // chain — which is what a cycle actually is.
100
52
  export function graphOf(root: Val): Graph {
101
53
  const edges: Edge[] = []
102
54
  const disjunct: string[] = []
@@ -136,11 +88,6 @@ export function graphOf(root: Val): Graph {
136
88
  visit(node.held, path, ancestors, hidden, undecided)
137
89
  }
138
90
 
139
- // An unresolved conjunction (a link waiting on a peer that never
140
- // came, a constraint still open) holds its terms at the SAME
141
- // position; every link among them is written there, and is an
142
- // edge. This is what a match-selected branch or a deferred refer()
143
- // looks like after evaluation.
144
91
  if (true === node.isConjunct && Array.isArray(node.peg)) {
145
92
  ancestors.add(node)
146
93
  for (const term of node.peg) {
@@ -149,10 +96,6 @@ export function graphOf(root: Val): Graph {
149
96
  ancestors.delete(node)
150
97
  }
151
98
 
152
- // AN UNRESOLVED DISJUNCTION IS NOT A VALUE (ADR-007), so a link
153
- // under one of its arms is not an edge. Its POSITION is collected
154
- // instead, so a figure can report what the document leaves
155
- // undecided rather than drawing it or dropping it in silence.
156
99
  if (true === node.isDisjunct && Array.isArray(node.peg)) {
157
100
  ancestors.add(node)
158
101
  for (const arm of node.peg) {
@@ -172,10 +115,6 @@ export function graphOf(root: Val): Graph {
172
115
 
173
116
  visit(root, [], new Set(), false, false)
174
117
 
175
- // DETERMINISTIC by construction, not by luck: edges by the position
176
- // they are written at, which is unique — one link, one place. That
177
- // holds through a conjunction too: its terms share the position, and
178
- // two links there would have had to unify into one.
179
118
  edges.sort((a, b) => cmpCodePoint(a.at, b.at))
180
119
 
181
120
  if (0 < disjunct.length) {
package/src/hcanon.ts CHANGED
@@ -1,44 +1,5 @@
1
1
  /* Copyright (c) 2025 Richard Rodger, MIT License */
2
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
- // An ALIAS REFERENCE left standing in a spread template renders its
20
- // EXPANSION through this same walk rather than through the reference's
21
- // own canon, so a close() or a mark on the aliased value survives into
22
- // the hash. Without that the wrappers above are absent exactly where
23
- // the alias filter has already erased the declaration that carried
24
- // them (BUGS.md §60).
25
- //
26
- // The marks PROPAGATE to every descendant at unification (walkMark), so
27
- // a wrapper is emitted only where a mark STARTS: the walk carries the
28
- // inherited marks down and a child whose mark the parent already
29
- // carries renders bare. Without that, hide({a:1}) would render every
30
- // leaf re-wrapped — still correct, never minimal, and not what the
31
- // source said.
32
- //
33
- // canonHash (G6 phase 1) is the pin built on it:
34
- // "aon1-" + base64url( SHA-256( UTF-8( hcanon(v) ) ) )
35
- // (unpadded base64url, RFC 4648 section 5). The "aon1-" scheme id
36
- // exists so a future semantically-stronger normal form is an upgrade,
37
- // not a breakage. This is a CANONICAL-TEXT hash, not a semantic
38
- // equivalence class: the failure direction is the safe one — a false
39
- // "changed" forces a needless re-review; a false "unchanged" would need
40
- // two hash forms with the same bytes and different meanings, which is
41
- // exactly the gap the close/mark wrappers exist to shut.
42
3
 
43
4
  import { createHash } from 'node:crypto'
44
5
 
@@ -53,15 +14,6 @@ type HMarks = {
53
14
  }
54
15
 
55
16
 
56
- // One node's rendering, carrying the marks the ANCESTORS already
57
- // wrapped. Bags and junctions recurse structurally (their canon getters
58
- // render children through plain canon, which would drop a nested
59
- // close), and so does an expanded alias reference, for the reason its
60
- // own arm gives. Everything else — scalars, kinds, funcs, constraints,
61
- // and a reference with nothing to expand — delegates to its own canon,
62
- // whose text is already in cross-port parity. The non-Val arm mirrors
63
- // MapVal.canon's raw-peg fallback and is unreachable through an
64
- // evaluated tree (direct-tested, ADR-002).
65
17
  function render(v: any, inh: HMarks): string {
66
18
  if (true !== v?.isVal) {
67
19
  return String(v)
@@ -76,12 +28,6 @@ function render(v: any, inh: HMarks): string {
76
28
 
77
29
  let s: string
78
30
  if (true === v.isMap) {
79
- // Alias declarations are dropped here for the same reason
80
- // MapVal.canon drops them, and this is the surface where it counts:
81
- // `aon1-` pins MEANING, so a document written with aliases and the
82
- // same document written longhand must hash to one string. Two
83
- // renderers, one rule -- hcanon is not canon and does not inherit
84
- // the filter (docs/design/ALIASES.0.md §4).
85
31
  const keys = Object.keys(v.peg)
86
32
  .filter((k) => !v.aliasKeys.includes(k))
87
33
  .sort(cmpCodePoint)
@@ -115,22 +61,6 @@ function render(v: any, inh: HMarks): string {
115
61
  else if (true === v.isConjunct || true === v.isDisjunct) {
116
62
  s = junctionText(v, true === v.isConjunct ? '&' : '|', inner)
117
63
  }
118
- // AN EXPANDED ALIAS REFERENCE IS RENDERED, NOT DELEGATED (BUGS.md
119
- // §60). A reference standing after unification is one inside a
120
- // spread template, and `RefVal.canon` answers with the EXPANSION's
121
- // plain canon -- which drops exactly what this renderer exists to
122
- // keep. The declaration carrying `close()` or a mark is erased by
123
- // the alias filter above, so a `close()` lost here is lost from the
124
- // hash entirely: `%A = close({n:string})` and `%A = {n:string}`,
125
- // used as `box: [&: %A]`, hashed to ONE STRING while refusing and
126
- // admitting `{n:"x",z:1}` respectively -- a change of meaning the
127
- // pin reported as no change, in the unsafe direction. Recursing
128
- // through `inner` is what makes the alias form and its longhand
129
- // twin agree again, which is ALIASES.0.md §4's own requirement.
130
- //
131
- // A reference with NO expansion still spells its name: a plain
132
- // `$.A` names a key the hash form still carries in full, and the
133
- // knot of a recursive alias inside its own template never gets one.
134
64
  else if (true === v.isRef && undefined !== v.expansion) {
135
65
  s = render(v.expansion, inner)
136
66
  }
@@ -160,14 +90,6 @@ function render(v: any, inh: HMarks): string {
160
90
  }
161
91
 
162
92
 
163
- // The JunctionVal.canon parenthesisation rule, kept: a member that is
164
- // itself a junction with more than one term keeps its parens so the
165
- // text reparses with the same structure (`(1|2)&3`, not the
166
- // differently-parsing `1|2&3`). Post-unification junctions are
167
- // flattened by norm, so no SOURCE reaches the wrapping arm -- it is
168
- // pinned by direct tests over constructed Vals in both ports, because
169
- // a hash form that could render ambiguously would be a pin that
170
- // silently agrees with a document it should not.
171
93
  function junctionText(v: any, sym: string, inner: HMarks): string {
172
94
  return v.peg.map((m: any) =>
173
95
  true === m?.isJunction && 1 < m.peg.length
@@ -185,10 +107,6 @@ export function hcanon(v: Val): string {
185
107
  }
186
108
 
187
109
 
188
- // The canon-hash pin. Scoped to the module evaluated STANDALONE: its
189
- // own include closure resolved and unified at its own root, before any
190
- // consumer context — which is what makes the pin transitive (an edit
191
- // two includes deep changes the unified root, hence the hash).
192
110
  export function canonHash(v: Val): string {
193
111
  return 'aon1-' +
194
112
  createHash('sha256').update(hcanon(v), 'utf8').digest('base64url')
package/src/helpdoc.ts CHANGED
@@ -41,7 +41,7 @@ const HELPDOC: HelpTopic[] = [
41
41
  "topic": "grammar",
42
42
  "summary": "the published ABNF, for a parser or a constrained decoder",
43
43
  "source": "grammar/aontu.abnf",
44
- "text": "; Aontu --- published grammar (ABNF, RFC 5234 + RFC 7405).\n;\n; The same language as grammar/aontu.gbnf, rule for rule and name for\n; name, in the notation an RFC reader expects. The GBNF form is for a\n; constrained decoder; THIS form is for a person, and for the railroad\n; diagram in the language reference, which is generated from this file\n; (ts/scripts/figures.cjs).\n;\n; It covers the DOCUMENTED EMISSION SURFACE: what a model should be\n; allowed to write, which is a superset of JSON plus the operators,\n; constraints and marks the language's own canonical form emits. It is\n; CONSERVATIVE BY CONSTRUCTION --- it may accept less than the parser\n; does, never more. The same two deliberate exclusions the GBNF has:\n;\n; - `@\"...\"` includes. A generated document should describe values,\n; not reach for files.\n; - Unquoted keys and the other spellings the parser tolerates.\n; Canon quotes every key, and one spelling is what a grammar is\n; for.\n;\n; TWO NOTATION CHOICES worth stating, because both are load-bearing.\n;\n; EVERY LITERAL IS CASE-SENSITIVE, spelled `%s\"...\"` (RFC 7405). A\n; plain `\"...\"` is case-INSENSITIVE in RFC 5234, and Aontu is not:\n; `TRUE` is a bare word and `true` is a boolean. The reader in\n; ts/scripts/abnf.cjs refuses a bare quoted string rather than guess\n; which was meant.\n;\n; ALTERNATION IS ORDERED. RFC 5234's `/` is formally unordered, and\n; the consumers of this file (a PEG-style matcher here, a railroad\n; renderer) take the first branch that matches. Where one spelling is\n; a prefix of another the longer comes first --- `exact` before\n; `number`, `refer` before `rem` before `re`, `biginteger` before\n; `boolean` --- so the ordered reading and the unordered one accept\n; the same language. ts/test/grammar.test.ts holds this file to the\n; whole canon corpus of test/spec/*.tsv, which is what proves it.\n\nroot = ws value ws\n\n; No pipe. `|>` was parse-time sugar; it was removed, `x |> f(a)`\n; being written `f(x, a)`.\nvalue = disjunct\n\ndisjunct = conjunct *( ws %s\"|\" ws conjunct )\n\nconjunct = prefixed *( ws %s\"&\" ws prefixed )\n\n; A preference marks the alternative a generation picks.\nprefixed = %s\"*\" ws prefixed / sum\n\nsum = atom *( ws %s\"+\" ws atom )\n\natom = map\n / list\n / func\n / ref\n / kind\n / place\n / scalar\n / %s\"(\" ws value ws %s\")\"\n\nmap = %s\"{\" ws [ entry *( ws %s\",\" ws entry ) ws ] %s\"}\"\n\nentry = spread / pair\n\n; The template every key of the bag must also satisfy.\nspread = %s\"&\" ws %s\":\" ws value\n\npair = string ws [ %s\"?\" ] ws %s\":\" ws value\n\n; A list ELEMENT is a value, not a pair --- only the template is keyed.\nlist = %s\"[\" ws [ element *( ws %s\",\" ws element ) ws ] %s\"]\"\n\nelement = spread / value\n\n; The builtins, applied. The name set is closed on purpose: an unknown\n; function is a parse-time error in the engine, so a grammar that\n; allowed any name would over-approximate.\nfunc = name %s\"(\" ws [ value *( ws %s\",\" ws value ) ws ] %s\")\"\n\n; ORDER MATTERS where one name is a prefix of another: `refer` is\n; listed before `re`, and `rem` before `re` as well.\nname = %s\"above\" / %s\"acyclic\" / %s\"add\" / %s\"below\" / %s\"close\"\n / %s\"copy\" / %s\"deprecate\" / %s\"div\"\n / %s\"each\" / %s\"emit\" / %s\"esc\" / %s\"filter\" / %s\"greatest\"\n / %s\"hide\"\n / %s\"inverse\" / %s\"join\" / %s\"key\" / %s\"least\"\n / %s\"length\" / %s\"list\" / %s\"lower\" / %s\"map\" / %s\"match\"\n / %s\"max\" / %s\"min\" / %s\"mod\" / %s\"move\"\n / %s\"mul\" / %s\"must\"\n / %s\"neq\"\n / %s\"open\" / %s\"pack\" / %s\"path\" / %s\"pick\" / %s\"pref\"\n / %s\"refer\" / %s\"rel\" / %s\"rem\" / %s\"rep\" / %s\"re\" / %s\"split\"\n / %s\"super\"\n / %s\"sub\" / %s\"sum\"\n / %s\"type\"\n / %s\"unique\" / %s\"upper\" / %s\"usc\"\n\n; A path reference, absolute from the document root. At least one\n; segment: a bare `$` is an incomplete expression, not a reference.\n; A RELATIVE reference has no `$`: `.n` names a sibling, resolved\n; against the enclosing map rather than the document root. Canon emits\n; one wherever a spread template survives unresolved, so a grammar\n; without it cannot parse this engine's own output. No conflict with\n; `number`: a numeric literal always starts with a digit or `-`.\nref = %s\"$\" 1*( %s\".\" segment ) / 1*( %s\".\" segment )\n\n; No `-`: it is not a bare-text character (test/spec/op-chars.tsv pins\n; `a:6-2` as a parse error), so admitting it would over-approximate.\nsegment = 1*( ALPHA / DIGIT / %s\"_\" )\n\n; The placeholder: a hole a call is filled through. BARE only --- `\"_\"`\n; is an ordinary string, and a longer bare word containing it is\n; ordinary text.\nplace = %s\"_\"\n\n; `biginteger` before `bigdecimal` is not required (they differ at the\n; fourth character), but `biginteger` before `boolean` is: see the\n; ordered-alternation note above.\nkind = %s\"biginteger\" / %s\"bigdecimal\" / %s\"boolean\" / %s\"float\"\n / %s\"integer\" / %s\"number\" / %s\"string\" / %s\"top\" / %s\"nil\"\n\n; `exact` before `number`, or `0d5` would match `number` as the single\n; digit `0` and leave `d5` unconsumed.\nscalar = string / exact / number / %s\"true\" / %s\"false\" / %s\"null\"\n\nstring = DQUOTE *char DQUOTE\n\nchar = unescaped / %x5C escape\n\n; Every code point but the quote and the backslash, which is what the\n; GBNF's `[^\"\\\\]` says. Control characters included: canon writes them\n; escaped, and a grammar that refused them would refuse less than the\n; parser accepts in the one direction this file may not.\nunescaped = %x00-21 / %x23-5B / %x5D-10FFFF\n\nescape = DQUOTE / %x5C / %s\"/\" / %s\"b\" / %s\"f\" / %s\"n\" / %s\"r\"\n / %s\"t\" / %s\"u\" hex hex hex hex\n\nhex = DIGIT / %x41-46 / %x61-66\n\n; The exact leaves: arbitrary precision, spelled with the 0d marker.\nexact = [ %s\"-\" ] %s\"0d\" digits [ %s\".\" digits ] [ exponent ]\n\nnumber = [ %s\"-\" ] digits [ %s\".\" digits ] [ exponent ]\n\nexponent = ( %s\"e\" / %s\"E\" ) [ %s\"-\" / %s\"+\" ] digits\n\ndigits = 1*DIGIT\n\nws = *( %x20 / %x09 / %x0A / %x0D )\n\n; RFC 5234's core rules, written out so this file stands alone.\nALPHA = %x41-5A / %x61-7A\nDIGIT = %x30-39\nDQUOTE = %x22\n"
44
+ "text": "; Aontu --- published grammar (ABNF, RFC 5234 + RFC 7405).\n;\n; The same language as grammar/aontu.gbnf, rule for rule and name for\n; name, in the notation an RFC reader expects. The GBNF form is for a\n; constrained decoder; THIS form is for a person, and for the railroad\n; diagram in the language reference, which is generated from this file\n; (ts/scripts/figures.cjs).\n;\n; It covers the DOCUMENTED EMISSION SURFACE: what a model should be\n; allowed to write, which is a superset of JSON plus the operators,\n; constraints and marks the language's own canonical form emits. It is\n; CONSERVATIVE BY CONSTRUCTION --- it may accept less than the parser\n; does, never more. The same two deliberate exclusions the GBNF has:\n;\n; - `@\"...\"` includes. A generated document should describe values,\n; not reach for files.\n; - Unquoted keys and the other spellings the parser tolerates.\n; Canon quotes every key, and one spelling is what a grammar is\n; for.\n;\n; TWO NOTATION CHOICES worth stating, because both are load-bearing.\n;\n; EVERY LITERAL IS CASE-SENSITIVE, spelled `%s\"...\"` (RFC 7405). A\n; plain `\"...\"` is case-INSENSITIVE in RFC 5234, and Aontu is not:\n; `TRUE` is a bare word and `true` is a boolean. The reader in\n; ts/scripts/abnf.cjs refuses a bare quoted string rather than guess\n; which was meant.\n;\n; ALTERNATION IS ORDERED. RFC 5234's `/` is formally unordered, and\n; the consumers of this file (a PEG-style matcher here, a railroad\n; renderer) take the first branch that matches. Where one spelling is\n; a prefix of another the longer comes first --- `exact` before\n; `number`, `refer` before `rem` before `re`, `biginteger` before\n; `boolean` --- so the ordered reading and the unordered one accept\n; the same language. ts/test/grammar.test.ts holds this file to the\n; whole canon corpus of test/spec/*.tsv, which is what proves it.\n\nroot = ws value ws\n\n; No pipe. `|>` was parse-time sugar; it was removed, `x |> f(a)`\n; being written `f(x, a)`.\nvalue = disjunct\n\ndisjunct = conjunct *( ws %s\"|\" ws conjunct )\n\nconjunct = prefixed *( ws %s\"&\" ws prefixed )\n\n; A preference marks the alternative a generation picks.\nprefixed = %s\"*\" ws prefixed / sum\n\nsum = atom *( ws %s\"+\" ws atom )\n\natom = map\n / list\n / func\n / ref\n / kind\n / place\n / scalar\n / %s\"(\" ws value ws %s\")\"\n\nmap = %s\"{\" ws [ entry *( ws %s\",\" ws entry ) ws ] %s\"}\"\n\nentry = spread / pair\n\n; The template every key of the bag must also satisfy.\nspread = %s\"&\" ws %s\":\" ws value\n\npair = string ws [ %s\"?\" ] ws %s\":\" ws value\n\n; A list ELEMENT is a value, not a pair --- only the template is keyed.\nlist = %s\"[\" ws [ element *( ws %s\",\" ws element ) ws ] %s\"]\"\n\nelement = spread / value\n\n; The builtins, applied. The name set is closed on purpose: an unknown\n; function is a parse-time error in the engine, so a grammar that\n; allowed any name would over-approximate.\nfunc = name %s\"(\" ws [ value *( ws %s\",\" ws value ) ws ] %s\")\"\n\n; ORDER MATTERS where one name is a prefix of another: `refer` is\n; listed before `re`, and `rem` before `re` as well.\nname = %s\"abnf\" / %s\"above\" / %s\"acyclic\" / %s\"add\" / %s\"below\" / %s\"close\"\n / %s\"copyfiles\" / %s\"copy\" / %s\"deprecate\" / %s\"div\"\n / %s\"each\" / %s\"emit\" / %s\"esc\" / %s\"filter\" / %s\"greatest\"\n / %s\"hide\"\n / %s\"inverse\" / %s\"join\" / %s\"key\" / %s\"least\"\n / %s\"length\" / %s\"listitems\" / %s\"list\" / %s\"lower\" / %s\"map\" / %s\"match\"\n / %s\"maybe\" / %s\"max\" / %s\"min\" / %s\"mod\" / %s\"move\"\n / %s\"mul\" / %s\"must\"\n / %s\"neq\"\n / %s\"open\" / %s\"pack\" / %s\"parse\" / %s\"path\" / %s\"pick\" / %s\"pref\"\n / %s\"refer\" / %s\"rel\" / %s\"rem\" / %s\"rep\" / %s\"re\" / %s\"sort\" / %s\"split\"\n / %s\"super\"\n / %s\"content\" / %s\"file\" / %s\"folder\" / %s\"fragment\" / %s\"inject\"\n / %s\"line\" / %s\"nom\" / %s\"project\" / %s\"slot\" / %s\"translate\"\n / %s\"sub\" / %s\"sum\"\n / %s\"type\"\n / %s\"unique\" / %s\"upper\" / %s\"usc\"\n\n; A path reference, absolute from the document root. At least one\n; segment: a bare `$` is an incomplete expression, not a reference.\n; A RELATIVE reference has no `$`: `.n` names a sibling, resolved\n; against the enclosing map rather than the document root. Canon emits\n; one wherever a spread template survives unresolved, so a grammar\n; without it cannot parse this engine's own output. No conflict with\n; `number`: a numeric literal always starts with a digit or `-`.\nref = %s\"$\" 1*( %s\".\" segment ) / 1*( %s\".\" segment )\n\n; No `-`: it is not a bare-text character (test/spec/op-chars.tsv pins\n; `a:6-2` as a parse error), so admitting it would over-approximate.\nsegment = 1*( ALPHA / DIGIT / %s\"_\" )\n\n; The placeholder: a hole a call is filled through. BARE only --- `\"_\"`\n; is an ordinary string, and a longer bare word containing it is\n; ordinary text.\nplace = %s\"_\"\n\n; `biginteger` before `bigdecimal` is not required (they differ at the\n; fourth character), but `biginteger` before `boolean` is: see the\n; ordered-alternation note above.\nkind = %s\"biginteger\" / %s\"bigdecimal\" / %s\"boolean\" / %s\"float\"\n / %s\"integer\" / %s\"number\" / %s\"string\" / %s\"top\" / %s\"nil\"\n\n; `exact` before `number`, or `0d5` would match `number` as the single\n; digit `0` and leave `d5` unconsumed.\nscalar = string / exact / number / %s\"true\" / %s\"false\" / %s\"null\"\n\nstring = DQUOTE *char DQUOTE\n\nchar = unescaped / %x5C escape\n\n; Every code point but the quote and the backslash, which is what the\n; GBNF's `[^\"\\\\]` says. Control characters included: canon writes them\n; escaped, and a grammar that refused them would refuse less than the\n; parser accepts in the one direction this file may not.\nunescaped = %x00-21 / %x23-5B / %x5D-10FFFF\n\nescape = DQUOTE / %x5C / %s\"/\" / %s\"b\" / %s\"f\" / %s\"n\" / %s\"r\"\n / %s\"t\" / %s\"u\" hex hex hex hex\n\nhex = DIGIT / %x41-46 / %x61-66\n\n; The exact leaves: arbitrary precision, spelled with the 0d marker.\nexact = [ %s\"-\" ] %s\"0d\" digits [ %s\".\" digits ] [ exponent ]\n\nnumber = [ %s\"-\" ] digits [ %s\".\" digits ] [ exponent ]\n\nexponent = ( %s\"e\" / %s\"E\" ) [ %s\"-\" / %s\"+\" ] digits\n\ndigits = 1*DIGIT\n\nws = *( %x20 / %x09 / %x0A / %x0D )\n\n; RFC 5234's core rules, written out so this file stands alone.\nALPHA = %x41-5A / %x61-7A\nDIGIT = %x30-39\nDQUOTE = %x22\n"
45
45
  }
46
46
  ]
47
47
 
package/src/hints.ts CHANGED
@@ -1,11 +1,5 @@
1
1
  /* Copyright (c) 2025 Richard Rodger, MIT License */
2
2
 
3
- /**
4
- * Error code hints for Aontu unification errors.
5
- *
6
- * Each key is an error code that can be passed to makeNilErr.
7
- * Each value is a human-readable explanation of what the error means.
8
- */
9
3
 
10
4
  const hints: Record<string, string> = {
11
5
 
@@ -40,7 +34,6 @@ const hints: Record<string, string> = {
40
34
  'when nothing else does.',
41
35
 
42
36
 
43
- // TODO: extend errors to have details so we can name the key
44
37
  mapval_required: 'This map value is required.',
45
38
 
46
39
  mapval_no_gen:
@@ -108,6 +101,31 @@ const hints: Record<string, string> = {
108
101
  ' # with "tier";\n' +
109
102
  ' min(0) & must(integer,"whole") & 3 -> 3 # Bands compose.',
110
103
 
104
+ abnf_grammar:
105
+ 'This ABNF grammar could not be compiled:\n' +
106
+ '{reason}\n' +
107
+ ' \n' +
108
+ 'abnf() takes RFC 5234 ABNF -- `=` and `/`, not `::=`. The\n' +
109
+ 'compiler reports the first thing it could not read; a rule\n' +
110
+ 'referenced but never defined is the usual cause, after a\n' +
111
+ 'quantifier written the EBNF way.',
112
+
113
+ parse_arg:
114
+ 'parse(grammar, text) takes two strings: a grammar, normally the\n' +
115
+ 'answer of an abnf() call, and the text to parse.\n' +
116
+ ' \n' +
117
+ 'Examples:\n' +
118
+ ' G: abnf("v = 1*DIGIT")\n' +
119
+ ' a: parse($.G, "12") # the AST\n' +
120
+ ' b: parse($.G, 12) # parse_arg: the text is not a string',
121
+
122
+ parse_failed:
123
+ 'The text does not parse under this grammar:\n' +
124
+ '{reason}\n' +
125
+ ' \n' +
126
+ 'A failure to parse is a failure to unify, so the field is\n' +
127
+ 'refused rather than set to a value meaning "no".',
128
+
111
129
  constraint_pattern:
112
130
  'This re() pattern is outside the supported subset. It uses\n' +
113
131
  '{reason}.\n' +
@@ -176,8 +194,6 @@ const hints: Record<string, string> = {
176
194
  bare_punct: 'A bare string holds letters, digits, `-` and `_`, and nothing else.\nThis one holds `{char}`, in `{text}`. Every other punctuation\ncharacter is either syntax or an error, never silently part of a\nstring: a value that needs one is written quoted, and a `>` or `<`\nthat was meant as a bound is written as min(x), max(x), above(x) or\nbelow(x).\n \nExamples:\n a: team-payments -> "team-payments" # `-` and `_` are text;\n a: 2026-09-05 -> "2026-09-05" # ... digits included;\n a: x=y -> nil # `=` is not;\n a: "x=y" -> "x=y" # ... so quote it;\n a: >10 -> nil # Not an operator: write above(10).',
177
195
 
178
196
 
179
-
180
-
181
197
  recursion_unexpanded: 'A schema refers to itself here, and no data reached this position\nto expand it against. Guard the recursion -- an optional key\n(next?:) drops when nothing arrives, and a preferred alternative\n(*null | $.Node) generates -- or supply the data.\n \nExamples:\n Node: {v: integer, next?: $.Node}\n t: $.Node & {v: 1} -> {..} # next? drops;\n Node: {v: integer, next: $.Node}\n t: $.Node & {v: 1} -> nil # ... required refuses.',
182
198
  recursion_budget: 'A recursive schema expanded past the evaluation depth budget\nwithout meeting concrete data. Expansion is driven by the data --\nfinite data always terminates -- so a chain this deep means two\ndefinitions feeding each other, or data deeper than the budget\n(docs/trust.md raises it deliberately).',
183
199
  list_length: 'A literal list alternative in a disjunction admits only a list of\nits own length -- a spread (&:) makes it variadic. Outside a\ndisjunction two statements of one list still merge elementwise.\n \nExamples:\n x: [] | [&: integer]\n x: [1, 2] -> [1,2] # The variadic arm;\n x: [] -> [] # ... or exactly empty;\n y: [a] | [b]\n y: [a, extra] -> nil # ... a literal arm is its length.',
@@ -204,15 +220,6 @@ const hints: Record<string, string> = {
204
220
 
205
221
  format_check: 'The formatted text is not the same document, so nothing was written.\nThis is a formatter defect: please report it, with the source.',
206
222
 
207
- // THIS PORT NEVER RAISES decimal_syntax -- Go's construct.go does,
208
- // and go/hints.go's header records that the CODE is Go-only. The
209
- // TEXT is here anyway, verbatim, because since G11 phase 3 this
210
- // table is a LOOKUP surface as well as a message source: the code is
211
- // in the shared registry (test/spec/errcodes.tsv), so
212
- // `aontu explain decimal_syntax` must answer the same in both ports
213
- // or the agent that met the error under one binary learns nothing
214
- // from the other. An entry for a code this port cannot raise is
215
- // never read on an error path, only on that lookup.
216
223
  decimal_syntax: 'This 0d literal is not a valid exact number.',
217
224
  view_style_profile: 'Each profile has ONE way to carry the meaning of a figure\'s marks:\nSGR escapes for text, CSS classes for svg. Asking for the other one is\na usage error rather than a silent no-op. `none` works everywhere.',
218
225
  view_style_unknown: 'The styles are none, ansi and css, plus `auto` at the command line,\nwhich the command resolves before the library runs: whether the\ndestination is a terminal is not something a library can see.',
@@ -345,6 +352,41 @@ const hints: Record<string, string> = {
345
352
  ' pick([{a:1},{b:2}], a) -> nil # ... the second does not;\n' +
346
353
  ' pick([[9],[8]], 0) -> [9,8] # A list child takes an index.',
347
354
 
355
+ sort_key:
356
+ 'A child of this bag has no key `{key}` to order by. Ordering\n' +
357
+ 'refuses rather than skipping, for the reason `pick` does: a\n' +
358
+ 'shorter list orders a DIFFERENT set of records than the one the\n' +
359
+ 'author named. Give every child the key, or filter the bag first.\n' +
360
+ ' \n' +
361
+ 'Examples:\n' +
362
+ ' sort([{a:2},{a:1}], a) -> [{a:1},{a:2}] # Every child has it;\n' +
363
+ ' sort([{a:1},{b:2}], a) -> nil # ... the second does not;\n' +
364
+ ' sort([[9],[8]], 0) -> [[8],[9]] # A list child takes an index.',
365
+
366
+ sort_domain:
367
+ 'This bag cannot be ordered: `{member}`. There are two orders and no\n' +
368
+ 'third -- text by code point, numbers by the exact comparator -- so a\n' +
369
+ 'bag that mixes them, or holds a boolean, a null or a container, has\n' +
370
+ 'no order to be put in. Project a field that is all one kind, or\n' +
371
+ 'filter the bag first.\n' +
372
+ ' \n' +
373
+ 'Examples:\n' +
374
+ ' sort([3,1,2]) -> [1,2,3] # All numbers;\n' +
375
+ ' sort([b,a]) -> ["a","b"] # ... or all text;\n' +
376
+ ' sort([1,a]) -> nil # ... never both.',
377
+
378
+ sort_dir:
379
+ 'A sort direction names no direction: `{dir}`. The third argument is\n' +
380
+ '`asc` or `desc`, and omitting it is `asc`. The second argument is\n' +
381
+ 'the field to order by, so a keyless descending sort writes the\n' +
382
+ 'empty projector: the member itself.\n' +
383
+ ' \n' +
384
+ 'Examples:\n' +
385
+ ' sort($.rows, n) # Ascending by field `n`;\n' +
386
+ ' sort($.rows, n, desc) # ... descending;\n' +
387
+ ' sort($.tags) # The members themselves, ascending;\n' +
388
+ ' sort($.tags, "", desc) # ... descending.',
389
+
348
390
  join_member:
349
391
  'A member of this bag is not text and never will be: `{member}`.\n' +
350
392
  '`join` folds with `+` seeded with the empty string, and `+` with a\n' +
@@ -479,8 +521,6 @@ const hints: Record<string, string> = {
479
521
  'empty': 'Empty disjunction. The disjunction has no valid alternatives.',
480
522
  'empty-dist': 'Empty disjunction distribution. All alternatives in the disjunction are invalid.',
481
523
 
482
- // ADR-011 R2: two DEFAULTS of equal rank that cannot agree. The
483
- // fix is a rank, so the hint names it.
484
524
  'pref_rank_clash': 'Two defaults of the same rank disagree.' +
485
525
  ' Rank one of them (`**x`) to say which is the weaker layer,' +
486
526
  ' or give them the same value.',
@@ -508,15 +548,6 @@ const hints: Record<string, string> = {
508
548
  }
509
549
 
510
550
 
511
- // codeClasses assigns every error code a CLASS: conflict | incomplete |
512
- // reference | parse | budget | internal. The contract lives in
513
- // test/spec/errcodes.tsv (mode `errcode`): the spec suite executes one
514
- // row per code against this table and asserts SET EQUALITY between the
515
- // file and these keys, in both implementations (go/hints.go mirrors
516
- // this map exactly). Codes are append-only and never renamed; a class
517
- // change is a breaking change. Class rulings (why decimal_budget and
518
- // lossy_integer_literal are conflict, not budget; why unknown_function
519
- // is reference) are documented in the tsv header.
520
551
  const codeClasses: Record<string, string> = {
521
552
  // parse -- the source text is malformed or unusable
522
553
  parse: 'parse',
@@ -551,10 +582,6 @@ const codeClasses: Record<string, string> = {
551
582
  patch_ambiguous: 'reference',
552
583
  patch_span_mismatch: 'internal',
553
584
 
554
- // G4 phase 2 -- the checked link: a string that is not a tree
555
- // address (class `parse`, the text is wrong), and an address that
556
- // names nothing in this evaluation (class `reference`, the same
557
- // class as `no_path`, because it is the same kind of miss).
558
585
  refer_address: 'parse',
559
586
  rel_address: 'parse',
560
587
  refer_unresolved: 'reference',
@@ -595,10 +622,6 @@ const codeClasses: Record<string, string> = {
595
622
  // class as refer_address, because it is the same mistake.
596
623
  path_address: 'parse',
597
624
 
598
- // G8 phase 1 -- the generation combinators. All three are class
599
- // `parse`: what is wrong is the CALL as written (data that is not a
600
- // bag, a list element that is not a name), not any pair of values a
601
- // meet brought together.
602
625
  pack_data: 'parse',
603
626
  pack_key: 'parse',
604
627
  each_data: 'parse',
@@ -611,24 +634,12 @@ const codeClasses: Record<string, string> = {
611
634
  filter_data: 'parse',
612
635
  match_none: 'conflict',
613
636
 
614
- // G9 phase 6 -- the string builtins. All five are class `parse`:
615
- // what is wrong is the CALL as written -- a variant that names no
616
- // convention, a pattern outside the subset, a substitution naming a
617
- // group that does not exist, a separator that is neither string nor
618
- // pattern. `usc_malformed` is the odd one and still `parse`: the
619
- // TEXT the call was given has no inverse, which is a fact about the
620
- // argument rather than about any meet.
621
637
  esc_variant: 'parse',
622
638
  usc_malformed: 'parse',
623
639
  rep_pattern: 'parse',
624
640
  rep_sub: 'parse',
625
641
  split_sep: 'parse',
626
642
 
627
- // G9 phase 6 -- apply-templates. The four shape codes are class
628
- // `parse`: what is wrong is the CALL as written -- a selection with
629
- // no children, a table that is not one, a rule missing a half.
630
- // `emit_none` is class `conflict` for `match_none`'s reason: the
631
- // node and every pattern written for it disagreed.
632
643
  emit_data: 'parse',
633
644
  emit_table: 'parse',
634
645
  emit_template: 'parse',
@@ -636,19 +647,11 @@ const codeClasses: Record<string, string> = {
636
647
  emit_none: 'conflict',
637
648
  emit_ref: 'conflict',
638
649
 
639
- // RENDER P6 -- `replace` on a template, and `form`. The two
640
- // template checks are class `parse`: what is wrong is the TEMPLATE
641
- // as written, before any node. `replace_value` is class `conflict`:
642
- // the node's value and the body that wanted text disagreed.
643
- // `form_data` is `each_data`'s retired twin (ADR-027).
644
650
  replace_overlap: 'parse',
645
651
  replace_unused: 'parse',
646
652
  replace_value: 'conflict',
647
653
  form_data: 'parse',
648
654
 
649
- // G8 phase 3 -- the placeholder. Class `conflict`: two values met
650
- // and neither could answer for the other, which is what every
651
- // conflict is.
652
655
  place_pair: 'conflict',
653
656
 
654
657
  // G6 phase 2 -- modules. Both are class `parse`: a module import is
@@ -689,6 +692,9 @@ const codeClasses: Record<string, string> = {
689
692
  constraint: 'conflict',
690
693
  must: 'conflict',
691
694
  constraint_pattern: 'conflict',
695
+ abnf_grammar: 'parse',
696
+ parse_arg: 'parse',
697
+ parse_failed: 'conflict',
692
698
  scalar_value: 'conflict',
693
699
  scalar_kind: 'conflict',
694
700
  no_scalar_unify: 'conflict',
@@ -706,6 +712,9 @@ const codeClasses: Record<string, string> = {
706
712
  exact_float_mix: 'conflict',
707
713
  inexact_integer_sum: 'conflict',
708
714
  pick_key: 'conflict',
715
+ sort_key: 'conflict',
716
+ sort_domain: 'conflict',
717
+ sort_dir: 'parse',
709
718
  aggregate_data: 'conflict',
710
719
  aggregate_empty: 'conflict',
711
720
  join_member: 'conflict',