aontu 0.62.0 → 0.64.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 (373) hide show
  1. package/README.md +7 -7
  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 +3 -3
  8. package/dist/aontu.js +4 -84
  9. package/dist/aontu.js.map +1 -1
  10. package/dist/aontumodel.d.ts +4 -0
  11. package/dist/aontumodel.js +27 -0
  12. package/dist/aontumodel.js.map +1 -0
  13. package/dist/casing.d.ts +5 -0
  14. package/dist/casing.js +90 -0
  15. package/dist/casing.js.map +1 -0
  16. package/dist/cli.d.ts +2 -2
  17. package/dist/cli.js +228 -935
  18. package/dist/cli.js.map +1 -1
  19. package/dist/ctx.js +0 -48
  20. package/dist/ctx.js.map +1 -1
  21. package/dist/diff.js +0 -32
  22. package/dist/diff.js.map +1 -1
  23. package/dist/err.js +0 -40
  24. package/dist/err.js.map +1 -1
  25. package/dist/escape.js +0 -45
  26. package/dist/escape.js.map +1 -1
  27. package/dist/exactjson.d.ts +0 -35
  28. package/dist/exactjson.js +0 -131
  29. package/dist/exactjson.js.map +1 -1
  30. package/dist/format.js +13 -203
  31. package/dist/format.js.map +1 -1
  32. package/dist/grammar.d.ts +9 -0
  33. package/dist/grammar.js +54 -0
  34. package/dist/grammar.js.map +1 -0
  35. package/dist/graph.js +0 -26
  36. package/dist/graph.js.map +1 -1
  37. package/dist/hcanon.js +0 -82
  38. package/dist/hcanon.js.map +1 -1
  39. package/dist/helpdoc.js +2 -2
  40. package/dist/helpdoc.js.map +1 -1
  41. package/dist/hints.d.ts +0 -6
  42. package/dist/hints.js +57 -55
  43. package/dist/hints.js.map +1 -1
  44. package/dist/jsonschema.js +0 -114
  45. package/dist/jsonschema.js.map +1 -1
  46. package/dist/keyorder.d.ts +0 -7
  47. package/dist/keyorder.js +0 -41
  48. package/dist/keyorder.js.map +1 -1
  49. package/dist/lang.js +17 -915
  50. package/dist/lang.js.map +1 -1
  51. package/dist/lsp-server.js +0 -16
  52. package/dist/lsp-server.js.map +1 -1
  53. package/dist/lsp.d.ts +1 -1
  54. package/dist/lsp.js +12 -159
  55. package/dist/lsp.js.map +1 -1
  56. package/dist/mcp-server.js +0 -26
  57. package/dist/mcp-server.js.map +1 -1
  58. package/dist/mcp.js +0 -149
  59. package/dist/mcp.js.map +1 -1
  60. package/dist/mod-tool.js +16 -131
  61. package/dist/mod-tool.js.map +1 -1
  62. package/dist/mod.js +0 -162
  63. package/dist/mod.js.map +1 -1
  64. package/dist/patch.js +0 -217
  65. package/dist/patch.js.map +1 -1
  66. package/dist/profile.d.ts +9 -0
  67. package/dist/profile.js +28 -0
  68. package/dist/profile.js.map +1 -0
  69. package/dist/provenance.js +0 -140
  70. package/dist/provenance.js.map +1 -1
  71. package/dist/query.js +0 -75
  72. package/dist/query.js.map +1 -1
  73. package/dist/reach.js +0 -43
  74. package/dist/reach.js.map +1 -1
  75. package/dist/relation.js +0 -61
  76. package/dist/relation.js.map +1 -1
  77. package/dist/report-sarif.d.ts +0 -11
  78. package/dist/report-sarif.js +0 -28
  79. package/dist/report-sarif.js.map +1 -1
  80. package/dist/sig.js +0 -35
  81. package/dist/sig.js.map +1 -1
  82. package/dist/sigdecl.js +1 -1
  83. package/dist/sigdecl.js.map +1 -1
  84. package/dist/siggate.js +0 -4
  85. package/dist/siggate.js.map +1 -1
  86. package/dist/site.js +3 -29
  87. package/dist/site.js.map +1 -1
  88. package/dist/subsume.d.ts +0 -10
  89. package/dist/subsume.js +0 -137
  90. package/dist/subsume.js.map +1 -1
  91. package/dist/template.d.ts +2 -1
  92. package/dist/template.js +58 -138
  93. package/dist/template.js.map +1 -1
  94. package/dist/trace.d.ts +21 -0
  95. package/dist/trace.js +107 -0
  96. package/dist/trace.js.map +1 -0
  97. package/dist/trim.js +0 -41
  98. package/dist/trim.js.map +1 -1
  99. package/dist/tsconfig.tsbuildinfo +1 -1
  100. package/dist/type.js.map +1 -1
  101. package/dist/unify.js +13 -248
  102. package/dist/unify.js.map +1 -1
  103. package/dist/utility.js +0 -22
  104. package/dist/utility.js.map +1 -1
  105. package/dist/val/AbnfFuncVal.d.ts +18 -0
  106. package/dist/val/AbnfFuncVal.js +132 -0
  107. package/dist/val/AbnfFuncVal.js.map +1 -0
  108. package/dist/val/AbsentVal.d.ts +11 -0
  109. package/dist/val/AbsentVal.js +30 -0
  110. package/dist/val/AbsentVal.js.map +1 -0
  111. package/dist/val/AggFuncVal.d.ts +10 -1
  112. package/dist/val/AggFuncVal.js +104 -116
  113. package/dist/val/AggFuncVal.js.map +1 -1
  114. package/dist/val/ArithFuncVal.js +0 -12
  115. package/dist/val/ArithFuncVal.js.map +1 -1
  116. package/dist/val/BagVal.js +1 -78
  117. package/dist/val/BagVal.js.map +1 -1
  118. package/dist/val/BigDecimalVal.js +0 -16
  119. package/dist/val/BigDecimalVal.js.map +1 -1
  120. package/dist/val/BigIntegerVal.js +0 -16
  121. package/dist/val/BigIntegerVal.js.map +1 -1
  122. package/dist/val/CloseFuncVal.js +0 -9
  123. package/dist/val/CloseFuncVal.js.map +1 -1
  124. package/dist/val/CmpFuncVal.d.ts +2 -0
  125. package/dist/val/CmpFuncVal.js +49 -72
  126. package/dist/val/CmpFuncVal.js.map +1 -1
  127. package/dist/val/ConjunctVal.js +0 -29
  128. package/dist/val/ConjunctVal.js.map +1 -1
  129. package/dist/val/ConstraintVal.js +0 -500
  130. package/dist/val/ConstraintVal.js.map +1 -1
  131. package/dist/val/ContainerKindVal.js +0 -2
  132. package/dist/val/ContainerKindVal.js.map +1 -1
  133. package/dist/val/CopyFuncVal.js +0 -3
  134. package/dist/val/CopyFuncVal.js.map +1 -1
  135. package/dist/val/Decimal.js +0 -179
  136. package/dist/val/Decimal.js.map +1 -1
  137. package/dist/val/DeprecateFuncVal.js.map +1 -1
  138. package/dist/val/DisjunctVal.js +0 -152
  139. package/dist/val/DisjunctVal.js.map +1 -1
  140. package/dist/val/EachFuncVal.js +0 -3
  141. package/dist/val/EachFuncVal.js.map +1 -1
  142. package/dist/val/EmitFuncVal.d.ts +1 -1
  143. package/dist/val/EmitFuncVal.js +6 -119
  144. package/dist/val/EmitFuncVal.js.map +1 -1
  145. package/dist/val/ExpectVal.js +0 -62
  146. package/dist/val/ExpectVal.js.map +1 -1
  147. package/dist/val/FilterFuncVal.js +0 -25
  148. package/dist/val/FilterFuncVal.js.map +1 -1
  149. package/dist/val/FuncBaseVal.d.ts +1 -0
  150. package/dist/val/FuncBaseVal.js +7 -127
  151. package/dist/val/FuncBaseVal.js.map +1 -1
  152. package/dist/val/GraphAtomVal.js +0 -15
  153. package/dist/val/GraphAtomVal.js.map +1 -1
  154. package/dist/val/HideFuncVal.js +0 -13
  155. package/dist/val/HideFuncVal.js.map +1 -1
  156. package/dist/val/IntegerVal.js +0 -61
  157. package/dist/val/IntegerVal.js.map +1 -1
  158. package/dist/val/JunctionVal.js +0 -20
  159. package/dist/val/JunctionVal.js.map +1 -1
  160. package/dist/val/KeyFuncVal.js +0 -46
  161. package/dist/val/KeyFuncVal.js.map +1 -1
  162. package/dist/val/ListVal.js +0 -57
  163. package/dist/val/ListVal.js.map +1 -1
  164. package/dist/val/LowerFuncVal.js +0 -11
  165. package/dist/val/LowerFuncVal.js.map +1 -1
  166. package/dist/val/MapVal.js +0 -151
  167. package/dist/val/MapVal.js.map +1 -1
  168. package/dist/val/MatchFuncVal.js +0 -27
  169. package/dist/val/MatchFuncVal.js.map +1 -1
  170. package/dist/val/{FormFuncVal.d.ts → MaybeFuncVal.d.ts} +5 -5
  171. package/dist/val/MaybeFuncVal.js +50 -0
  172. package/dist/val/MaybeFuncVal.js.map +1 -0
  173. package/dist/val/MoveFuncVal.js +0 -18
  174. package/dist/val/MoveFuncVal.js.map +1 -1
  175. package/dist/val/NilVal.js +0 -60
  176. package/dist/val/NilVal.js.map +1 -1
  177. package/dist/val/NomFuncVal.js +18 -54
  178. package/dist/val/NomFuncVal.js.map +1 -1
  179. package/dist/val/NumberVal.js +0 -15
  180. package/dist/val/NumberVal.js.map +1 -1
  181. package/dist/val/OpBaseVal.d.ts +1 -0
  182. package/dist/val/OpBaseVal.js +3 -15
  183. package/dist/val/OpBaseVal.js.map +1 -1
  184. package/dist/val/PackFuncVal.js +0 -34
  185. package/dist/val/PackFuncVal.js.map +1 -1
  186. package/dist/val/PathFuncVal.js +0 -6
  187. package/dist/val/PathFuncVal.js.map +1 -1
  188. package/dist/val/PathVal.js +0 -41
  189. package/dist/val/PathVal.js.map +1 -1
  190. package/dist/val/PlaceVal.js +0 -25
  191. package/dist/val/PlaceVal.js.map +1 -1
  192. package/dist/val/PlusOpVal.d.ts +1 -7
  193. package/dist/val/PlusOpVal.js +13 -74
  194. package/dist/val/PlusOpVal.js.map +1 -1
  195. package/dist/val/PrefFuncVal.js +0 -1
  196. package/dist/val/PrefFuncVal.js.map +1 -1
  197. package/dist/val/PrefVal.js +0 -167
  198. package/dist/val/PrefVal.js.map +1 -1
  199. package/dist/val/RecurseVal.js +0 -55
  200. package/dist/val/RecurseVal.js.map +1 -1
  201. package/dist/val/RefVal.js +0 -282
  202. package/dist/val/RefVal.js.map +1 -1
  203. package/dist/val/ReferFuncVal.js +3 -232
  204. package/dist/val/ReferFuncVal.js.map +1 -1
  205. package/dist/val/ScalarKindVal.js +0 -49
  206. package/dist/val/ScalarKindVal.js.map +1 -1
  207. package/dist/val/ScalarVal.js +0 -11
  208. package/dist/val/ScalarVal.js.map +1 -1
  209. package/dist/val/StrFuncVal.js +0 -18
  210. package/dist/val/StrFuncVal.js.map +1 -1
  211. package/dist/val/SuperFuncVal.js +0 -32
  212. package/dist/val/SuperFuncVal.js.map +1 -1
  213. package/dist/val/TopVal.js +0 -1
  214. package/dist/val/TopVal.js.map +1 -1
  215. package/dist/val/TranslateFuncVal.js +1 -3
  216. package/dist/val/TranslateFuncVal.js.map +1 -1
  217. package/dist/val/UpperFuncVal.js +0 -11
  218. package/dist/val/UpperFuncVal.js.map +1 -1
  219. package/dist/val/Val.d.ts +1 -0
  220. package/dist/val/Val.js +2 -133
  221. package/dist/val/Val.js.map +1 -1
  222. package/dist/val/VarVal.js +0 -12
  223. package/dist/val/VarVal.js.map +1 -1
  224. package/dist/val/arith.js +0 -37
  225. package/dist/val/arith.js.map +1 -1
  226. package/dist/val/caserange.js +0 -61
  227. package/dist/val/caserange.js.map +1 -1
  228. package/dist/val/members.js +0 -6
  229. package/dist/val/members.js.map +1 -1
  230. package/dist/val/numcmp.js +0 -11
  231. package/dist/val/numcmp.js.map +1 -1
  232. package/dist/val/numkind.js +0 -145
  233. package/dist/val/numkind.js.map +1 -1
  234. package/dist/val/valutil.js +0 -16
  235. package/dist/val/valutil.js.map +1 -1
  236. package/dist/vet.js +0 -461
  237. package/dist/vet.js.map +1 -1
  238. package/dist/view.js +0 -414
  239. package/dist/view.js.map +1 -1
  240. package/dist/walk.js +0 -41
  241. package/dist/walk.js.map +1 -1
  242. package/grammar/aontu.abnf +8 -6
  243. package/grammar/aontu.gbnf +4 -4
  244. package/grammar/aontu.lark +4 -4
  245. package/grammar/aontu.tmLanguage.json +1 -1
  246. package/package.json +4 -2
  247. package/skill/tasks.md +9 -7
  248. package/src/agentsmd.ts +0 -35
  249. package/src/alias.ts +0 -39
  250. package/src/allow.ts +1 -96
  251. package/src/aontu.ts +4 -116
  252. package/src/aontumodel.ts +26 -0
  253. package/src/casing.ts +95 -0
  254. package/src/cli.ts +258 -1024
  255. package/src/ctx.ts +0 -103
  256. package/src/diff.ts +0 -40
  257. package/src/err.ts +0 -40
  258. package/src/escape.ts +0 -46
  259. package/src/exactjson.ts +0 -131
  260. package/src/format.ts +14 -257
  261. package/src/grammar.ts +72 -0
  262. package/src/graph.ts +0 -61
  263. package/src/hcanon.ts +0 -82
  264. package/src/helpdoc.ts +2 -2
  265. package/src/hints.ts +69 -57
  266. package/src/jsonschema.ts +0 -123
  267. package/src/keyorder.ts +0 -42
  268. package/src/lang.ts +19 -931
  269. package/src/lsp-server.ts +0 -16
  270. package/src/lsp.ts +12 -180
  271. package/src/mcp-server.ts +0 -31
  272. package/src/mcp.ts +0 -169
  273. package/src/mod-tool.ts +18 -159
  274. package/src/mod.ts +0 -178
  275. package/src/patch.ts +0 -232
  276. package/src/profile.ts +42 -0
  277. package/src/provenance.ts +0 -183
  278. package/src/query.ts +0 -84
  279. package/src/reach.ts +0 -53
  280. package/src/relation.ts +0 -84
  281. package/src/report-sarif.ts +0 -48
  282. package/src/sig.ts +0 -35
  283. package/src/sigdecl.ts +1 -1
  284. package/src/siggate.ts +0 -30
  285. package/src/site.ts +3 -29
  286. package/src/subsume.ts +1 -161
  287. package/src/template.ts +69 -140
  288. package/src/trace.ts +157 -0
  289. package/src/trim.ts +0 -53
  290. package/src/type.ts +2 -45
  291. package/src/unify.ts +14 -257
  292. package/src/utility.ts +0 -31
  293. package/src/val/AbnfFuncVal.ts +181 -0
  294. package/src/val/AbsentVal.ts +54 -0
  295. package/src/val/AggFuncVal.ts +152 -188
  296. package/src/val/ArithFuncVal.ts +0 -20
  297. package/src/val/BagVal.ts +1 -78
  298. package/src/val/BigDecimalVal.ts +0 -16
  299. package/src/val/BigIntegerVal.ts +0 -16
  300. package/src/val/CloseFuncVal.ts +0 -9
  301. package/src/val/CmpFuncVal.ts +68 -184
  302. package/src/val/ConjunctVal.ts +0 -33
  303. package/src/val/ConstraintVal.ts +2 -537
  304. package/src/val/ContainerKindVal.ts +0 -18
  305. package/src/val/CopyFuncVal.ts +0 -5
  306. package/src/val/Decimal.ts +1 -185
  307. package/src/val/DeprecateFuncVal.ts +0 -10
  308. package/src/val/DisjunctVal.ts +0 -157
  309. package/src/val/EachFuncVal.ts +0 -40
  310. package/src/val/EmitFuncVal.ts +8 -208
  311. package/src/val/ExpectVal.ts +0 -62
  312. package/src/val/FilterFuncVal.ts +0 -55
  313. package/src/val/FuncBaseVal.ts +9 -130
  314. package/src/val/GraphAtomVal.ts +0 -42
  315. package/src/val/HideFuncVal.ts +0 -15
  316. package/src/val/IntegerVal.ts +0 -61
  317. package/src/val/JunctionVal.ts +0 -20
  318. package/src/val/KeyFuncVal.ts +0 -48
  319. package/src/val/ListVal.ts +0 -59
  320. package/src/val/LowerFuncVal.ts +0 -12
  321. package/src/val/MapVal.ts +0 -151
  322. package/src/val/MatchFuncVal.ts +0 -59
  323. package/src/val/MaybeFuncVal.ts +86 -0
  324. package/src/val/MoveFuncVal.ts +0 -20
  325. package/src/val/NilVal.ts +0 -60
  326. package/src/val/NomFuncVal.ts +10 -99
  327. package/src/val/NumberVal.ts +0 -16
  328. package/src/val/OpBaseVal.ts +4 -17
  329. package/src/val/PackFuncVal.ts +0 -63
  330. package/src/val/PathFuncVal.ts +0 -32
  331. package/src/val/PathVal.ts +0 -66
  332. package/src/val/PlaceVal.ts +0 -45
  333. package/src/val/PlusOpVal.ts +18 -75
  334. package/src/val/PrefFuncVal.ts +0 -1
  335. package/src/val/PrefVal.ts +0 -179
  336. package/src/val/RecurseVal.ts +0 -81
  337. package/src/val/RefVal.ts +1 -285
  338. package/src/val/ReferFuncVal.ts +4 -255
  339. package/src/val/ScalarKindVal.ts +0 -50
  340. package/src/val/ScalarVal.ts +0 -12
  341. package/src/val/StrFuncVal.ts +0 -44
  342. package/src/val/SuperFuncVal.ts +0 -42
  343. package/src/val/TopVal.ts +0 -1
  344. package/src/val/TranslateFuncVal.ts +1 -51
  345. package/src/val/UpperFuncVal.ts +0 -12
  346. package/src/val/Val.ts +3 -192
  347. package/src/val/VarVal.ts +0 -15
  348. package/src/val/arith.ts +0 -92
  349. package/src/val/caserange.ts +0 -62
  350. package/src/val/members.ts +0 -23
  351. package/src/val/numcmp.ts +1 -27
  352. package/src/val/numkind.ts +0 -149
  353. package/src/val/valutil.ts +0 -16
  354. package/src/vet.ts +1 -582
  355. package/src/view.ts +0 -507
  356. package/src/walk.ts +0 -41
  357. package/dist/lower.d.ts +0 -23
  358. package/dist/lower.js +0 -578
  359. package/dist/lower.js.map +0 -1
  360. package/dist/render.d.ts +0 -53
  361. package/dist/render.js +0 -547
  362. package/dist/render.js.map +0 -1
  363. package/dist/std.d.ts +0 -3
  364. package/dist/std.js +0 -672
  365. package/dist/std.js.map +0 -1
  366. package/dist/val/FormFuncVal.js +0 -55
  367. package/dist/val/FormFuncVal.js.map +0 -1
  368. package/dist/val/NamerFuncVal.d.ts +0 -12
  369. package/dist/val/NamerFuncVal.js +0 -176
  370. package/dist/val/NamerFuncVal.js.map +0 -1
  371. package/src/lower.ts +0 -636
  372. package/src/render.ts +0 -732
  373. package/src/std.ts +0 -683
package/src/vet.ts CHANGED
@@ -1,28 +1,5 @@
1
1
  /* Copyright (c) 2025 Richard Rodger, MIT License */
2
2
 
3
- // The validation verb: check a data document against a schema document
4
- // and return a MACHINE-READABLE report (G2 phase 2,
5
- // docs/capability-review/g2-validation-verb.md).
6
- //
7
- // This module is the engine only. The CLI verb, the JSON/SARIF
8
- // renderers and `--watch` are phase 3 and 5; the Go port is phase 4.
9
- // Keeping the engine transport-free is the split lsp.ts already uses,
10
- // and for the same reason: it is the part that has to be unit-testable
11
- // and embeddable.
12
- //
13
- // Two properties of the engine shape everything here, and both were
14
- // probed rather than assumed:
15
- //
16
- // - A CONTRADICTION surfaces as a NilVal in the unified tree, so
17
- // conflict findings come from a tree walk (the `walkNils` pattern
18
- // lsp.ts already uses, generalised).
19
- // - INCOMPLETENESS does not. `{name:"auth"}` against
20
- // `{name:string, port:integer}` unifies cleanly and leaves
21
- // `port:integer` standing — no nil, no error. It surfaces only when
22
- // something tries to GENERATE, which is why vet runs a generate
23
- // check in an isolated collect context and reads the
24
- // `incomplete`-class errors out of it. The two verdicts the report
25
- // distinguishes therefore come from two different mechanisms.
26
3
 
27
4
  import type { TrustOptions, Val } from './type'
28
5
 
@@ -40,11 +17,6 @@ import { collectDeprecations, walkBagVals, deprecationMessage,
40
17
  includeOpts,
41
18
  } from './utility'
42
19
  import { subsumeNode, effectiveDefault } from './subsume'
43
- // The `--at` refusal is the SAME refusal `get` and `why` give for a
44
- // path that names nothing, down to the "did you mean" -- so it is that
45
- // one, not a second spelling of it. A cycle in the module graph
46
- // (query imports anchorAt from here), and a benign one: both sides
47
- // use the other only from inside a function body, never at load time.
48
20
  import { noPathFinding } from './query'
49
21
  import { cmpCodePoint } from './keyorder'
50
22
 
@@ -57,34 +29,8 @@ export type VetSite = {
57
29
  file: string
58
30
  row: number
59
31
  col: number
60
- // The extent in UTF-16 code units, or -1 when unknown — the same
61
- // "unknown" row and col already use.
62
- //
63
- // THIS IS WHAT MAKES A FINDING REPAIRABLE. `value` is the CANON, not
64
- // the source text: `port: 0x1F` reports canon `31` at column 7, so a
65
- // consumer replacing `(col, value.length)` writes `port: 5x1F` and
66
- // corrupts the document. With `len` the span is `(col, 4)` and the
67
- // replacement is exact.
68
- //
69
- // NEVER GUESSED. Where the span is unknown this is -1 and a consumer
70
- // must not edit — unlike the LSP, which falls back to canon because a
71
- // wonky highlight is cosmetic while a wrong edit is a lost file.
72
- // See ts/src/site.ts for what the extent covers.
73
32
  len: number
74
33
  role: VetRole
75
- // The SOURCE TEXT the span covers, or '' when unknown.
76
- //
77
- // This is what makes the span SELF-VERIFYING, and it is not the same
78
- // as `value`. For a scalar the two differ by normalisation — `0x1F`
79
- // has src `0x1F` and value (canon) `31`. For a COMPOUND the span
80
- // names the opening token only, exactly as row and col always have:
81
- // a constraint `min(1)` reports src `min`, and a reference `$.b`
82
- // reports src `$`.
83
- //
84
- // So a consumer must read the document at (row, col, len), compare it
85
- // to `src`, and REFUSE when they differ — and, seeing `min` where it
86
- // expected `min(1)`, refuse rather than replace the name and orphan
87
- // the arguments. Without this field that mistake is undetectable.
88
34
  src?: string
89
35
  value?: string
90
36
  }
@@ -96,21 +42,6 @@ export type VetFinding = {
96
42
  path: string
97
43
  message: string
98
44
 
99
- // THE REPAIR, not just the diagnosis. `message` is one line by
100
- // design -- it is the headline, and the frames under it are for a
101
- // human at a terminal -- but for several codes the part that says
102
- // what to DO about the failure lived only in those frames, so a
103
- // machine reader (an agent, a CI annotation, an editor) got the
104
- // complaint and none of the cure. `0d` is the clearest case: the
105
- // engine refuses a lossy integer literal and the hint names the
106
- // exact-decimal escape that fixes it. Populated from the shared
107
- // hints table (ts/src/hints.ts, mirrored by go/hints.go) whenever
108
- // the code has one; absent when it does not (the report-layer
109
- // compat_* codes, notably, carry no hint text).
110
- //
111
- // Excluded from spec goldens for the same reason `message` is: it is
112
- // prose, it is long, and the two ports hold it to the byte through
113
- // the message tests instead of through every vet row.
114
45
  hint?: string
115
46
 
116
47
  sites: VetSite[]
@@ -119,37 +50,12 @@ export type VetFinding = {
119
50
  note?: string
120
51
  }
121
52
 
122
- // WHAT THE CHECK ACTUALLY EXAMINED (G11 phase 5,
123
- // docs/capability-review/g11-agent-onramp.md).
124
- //
125
- // The defect this exists for: a schema written with the wildcard every
126
- // neighbouring tool uses -- `{"*": {...}}`, which in aontu is a key
127
- // NAMED `*` and not a template -- constrains nothing, and vet answers
128
- // `valid` over data that violates it. aontu is not wrong there; it was
129
- // asked about a document declaring an entity called `*`. The defect is
130
- // that a check that examined NOTHING and a check that PASSED are the
131
- // same bytes and the same exit code, so an unattended caller reports
132
- // success.
133
- //
134
- // Absent unless asked for (`VetOptions.coverage`), so no existing
135
- // report changes shape and the accounting costs nothing by default --
136
- // `render --coverage` sets both precedents.
137
53
  export type VetCoverage = {
138
- // Data LEAVES a schema declaration constrained. Leaves, not paths:
139
- // a leaf is where a value lives, and matching a CONTAINER constrains
140
- // no value. A schema that says only "there is a key called entity"
141
- // has checked nothing, and this is the number that says so.
142
54
  checked: number
143
- // Declarations the schema makes under the anchor. A declaration is a
144
- // map key, a list index, or a template (spelled `&` in the path),
145
- // at every depth.
146
55
  declared: number
147
56
  // Data leaves in all, under `coverageAt` when it is given. `checked`
148
57
  // over this is the ratio a reader wants.
149
58
  leaves: number
150
- // The SHALLOWEST data paths no declaration constrained. Shallowest,
151
- // as `render --coverage`'s `dead` is: a path whose subtree is wholly
152
- // unconstrained is named once instead of every leaf beneath it.
153
59
  unchecked: string[]
154
60
  // The SHALLOWEST declarations no data path met.
155
61
  unused: string[]
@@ -177,34 +83,13 @@ export type VetOptions = {
177
83
  // the report gains a `coverage` object only when this is set, so no
178
84
  // existing caller's report changes shape.
179
85
  coverage?: boolean
180
- // Measure under this path of the DATA only, instead of the whole
181
- // document -- `render --coverage`'s `--coverage-at`, for the same
182
- // reason: a caller gating one subtree should not be answered about
183
- // the rest. Ignored unless `coverage` is set.
184
86
  coverageAt?: string
185
- schemaUrl?: string // provenance label for schema sites
87
+ schemaUrl?: string
186
88
  dataUrl?: string // provenance label for data sites
187
89
 
188
- // Where each document CAME FROM, used to resolve its relative
189
- // `@"file"` loads -- the file path, as `Aontu({path})` takes it, not
190
- // the directory. Vet takes two documents from its caller rather than
191
- // from the filesystem, so it cannot know this: without it a modular
192
- // schema resolved its includes against the process working
193
- // directory, which fails outside that directory and, worse, silently
194
- // reads a same-named file that happens to sit there. The two
195
- // documents get their OWN bases, because they need not live in the
196
- // same place.
197
90
  schemaPath?: string
198
91
  dataPath?: string
199
92
 
200
- // The trust profile this run evaluates under (G5, docs/trust.md).
201
- // Vet's whole job is to evaluate a document its caller did not
202
- // write, so the caller must be able to say what that document is
203
- // allowed to reach: without this the include chain is the default
204
- // one, and `@"../../etc/passwd.aon"` in hostile data reads whatever
205
- // the validating process can. (`@"x.js"` no longer executes --
206
- // ADR-012 refuses the extension -- but reading is enough.) A server
207
- // passes `{include:'none'}`.
208
93
  trust?: TrustOptions
209
94
 
210
95
  // Extensions additionally read as text (the CLI's `--text-ext`).
@@ -223,37 +108,10 @@ const DEFAULT_SCHEMA_URL = 'schema'
223
108
  const DEFAULT_DATA_URL = 'data'
224
109
 
225
110
 
226
- // Every site in a freshly parsed tree carries the same url, and for a
227
- // bare parse that url is the empty string: `site.url` is only populated
228
- // by the multisource loader (ts/src/lang.ts). Vet takes two documents
229
- // from its CALLER, not from the filesystem, so it stamps provenance
230
- // itself — which is what lets the report assign site ROLES by
231
- // provenance rather than by NilVal's source-order heuristic, exactly as
232
- // the design requires.
233
- // EVERY SITE NAMES THE FILE WHOSE TEXT IT EXCERPTS (the review's
234
- // finding F, use-cases/BUGS.md §25). The parser already names the file
235
- // each value was read from -- a value loaded through `@"lib/types.aon"`
236
- // carries that path, with that file's row and column -- and this walk
237
- // used to OVERWRITE every url with the entry document's name. The
238
- // coordinates stayed the included file's, so a finding cited
239
- // `entry.aon:3:7` for text that lives three files away, at a line the
240
- // entry may not even have. A repair agent that follows the site edits
241
- // the wrong file.
242
- //
243
- // Only the values that carry no name of their own are stamped: those
244
- // are the ones the engine minted rather than read, and the entry is
245
- // the honest name for them. The urls actually seen are collected, so
246
- // the report can still tell WHICH DOCUMENT a site belongs to without
247
- // pretending they all came from one file -- see roleOf.
248
111
  function stampUrl(v: any, url: string, seen?: Set<string>): Set<string> {
249
112
  const urls = seen ?? new Set<string>()
250
113
  urls.add(url)
251
114
  walkVals(v, (n: any) => {
252
- // UNDEFINED counts as unstamped, not just empty: the parser leaves
253
- // the url undefined on one of its two paths (ts/src/lang.ts), and
254
- // treating that as a name would put `undefined` in the url set --
255
- // where the OTHER document's unstamped values would then match it,
256
- // and every site would read `data`.
257
115
  if (null == n.site.url || '' === n.site.url) {
258
116
  n.site.url = url
259
117
  }
@@ -264,10 +122,6 @@ function stampUrl(v: any, url: string, seen?: Set<string>): Set<string> {
264
122
  }
265
123
 
266
124
 
267
- // The provenance a report projects its sites through: which urls
268
- // belong to the DATA document, and how the caller reached each of the
269
- // two documents (which is what says how to NAME a third file either of
270
- // them included).
271
125
  type Prov = {
272
126
  // The urls the data walk reached. Roles are decided by membership,
273
127
  // on the RAW url -- never by a name comparison.
@@ -279,20 +133,6 @@ type Prov = {
279
133
  }
280
134
 
281
135
 
282
- // A FILE THE READER CAN OPEN. The parser resolves an include to an
283
- // absolute path, which is the right identity (two files loading the
284
- // same library by different relative spellings must be one file) and
285
- // the wrong NAME: a report whose entry reads `contract.aon` and whose
286
- // included site reads `/home/someone/checkout/types.aon` is a report
287
- // that cannot be uploaded as SARIF, diffed between machines, or read
288
- // beside the command that produced it.
289
- //
290
- // So an included file is named as the ENTRY'S OWN NAME reaches it:
291
- // relative to the entry's directory, then re-anchored on however the
292
- // caller spelled the entry. `vet contract.aon` names `types.aon`;
293
- // `vet a/b/contract.aon` names `a/b/types.aon`; an absolute entry
294
- // keeps absolute includes. A caller who passed no path at all has no
295
- // base to relativise against and gets the url unchanged.
296
136
  export function displayFile(
297
137
  url: string, label: string, path?: string): string {
298
138
  if (url === label || null == path || '' === url || !isAbsolute(url)) {
@@ -304,12 +144,6 @@ export function displayFile(
304
144
  }
305
145
 
306
146
 
307
- // The name for one site, taken from the document the site BELONGS to
308
- // -- which is the role, already decided by url-set membership. Doing
309
- // it here rather than from a map built at stamping time is not a
310
- // shortcut: a nil's operands are off the tree by the time the report
311
- // is built, so a value first seen during the MEET (the commonest
312
- // schema site there is) would be missing from any such map.
313
147
  function displayOf(file: string, role: VetRole, prov: Prov): string {
314
148
  return 'data' === role
315
149
  ? displayFile(file, prov.dataUrl ?? file, prov.dataPath)
@@ -317,50 +151,21 @@ function displayOf(file: string, role: VetRole, prov: Prov): string {
317
151
  }
318
152
 
319
153
 
320
- // The ROLE of a site: which of the two documents it belongs to. Not a
321
- // name comparison -- a data document may itself include another file,
322
- // and that file's values are still data. Membership of the url set the
323
- // stamping walk collected is the question, and the answer is `schema`
324
- // for anything the data walk never reached (an engine-minted value
325
- // stamped with the schema entry, say).
326
154
  function roleOf(file: string, prov: Prov): VetRole {
327
155
  return prov.data.has(file) ? 'data' : 'schema'
328
156
  }
329
157
 
330
158
 
331
- // `$.a.b`, and `$` for the root. Deliberately NOT delimiter-escaped: a
332
- // map key may contain any character, including every separator a
333
- // compact summary might pick, so the path is carried as a JSON string
334
- // and never parsed back out of a larger token.
335
159
  function pathText(path?: string[]): string {
336
160
  return '$' + (null != path && 0 < path.length ? '.' + path.join('.') : '')
337
161
  }
338
162
 
339
163
 
340
- // `secondary` is the only operand that can be absent — a `closed` or an
341
- // incomplete finding has one side, a two-site conflict has both — so
342
- // this is the one nullable input, and every Val that does arrive
343
- // carries a site and a canon.
344
164
  function siteOf(v: any, prov: Prov): VetSite | undefined {
345
165
  if (null == v) {
346
166
  return undefined
347
167
  }
348
- // The report's `file` is whatever the site carries, and by the time a
349
- // site reaches a report that is always a stamped name: vet walks both
350
- // documents before they meet, and the walk reaches the off-peg values
351
- // a finding can name (ts/src/walk.ts). A consumer therefore reads
352
- // `file` without a presence check, and the Go port -- whose field is
353
- // a plain string -- writes the same key.
354
- //
355
- // NOT coalesced. The parser leaves the url undefined on one of its
356
- // two paths (ts/src/lang.ts), and a `?? ''` here would be dead code
357
- // that hides it: if a value ever reaches a report unstamped, the two
358
- // ports should disagree loudly rather than quietly agree on an empty
359
- // name that neither of them meant.
360
168
  const file = v.site.url
361
- // NAMED for the reader, ROLED by the raw url: the two questions are
362
- // different, and only the first is about how the file is spelled
363
- // (see displayFile).
364
169
  const role = roleOf(file, prov)
365
170
  return {
366
171
  file: displayOf(file, role, prov),
@@ -378,13 +183,6 @@ function siteOf(v: any, prov: Prov): VetSite | undefined {
378
183
  // The underlying NilVal fields are untouched: this is a report-layer
379
184
  // projection, so the existing error.tsv assertions do not move.
380
185
  function sitesOf(nil: any, prov: Prov): VetSite[] {
381
- // `?? nil`: a failure raised about a CONSTRUCT rather than about a
382
- // failed meet -- a lossy integer literal, say -- carries no operands
383
- // at all, and reporting it about ITSELF is what ctx.adderr already
384
- // does for the same reason. Without the fallback the report built a
385
- // site out of `undefined` and threw while partitioning it, which is
386
- // the one thing vet promises not to do: a bad value in the data is
387
- // DATA, and the caller gets a report.
388
186
  const sites: VetSite[] = [siteOf(nil.primary ?? nil, prov) as VetSite]
389
187
 
390
188
  const secondary = siteOf(nil.secondary, prov)
@@ -392,9 +190,6 @@ function sitesOf(nil: any, prov: Prov): VetSite[] {
392
190
  sites.push(secondary)
393
191
  }
394
192
 
395
- // Partitioned rather than sorted: which of the two NilVal operands is
396
- // `primary` follows source order within one document, which says
397
- // nothing useful when one side is a schema and the other is data.
398
193
  return [
399
194
  ...sites.filter((s) => 'data' === s.role),
400
195
  ...sites.filter((s) => 'schema' === s.role),
@@ -402,12 +197,6 @@ function sitesOf(nil: any, prov: Prov): VetSite[] {
402
197
  }
403
198
 
404
199
 
405
- // The message text is MATERIALISED on demand, exactly as handleErrors
406
- // materialises one before a caller sees it: makeNilErr defers it
407
- // because most NilVals are transient and never rendered, and only the
408
- // throwing path asks for it. Without this a finding could carry an
409
- // empty `message` -- which is what the incomplete half of every report
410
- // did, and what any nil built during the PARSE of a document did.
411
200
  function materialise(nil: any, ctx: any): void {
412
201
  if (null == nil.msg || '' === nil.msg) {
413
202
  descErr(nil, ctx)
@@ -432,32 +221,15 @@ function findingOf(nil: any, prov: Prov): VetFinding {
432
221
  class: nil.class,
433
222
  severity: 'error',
434
223
  path: pathText(nil.path),
435
- // The HEADLINE only, WITHOUT ANSI: the frames below it are for a
436
- // human reading a terminal, and the first line is the part the two
437
- // ports hold to byte parity. Materialised before this runs, so it
438
- // is always there (see materialise above). The escapes matter for
439
- // one family only -- a parse failure's text comes from the parser,
440
- // which colours its marker -- and a machine-readable report is no
441
- // place for terminal control codes.
442
224
  message: stripAnsi(nil.msg.split('\n')[0]),
443
225
  sites: sitesOf(nil, prov),
444
226
  }
445
227
 
446
- // The hint, whole, with its detail placeholders filled in exactly as
447
- // the terminal frame fills them. Trailing whitespace is dropped
448
- // because it is spacing for the frame that used to follow it, not
449
- // part of the text; the deliberate blank lines INSIDE a hint are
450
- // `\n \n` and survive.
451
228
  const hint = getHint(nil.why, nil.details)
452
229
  if (null != hint && '' !== hint) {
453
230
  finding.hint = stripAnsi(hint).replace(/\s+$/, '')
454
231
  }
455
232
 
456
- // `expected`/`actual` are the admissible-alternatives contract, and
457
- // the constraint algebra already produces them: G1's atoms attach the
458
- // normalised residual and the offending value, and `must` attaches
459
- // the author's message. Read them where they are rather than
460
- // re-deriving them here.
461
233
  if ('string' === typeof details.expected) {
462
234
  finding.expected = details.expected
463
235
  }
@@ -472,19 +244,6 @@ function findingOf(nil: any, prov: Prov): VetFinding {
472
244
  }
473
245
 
474
246
 
475
- // Findings are sorted BY VET, not by the walk. The underlying walk
476
- // iterates raw object keys and the two hosts disagree about their order
477
- // — `10:… 9:…` yields ["9","10"] in JavaScript, which hoists
478
- // integer-like keys, against Go's insertion order (ts/src/keyorder.ts
479
- // exists for exactly this) — so an unsorted report could never be in
480
- // cross-port parity.
481
- //
482
- // The order is by data site (file, row, column), then code, then path.
483
- // It is carried in ONE key string rather than a cascade of comparisons:
484
- // the row and column are zero-padded so lexicographic order is numeric
485
- // order, and NUL joins the fields because no field can contain one.
486
- // A cascade would need a test per tie-breaker to stay honest; a key
487
- // needs none, and cannot disagree with itself.
488
247
  const ORDER_PAD = 9
489
248
 
490
249
 
@@ -493,12 +252,6 @@ function pad(n: number): string {
493
252
  }
494
253
 
495
254
 
496
- // The walk index is the LAST field, which makes every key unique and
497
- // the sort below total: two findings can otherwise share everything the
498
- // key carries — same data site, same code, same path — and a comparator
499
- // that has to answer "equal" is one more thing to get right in two
500
- // languages. With the index appended, ties simply keep walk order, in
501
- // both ports, by construction rather than by the sort's promises.
502
255
  function orderKey(f: VetFinding, index: number): string {
503
256
  const site = f.sites[0]
504
257
  return [
@@ -512,44 +265,11 @@ function orderKey(f: VetFinding, index: number): string {
512
265
  }
513
266
 
514
267
 
515
- // A DOCUMENT THAT DOES NOT STAND UP, in the finding shape (the
516
- // review's finding F). `trim` and `relations` answered an unusable
517
- // document with `verdict: error` and an EMPTY list: the caller learned
518
- // that something was wrong and nothing about what, which is the one
519
- // thing a repair loop cannot work with. Both verbs take ONE document,
520
- // so there is no role to decide -- the document is the thing being
521
- // checked and the thing to edit, which is what `data` means here.
522
- //
523
- // The engine's own first error IS the finding: these verbs add nothing
524
- // to a diagnosis the evaluator already made, and the FIRST is enough
525
- // because everything after it is a consequence.
526
- //
527
- // The Go twin is failureFinding in go/vet.go.
528
268
  export function failureFinding(
529
269
  ctx: any, url?: string, failed?: any): VetFinding {
530
- // ctx.err IS SOMETIMES EMPTY, and the comment that used to stand here
531
- // said otherwise (use-cases/BUGS.md §43). `&: id(root)` fails with a
532
- // NIL ROOT and NO COLLECTED ERROR -- the id-spread refusal is the
533
- // root itself -- and every verb that reports "this document does not
534
- // stand up" then read `ctx.err[0]` as undefined and died: a TypeError
535
- // out of `relations`, `reaches` and `jsonschema` in TypeScript, a
536
- // panic in Go. The one shape where finding F's own invariant, that a
537
- // document which does not stand up SAYS SO in the finding shape, was
538
- // answered with a stack trace.
539
- //
540
- // `failed` is the caller's own root -- every caller has it, and its
541
- // condition is `0 < ctx.err.length || root.isNil`, so when the first
542
- // half is false the second holds and the root IS the reason.
543
270
  const nil: any = ctx.err[0] ?? failed
544
271
  materialise(nil, ctx)
545
272
 
546
- // STAMPED, as vet stamps both documents before they meet: siteOf does
547
- // not coalesce a missing name (deliberately -- see there), so a site
548
- // that reached the report unstamped would carry `file: undefined`.
549
- // The three Vals a finding can name are the nil and its two operands,
550
- // and the url set collects whatever name each already had, so a value
551
- // read from an included file keeps that file's name and still counts
552
- // as part of the one document being checked.
553
273
  const at = url ?? ''
554
274
  const urls = new Set([at])
555
275
  for (const v of [nil, nil.primary, nil.secondary]) {
@@ -575,28 +295,8 @@ export function anchorAt(root: any, at: string): Val | undefined {
575
295
 
576
296
  let node: any = root
577
297
  for (const part of parts) {
578
- // A SIZING RESIDUE IS ITS CONTAINER, plus a note about what the
579
- // container must still satisfy (use-cases/BUGS.md §16). The path
580
- // steps through it: `$.a.ports.0.port` names the same node whether
581
- // or not `ports` still carries a `unique()`, and an anchor that
582
- // stopped here would report `no_path` for a key the document
583
- // plainly has.
584
298
  node = throughResidue(node)
585
299
 
586
- // TYPE-DIRECTED, not a property lookup on whatever `peg` happens to
587
- // be. An anchor is a STRUCTURAL path into the schema — the same
588
- // thing a reference means by `$.a.b` — so it walks map keys and
589
- // list indices, and stops at anything else.
590
- //
591
- // Indexing the peg generically walked much further than that: into
592
- // a junction's branches (`a:1|2` with `--at $.a.0` validated
593
- // against ONE branch), into a constraint's atom arguments (so
594
- // `min(2)` with `--at $.a.0` reported the bound's own argument as
595
- // the truth), into a pref's wrapped value through the literal key
596
- // `peg`, and into an array's `length` — that last one handing back
597
- // a JavaScript NUMBER as the anchor, after which every document
598
- // whatsoever came back valid. The Go port has always been
599
- // type-directed here; this is the canonical side moving to it.
600
300
  if (true === node?.isMap) {
601
301
  const peg = node.peg
602
302
  if (null == peg || !Object.prototype.hasOwnProperty.call(peg, part)) {
@@ -621,53 +321,20 @@ export function anchorAt(root: any, at: string): Val | undefined {
621
321
  }
622
322
  }
623
323
 
624
- // THE ANCHOR KEEPS ITS ATOM. Stepping THROUGH a residue is right --
625
- // `$.x.a` names a key of the container whatever the container still
626
- // has to satisfy -- but ARRIVING at one and handing back the bare
627
- // container drops a constraint the author wrote, so `--at $.x` vetted
628
- // clean against a `length` the evaluator enforces. The residue is the
629
- // honest schema for the node: the meet drives it, and generation
630
- // settles it, exactly as it does without an anchor.
631
324
  return node
632
325
  }
633
326
 
634
327
 
635
- // The container inside a settled sizing residue, or the value itself.
636
- // EXPORTED for the `doc` figure, which walks the same shape the anchor
637
- // does: a list still carrying a `unique()` is a list, and a drawing
638
- // that stopped at the residue would omit keys the document plainly
639
- // has.
640
328
  export function throughResidue(v: any): any {
641
329
  return sizingResidue(v)?.bag ?? v
642
330
  }
643
331
 
644
332
 
645
- // Validate `dataSrc` against `schemaSrc`.
646
- //
647
- // Never throws for findings: a contradiction in the data is DATA, and
648
- // the caller gets a report. It throws only when the caller's own inputs
649
- // are unusable — which is why an unusable schema is a verdict (`error`)
650
- // rather than an exception too: "the schema is broken" is a fact the
651
- // agent loop needs to branch on, not an exceptional condition.
652
- // THE COVERAGE ACCOUNTING (G11 phase 5). Structural, over the two
653
- // trees vet already holds, and deliberately NOT provenance-based: the
654
- // question is what the SCHEMA DECLARES about the data, which is a
655
- // property of the two documents rather than of the meet that ran. A
656
- // meet-based reading would also count a value the data supplied to
657
- // itself as "covered", which is the opposite of the thing being asked.
658
- //
659
- // A map's template lives on `spread.cj` rather than in `peg`, so a
660
- // declaration path spells it `&` -- the same character the language
661
- // spells it with, and one no map key can collide with, since a bare
662
- // `&` cannot be a key.
663
333
  const COVER_TEMPLATE = '&'
664
334
 
665
335
 
666
336
  // Is this value a bag with children to walk?
667
337
  function coverKids(v: any): { key: string, val: any }[] {
668
- // NO KIND GUARD: the two tests below already reject anything that is
669
- // not a bag, exactly as the Go twin's type switch does, so a guard
670
- // above them is dead code (ADR-002).
671
338
  const out: { key: string, val: any }[] = []
672
339
  if (true === v.isMap && null != v.peg) {
673
340
  for (const k of Object.keys(v.peg).sort(cmpCodePoint)) {
@@ -681,30 +348,12 @@ function coverKids(v: any): { key: string, val: any }[] {
681
348
  }
682
349
 
683
350
 
684
- // The template a bag applies to every child, when it has one. A spread
685
- // with no conjunct is not a declaration: `{"*":{...}}` carries the
686
- // empty spread every map carries, and reading that as a template is
687
- // precisely the confusion this phase exists to end.
688
351
  function coverTemplate(v: any): any {
689
352
  const cj = v?.spread?.cj
690
353
  return null != cj && true === cj.isVal && true !== cj.isTop ? cj : undefined
691
354
  }
692
355
 
693
356
 
694
- // Every declaration the schema makes, as a path, with the node at it.
695
- // Named keys and templates alike, at every depth.
696
- //
697
- // NO IDENTITY GUARD, and that is a decision rather than an omission.
698
- // `walkVals` (ts/src/walk.ts) carries one because it walks values the
699
- // unification MINTED -- findings, conjunct operands, disjunct trials --
700
- // where a node really is reached twice. These two walks descend a
701
- // SETTLED bag through `peg` and `spread` alone, and such a tree is a
702
- // tree: a reference resolves by cloning its target, and an alias, a
703
- // repeated spread and a recursive residual were each probed and share
704
- // nothing. The property is already relied on repository-wide, because
705
- // `canon` walks the same edges with no guard and is computed on every
706
- // one of these values. A guard here would be a branch nothing can
707
- // take, which ADR-002 exists to keep out.
708
357
  function coverDeclare(
709
358
  v: any, path: string[], out: Map<string, any>): void {
710
359
  const tpl = coverTemplate(v)
@@ -741,11 +390,6 @@ function coverDataPaths(
741
390
  // covering template. Undefined when the schema declares nothing there.
742
391
  function coverMatch(
743
392
  anchor: any, segs: string[]): string | undefined {
744
- // NO NIL GUARD ON `at`, and none on an empty `segs`: `at` starts as
745
- // the anchor and is only ever reassigned to a non-nil child or
746
- // template, and coverDataPaths never emits the root path, so a call
747
- // with no segments cannot happen. A guard that cannot fire is dead
748
- // code, and dead code is what ADR-002 exists to keep out.
749
393
  let at: any = anchor
750
394
  let decl = ''
751
395
  for (const seg of segs) {
@@ -849,10 +493,6 @@ export function vetCoverage(
849
493
  leaves,
850
494
  unchecked: coverShallowest(unchecked),
851
495
  unused: coverShallowest(unused),
852
- // VACUOUS IS ABOUT LEAVES, and a document with none cannot be
853
- // vacuously checked: `{}` against any schema examined nothing
854
- // because there was nothing to examine, which is not the failure
855
- // this reports.
856
496
  vacuous: 0 === checked && 0 < leaves,
857
497
  }
858
498
  }
@@ -865,9 +505,6 @@ export function vet(
865
505
  const dataUrl = options.dataUrl ?? DEFAULT_DATA_URL
866
506
  const maxErrors = options.maxErrors ?? VET_MAX_ERRORS
867
507
 
868
- // ONE instance, two bases: the path rides on each CALL rather than on
869
- // the constructor, because the schema and the data may live in
870
- // different directories (Lang.parse takes `opts.path` per parse).
871
508
  const aontu = new Aontu(includeOpts(options))
872
509
  const schemaOpts = null == options.schemaPath ?
873
510
  undefined : { path: options.schemaPath }
@@ -879,34 +516,8 @@ export function vet(
879
516
  const schemaCtx = aontu.ctx({ collect: true })
880
517
  const schemaVal: any = aontu.unify(schemaSrc, schemaOpts, schemaCtx)
881
518
  if (0 < schemaCtx.err.length || true === schemaVal?.isNil) {
882
- // A broken schema REPORTS, exactly as broken data does. It used to
883
- // answer `findings: []` with exit 4 and nothing else, in both
884
- // ports: the engine had collected the fault and vet threw it away,
885
- // so an agent -- or a person -- was told the schema was broken and
886
- // not what or where. The verdict stays `error` (the fault is in
887
- // the truth, not in the data, and that distinction is the whole
888
- // point of the class), but the finding travels with it.
889
- //
890
- // The FIRST error only, and the data path's reasoning applies
891
- // unchanged: later errors in a document that does not stand up are
892
- // consequences of the first rather than separate things to fix.
893
- //
894
- // ONE OF THE TWO IS ALWAYS THERE, and both are nils: the branch
895
- // condition admits a collected error or a nil root, and every
896
- // value on `schemaCtx.err` is a NilVal. There is no third case, so
897
- // there is no guard here -- a guard that cannot fire is dead code,
898
- // and dead code is what ADR-002 exists to keep out. (One stood
899
- // here and the TypeScript line report called it covered; the Go
900
- // gate, which measures blocks, refused the twin.)
901
519
  const failure: any =
902
520
  0 < schemaCtx.err.length ? schemaCtx.err[0] : schemaVal
903
- // The normal path stamps both documents before they meet
904
- // (stampUrl(anchor...) below), and this early return never reaches
905
- // it, so it stamps what it is about to report: the unified root,
906
- // and the failure itself -- a COLLECTED error is minted during
907
- // unification and hangs off no tree, so nothing else would name
908
- // it. The walk reaches a failure's operands (ts/src/walk.ts),
909
- // which is what makes the sites say which file.
910
521
  stampUrl(schemaVal, schemaUrl)
911
522
  stampUrl(failure, schemaUrl)
912
523
  materialise(failure, schemaCtx)
@@ -924,11 +535,6 @@ export function vet(
924
535
  if (null != options.at) {
925
536
  anchor = anchorAt(schemaVal, options.at)
926
537
  if (null == anchor) {
927
- // AND IT SAYS WHICH SEGMENT. `--at` naming nothing is an error
928
- // verdict for the same reason a broken schema is -- the run
929
- // could not be set up from the truth's side -- and it reports
930
- // for the same reason too: a caller handed exit 4 and an empty
931
- // list has nothing to act on.
932
538
  return {
933
539
  verdict: 'error',
934
540
  truncated: false,
@@ -942,22 +548,6 @@ export function vet(
942
548
  const dataCtx = aontu.ctx({ collect: true })
943
549
  const dataVal: any = aontu.parse(dataSrc, dataOpts, dataCtx)
944
550
  if (0 < dataCtx.err.length || null == dataVal) {
945
- // A DATA DOCUMENT THAT WILL NOT PARSE IS THE DATA'S FAULT, and the
946
- // report says so: verdict `invalid`, with a finding carrying the
947
- // parser's own code and a site in the data. `error` is left to mean
948
- // what the exit table says it means -- the run could not be set up
949
- // from the SCHEMA side.
950
- //
951
- // The engine already answered it this way one character earlier: a
952
- // refused CONSTRUCT (`a: 9007199254740993`) reaches the tree as an
953
- // ordinary nil and is reported as an invalid data finding. A stray
954
- // `]` took the throwing path instead and came back as a broken
955
- // SCHEMA -- the same fault, classified two opposite ways by which
956
- // branch the parser happened to take.
957
- //
958
- // The FIRST error only: the parser stops at the first syntax error,
959
- // so a second entry would be a consequence of the first rather than
960
- // a separate thing to fix.
961
551
  const failure = dataCtx.err[0]
962
552
  if (null == failure) {
963
553
  return { verdict: 'error', truncated: false, findings: [] }
@@ -970,17 +560,6 @@ export function vet(
970
560
  findings: [findingOf(failure, { data: new Set([dataUrl]) })],
971
561
  }
972
562
  }
973
- // STAMP THE WHOLE SETTLED SCHEMA, not just the lifted anchor.
974
- // Without `--at` these are the same tree. With it, the anchor is a
975
- // subtree and the rest of the schema is still REACHABLE from inside
976
- // it -- a `%alias` declaration (`[&: %U]`, target `$.%U`) or a
977
- // recursive residual's `$.spec.Step`, both of which the meet
978
- // resolves through _fixroot (RefVal.find, RecurseVal.body). A node
979
- // reached that way but never stamped carries no url, so its site
980
- // named no file while excerpting the schema's text -- against the
981
- // invariant that every site names the file whose text it shows
982
- // (finding F, §25). stampUrl only fills a url that is EMPTY, so
983
- // stamping the superset never renames a value read from an include.
984
563
  stampUrl(schemaVal, schemaUrl)
985
564
  const dataUrls = stampUrl(dataVal, dataUrl)
986
565
  // The projection every site in this report goes through: roles by
@@ -991,15 +570,6 @@ export function vet(
991
570
  dataUrl, dataPath: options.dataPath,
992
571
  }
993
572
 
994
- // COVERAGE IS MEASURED BEFORE THE MEET (G11 phase 5), because the
995
- // meet CONSUMES its operands: parsed trees are single-use, and under
996
- // `--at` the anchor itself is the left operand. Measuring after would
997
- // read a tree the fixpoint had already rewritten.
998
- //
999
- // The data side is its own evaluation rather than the parse above,
1000
- // so a document that reaches its values through `@"..."` or a
1001
- // reference is measured on the paths it actually has. It is one more
1002
- // evaluation of one document, and it happens only when asked for.
1003
573
  let coverage: VetCoverage | undefined
1004
574
  if (true === options.coverage) {
1005
575
  const coverCtx = aontu.ctx({ collect: true })
@@ -1012,31 +582,6 @@ export function vet(
1012
582
  coverage = vetCoverage(anchor, measured, options.coverageAt)
1013
583
  }
1014
584
 
1015
- // Default-validity lint (G3 phase 5, re-examined under ADR-004): for
1016
- // every disjunction in the SCHEMA carrying a preference, warn when
1017
- // the effective default is not an instance of any REMAINING
1018
- // alternative (code `pref_not_instance`, class compat, severity
1019
- // warning).
1020
- //
1021
- // What the finding MEANS changed with the admission gate (ADR-004).
1022
- // Before the gate it flagged a soundness hole: the preference held
1023
- // the disjunction open, so `a:*5|string` both generated a value the
1024
- // alternatives refuse AND admitted any same-kind override. The gate
1025
- // closed that hole — a preferred branch now contributes exactly its
1026
- // own value to the admitted set, so a default can no longer be
1027
- // "invalid against its own disjunct" and the enum-with-default idiom
1028
- // (`*'auto'|'literal'|'data'`) is sound as written. The lint is KEPT,
1029
- // as an advisory: a default admitted only because it is the default
1030
- // is also the exact shape of a typo'd default
1031
- // (`level:*wran|info|warn|debug` — the intended `*warn` would be
1032
- // silent), and nothing at meet time can catch that. The
1033
- // repeated-branch spelling (`*warn|warn|...`) states "the default is
1034
- // a first-class member", silences the lint, and — unlike before the
1035
- // gate — enforces exactly the same admitted set. The message names
1036
- // the REMAINING alternatives because that is what was scanned: the
1037
- // preferred branch itself always admits its own default, so the old
1038
- // wording ("any alternative of *5|string") read as false on its face
1039
- // (use-cases/BUGS.md §4).
1040
585
  const lintFindings: VetFinding[] = []
1041
586
  walkBagVals(anchor, (v: any, path: string[]): void => {
1042
587
  if (true === v.isDisjunct && Array.isArray(v.peg)) {
@@ -1073,45 +618,10 @@ export function vet(
1073
618
  }
1074
619
  })
1075
620
 
1076
- // `--closed` sets the flag `close()` itself sets, rather than wrapping
1077
- // the anchor in a CloseFuncVal: the anchor is an already-evaluated
1078
- // tree, and a func value would have to resolve again to have any
1079
- // effect. A scalar anchor has no keys to close, so the flag is only
1080
- // meaningful on a bag.
1081
621
  if (true === options.closed && (true === anchor.isMap || true === anchor.isList)) {
1082
622
  anchor.closed = true
1083
623
  }
1084
624
 
1085
- // THE MEET IS FROM A FRESH PARSE, NOT THE SETTLED SCHEMA (the
1086
- // review's finding C, use-cases/BUGS.md §15).
1087
- //
1088
- // Step 1 evaluated the schema ALONE, to decide whether it stands up
1089
- // before any data is blamed for it. That answer is a diagnosis, and
1090
- // it was also being used as the left side of the meet -- so every
1091
- // reference in the schema had already RESOLVED against the schema's
1092
- // own values and been replaced by them. `a:integer b:$.a` settled to
1093
- // `a:integer b:integer`, and data `{a:3,b:4}` then vetted VALID,
1094
- // while the same four lines as one document refuse with
1095
- // scalar_value. A reference is a statement about the FINAL model, and
1096
- // vet is asking about a model the data is part of.
1097
- //
1098
- // Parsing again is what makes `vet(S,D)` and `eval(S ∪ D)` the same
1099
- // question: the meet runs the fixpoint once, over both documents, so
1100
- // references, spreads and generators all see the data. Parsed trees
1101
- // are single-use, hence a second parse rather than a reuse of step
1102
- // 1's. The lint above still reads the SETTLED tree, where
1103
- // disjunctions are ranked and normalised.
1104
- //
1105
- // ONLY WHEN THERE IS NO `--at`. An anchor is a SUBTREE lifted out of
1106
- // the schema, and an absolute reference inside it (`$.OrderPlaced`,
1107
- // the discriminated-union idiom) names a sibling of the document
1108
- // root -- which the lifted subtree no longer has. The settled tree is
1109
- // where those references have already been resolved and substituted,
1110
- // so an anchored run keeps meeting that, exactly as it always has.
1111
- // Making the rule explicit rather than leaving it to whether
1112
- // anchorAt happens to find the path in an unresolved tree: the two
1113
- // ports answered that differently, which is an ADR-001 divergence
1114
- // waiting to happen.
1115
625
  const ctx = aontu.ctx({ collect: true })
1116
626
  let meetAnchor: any = anchor
1117
627
  if (null == options.at) {
@@ -1127,39 +637,13 @@ export function vet(
1127
637
  }
1128
638
  }
1129
639
  else {
1130
- // A RECURSIVE residual inside the lifted anchor still names its
1131
- // definition by absolute path (`then?: $.spec.Step` -- the
1132
- // fixpoint, RECURSION.0.md), and the meet's root is the anchored
1133
- // subtree, which does not contain `$.spec`. Without a tree to
1134
- // walk, the residual held its peer forever and everything under a
1135
- // recursive field vetted VALID unchecked. The settled schema root
1136
- // is kept on the meet context for exactly that walk
1137
- // (AontuContext._fixroot; RecurseVal.body and RefVal.find fall
1138
- // back to it).
1139
640
  ; (ctx as any)._fixroot = schemaVal
1140
- // And the meet DRIVES AT the anchor's own path, so every finding
1141
- // minted live during it sits in the schema's namespace
1142
- // ($.spec.Step.then.approver), exactly where the findings carried
1143
- // on the settled anchor's stored paths already sit -- the Go port
1144
- // gets this for free from its clone discipline, and the shared
1145
- // anchored-vet rows pin the agreement.
1146
641
  ; (ctx as any).path = options.at.replace(/^\$\.?/, '')
1147
642
  .split('.').filter((s: string) => '' !== s)
1148
643
  }
1149
644
  const pair = new ConjunctVal({ peg: [meetAnchor, dataVal] }, ctx)
1150
645
  const unified: any = aontu.unify(pair, undefined, ctx)
1151
646
 
1152
- // 4. Contradictions: every NilVal standing in the result, PLUS the
1153
- // ones that never made it into the tree.
1154
- //
1155
- // The second half is not belt-and-braces. When a parent collapses to
1156
- // a nil the whole subtree goes with it, so `service: close({...})`
1157
- // meeting a typo AND a kind conflict leaves ONE nil in the tree and
1158
- // reports the other only on the context — the vet verb's own
1159
- // motivating example, reporting half of what it found. The language
1160
- // server already walks both for this reason; vet dedups by identity
1161
- // the same way, and skips the transient disjunct-trial sentinel,
1162
- // which is bookkeeping rather than a finding.
1163
647
  const seen = new Set<any>()
1164
648
  const nils: any[] = collectNils(unified, seen)
1165
649
  for (const err of ctx.err) {
@@ -1174,45 +658,17 @@ export function vet(
1174
658
  return findingOf(n, prov)
1175
659
  })
1176
660
 
1177
- // 5. Incompleteness: what is left standing that cannot generate. The
1178
- // generate check runs in its own collect context so nothing it
1179
- // raises reaches the caller's error list, and so a schema that is
1180
- // merely unsatisfied does not look like one that is contradicted.
1181
- // No try/catch: in collect mode `gen` records its reasons on the
1182
- // context instead of throwing, which is the whole point of the mode.
1183
661
  const genCtx: any = aontu.ctx({ collect: true })
1184
662
  genCtx.root = unified
1185
- // Under `--at` the probe descends through the OUTPUT marks: the
1186
- // caller named this node as the truth to validate against, so a
1187
- // `type()` or `hide()` on it (or propagated into it) is not a reason
1188
- // to check nothing. See AontuContext.probe.
1189
663
  genCtx.probe = null != options.at
1190
664
  unified.gen(genCtx)
1191
665
  for (const err of genCtx.err) {
1192
- // A CONFLICT RAISED AT GENERATION COUNTS TOO (the review's finding
1193
- // C, use-cases/BUGS.md §16). The filter used to keep the
1194
- // `incomplete` class alone, on the reading that step 4 had already
1195
- // found every contradiction -- true while every conflict was
1196
- // decided during the meet, and untrue since a sizing atom or a
1197
- // container `must` may hold a PROVISIONAL reading until generation,
1198
- // which is where no more members can arrive. Dropping those left
1199
- // `vet` answering `valid` for data the evaluator refuses, which is
1200
- // the one disagreement the vet-equals-eval harness exists to catch
1201
- // -- and did.
1202
- //
1203
- // Deduped against step 4 by the same cause key the loop below uses,
1204
- // so a contradiction seen twice is still reported once.
1205
666
  if ('incomplete' === err.class || 'conflict' === err.class) {
1206
667
  materialise(err, genCtx)
1207
668
  findings.push(findingOf(err, prov))
1208
669
  }
1209
670
  }
1210
671
 
1211
- // 5b. Deprecation warnings (G3 phase 4): a value that carries the
1212
- // deprecate() record after the meet was USED — the data met a
1213
- // deprecated schema value, or the schema's own default will
1214
- // generate one. Severity `warning` (the slot G2 reserved for
1215
- // exactly this mark), and warnings never touch the verdict below.
1216
672
  findings.push(...lintFindings)
1217
673
  for (const { val, path } of collectDeprecations(unified)) {
1218
674
  const v: any = val
@@ -1242,27 +698,6 @@ export function vet(
1242
698
  keyed.sort((a, b) => a.key < b.key ? -1 : 1)
1243
699
  let ordered = keyed.map((k) => k.finding)
1244
700
 
1245
- // ONE CAUSE, ONE FINDING. A reference resolves by CLONING its target,
1246
- // so a target that later fails can fail once per referrer — same
1247
- // code, same two source sites, a different path each time. Multi-pass
1248
- // collection (G2 phase 6) made this reachable: the pass loop now
1249
- // continues past the erroring pass, so the clones' own folds run too.
1250
- // The dedup key is the CODE plus the SITES (file, row, col, value,
1251
- // role): two findings that name the same meet of the same two source
1252
- // positions are one contradiction observed from two paths. The key is
1253
- // NOT (code, path) — the design's sketch — because the paths are
1254
- // exactly what differ. Sorted order makes the kept finding the first
1255
- // by data site then path, deterministically in both ports.
1256
- //
1257
- // THE KEPT PATH IS THE DEEPEST one (use-cases/BUGS.md §41). A meet
1258
- // that fails inside a REFERENCED map is recorded twice: once at the
1259
- // key that actually conflicts, and once at the enclosing map, which
1260
- // collapsed as a consequence and carries the child's two sites. Both
1261
- // are the same cause; only the deeper one names the field an author
1262
- // or an agent has to edit, and `$.q` for a conflict in `$.q.a` sent a
1263
- // repair loop to rewrite the whole record -- twice over, identically,
1264
- // when two of its fields conflicted. Depth first, then the sort order
1265
- // above, so the choice stays deterministic in both ports.
1266
701
  const causeKey = (f: VetFinding): string =>
1267
702
  f.code + '\u0000' + f.sites.map((s) =>
1268
703
  [s.file, s.row, s.col, s.role, s.value].join('\u0000')).join('\u0000')
@@ -1288,22 +723,6 @@ export function vet(
1288
723
  const truncated = maxErrors < ordered.length
1289
724
  const kept = truncated ? ordered.slice(0, maxErrors) : ordered
1290
725
 
1291
- // 6. The verdict derives from finding CLASSES, never from codes, so a
1292
- // new code can never change exit behaviour.
1293
- //
1294
- // BY CLASS, NOT BY STAGE. The split used to be positional -- whatever
1295
- // step 4 found counted as contradiction and whatever step 5 added
1296
- // counted as incompleteness -- which stopped being true when a sizing
1297
- // atom or a container `must` began holding a provisional reading
1298
- // until generation (the review's finding C, use-cases/BUGS.md §16). A
1299
- // CONTRADICTION found at generation is still a contradiction: reading
1300
- // it as mere incompleteness answered `incomplete` where the evaluator
1301
- // refuses, and `vet` and `eval` have to agree.
1302
- //
1303
- // So: an error-severity finding that is not INCOMPLETENESS makes the
1304
- // document invalid, wherever it was found -- a contradiction, a parse
1305
- // refusal, an unresolvable reference alike. Warnings (the `compat`
1306
- // class: lint and deprecation) never touch the verdict.
1307
726
  let verdict: VetVerdict = 'valid'
1308
727
  const errors = ordered.filter((f) => 'error' === f.severity)
1309
728
  const unmet = errors.filter((f) => 'incomplete' === f.class).length