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/patch.ts CHANGED
@@ -1,58 +1,5 @@
1
1
  /* Copyright (c) 2025 Richard Rodger, MIT License */
2
2
 
3
- // OVERLAY PATCH (G7 phase 5,
4
- // docs/capability-review/g7-machine-access.md): change a document by
5
- // APPENDING to an overlay, not by rewriting the file.
6
- //
7
- // This is the stage that needs no rewriter. An overlay entry is just
8
- // another conjunct, and unification is order-independent, so appending
9
- // `services: auth: owner: "identity-2"` to a second file and
10
- // evaluating both is exactly the same value as writing it into the
11
- // first — with no parsing of the target, no comment or layout damage,
12
- // and nothing to preserve. The spec pins that equivalence rather than
13
- // asserting it.
14
- //
15
- // What an overlay CANNOT do is change a PINNED value: the lattice
16
- // refuses 5 against 3, and the report says so with the pinning site,
17
- // which `why` then locates. That left the loop "set → conflict → why →
18
- // edit the pinning site" with its last step manual — and since the
19
- // commonest vet failure of all is "the data pins the wrong value",
20
- // `set` was unable to repair the very case it existed for.
21
- //
22
- // IN-PLACE REPLACE (`--in-place`) closes that. The G7 design deferred
23
- // it behind two prerequisites: an evaluated-path → contributing-span
24
- // map, and a comment-and-layout-preserving CST. The first now exists —
25
- // `why` is that map, and sites carry `len` and `src` since a site was
26
- // given an extent. The second turns out NOT to be needed for the case
27
- // that matters, and the reason is worth stating: a CST is what you need
28
- // to RE-SERIALISE a document, and a targeted span splice serialises
29
- // nothing. It replaces `len` code units at one offset and leaves every
30
- // other byte — every comment, every blank line, every alignment space —
31
- // exactly as the author left it, because it never looks at them.
32
- //
33
- // What makes the splice safe rather than merely plausible is that the
34
- // site carries `src`, the text it claims to cover. The span is VERIFIED
35
- // against it before a byte is written, so the corrupting arithmetic
36
- // this repository has already shipped once — `port: 0x1F` reporting
37
- // canon `"31"` at column 7, and `(col, canon.length)` writing
38
- // `port: 5x1F` — cannot be reached: `0x1F` is four code units and says
39
- // so, and if the text at the span is anything else the edit is refused
40
- // rather than guessed.
41
- //
42
- // Replace is never WORSE than append. Where the value is not a single
43
- // editable literal in this overlay — a spread template governing other
44
- // keys, a reference whose site is the `$` and not the target, two
45
- // statements pinning the same path, a literal in an included file — the
46
- // splice is refused and the assignment is APPENDED exactly as it would
47
- // have been without the flag, plus one `warning` finding naming the
48
- // case and the site it came from. Warnings never move a verdict, so
49
- // `--in-place` cannot turn a run that would have succeeded into one
50
- // that fails; it can only rewrite where rewriting is safe, and explain
51
- // itself where it is not.
52
- //
53
- // The verdict is G2's, unchanged: `vet(entry, overlay)` already asks
54
- // exactly the right question — does this document hold against that
55
- // truth, and if not, where — so `set` adds a writer, not a report.
56
3
 
57
4
  import { vet } from './vet'
58
5
  import type { TrustOptions } from './type'
@@ -67,19 +14,10 @@ export type PatchOptions = {
67
14
  // them resolve from their own directories (vet's precedent).
68
15
  entryPath?: string
69
16
  overlayPath?: string
70
- // Rewrite a pinned literal where the author wrote it, instead of
71
- // appending a line that contradicts it. Opt-in: appending is
72
- // non-destructive and in-place editing is not, so the caller says
73
- // which one they meant.
74
17
  inPlace?: boolean
75
18
  // The include capability this document evaluates under
76
19
  // (G5, docs/trust.md); vet's precedent.
77
20
  trust?: TrustOptions
78
- // The extensions an include additionally reads as text (the CLI's
79
- // --text-ext). It rides WITH the capability, never beside it: this
80
- // verb threaded the capability and not the extension, so `set`
81
- // refused an include -- and wrote nothing -- under a flag the bare
82
- // command honoured.
83
21
  textExt?: string[]
84
22
  }
85
23
 
@@ -97,13 +35,7 @@ export type PatchReplacement = {
97
35
  }
98
36
 
99
37
  export type PatchReport = {
100
- // The overlay text as it would stand after the assignments: the
101
- // existing text, with any in-place replacements applied, plus one
102
- // appended line for each assignment that was not replaced. The caller
103
- // writes it — an engine that touched the filesystem could not be used
104
- // by a server, and the CLI is the one place that knows about files.
105
38
  overlay: string
106
- // The appended lines alone, in order.
107
39
  appended: string[]
108
40
  // The in-place replacements made, in the order the assignments were
109
41
  // given (NOT the order they were applied to the text, which is
@@ -133,23 +65,12 @@ export function parseAssignment(
133
65
  }
134
66
 
135
67
 
136
- // The path-flattened conjunct one assignment becomes:
137
- // `$.a.b = 1` is `"a": "b": 1`. Keys are QUOTED — a segment may be a
138
- // word the grammar spells otherwise (`if`), a number, or a name with
139
- // a space in it, and quoting one key is the same value as writing it
140
- // bare.
141
68
  export function overlayLine(path: string, value: string): string {
142
69
  return pathParts(path).map((p) => JSON.stringify(p)).join(': ') +
143
70
  ': ' + value
144
71
  }
145
72
 
146
73
 
147
- // The character offset of a 1-based (row, col) in `src`, or -1 when the
148
- // text has no such position. Columns are UTF-16 code units, which is
149
- // what a site carries and what a JavaScript string index already is —
150
- // so this is the inverse of the site arithmetic, not a reinterpretation
151
- // of it (go/patch.go converts to a byte offset, because Go strings are
152
- // bytes; both address the same character).
153
74
  export function offsetAt(src: string, row: number, col: number): number {
154
75
  if (row < 1 || col < 1) {
155
76
  return -1
@@ -177,27 +98,9 @@ export function spanAt(
177
98
  }
178
99
 
179
100
 
180
- // DOES THE TEXT AT THIS SITE SAY WHAT THE SITE CLAIMS IT SAYS?
181
- //
182
- // The last check before a splice, and the one that makes the write
183
- // PROVABLE rather than argued. Exported so it can be exercised with a
184
- // site the engine would never produce — an out-of-range position, a
185
- // span over different text — which is the only way to test a guard whose
186
- // whole purpose is to catch a state the rest of the code says cannot
187
- // happen. (go/patch.go has the twin, tested the same way.)
188
101
  export function spanHolds(
189
102
  src: string, site: { row: number, col: number, len: number }, expect: string
190
103
  ): boolean {
191
- // THE SITE'S OWN LENGTH IS PART OF ITS CLAIM, and is checked before
192
- // the text is. A site whose `len` disagrees with the text it says it
193
- // covers CONTRADICTS ITSELF, which is exactly the state this guard
194
- // exists to catch — and a zero-length span would otherwise compare
195
- // equal against nothing and then splice nothing, INSERTING the new
196
- // value rather than replacing anything.
197
- //
198
- // Both ports compare in UTF-16 code units, which is what a site's
199
- // `len` counts. That is free here and is not in Go, where a string is
200
- // bytes (go/patch.go converts).
201
104
  if ('' === expect || site.len !== expect.length) {
202
105
  return false
203
106
  }
@@ -205,68 +108,17 @@ export function spanHolds(
205
108
  }
206
109
 
207
110
 
208
- // WHY IS THE VALUE AT THIS PATH WHAT IT IS, and is exactly one of the
209
- // answers a literal this overlay can edit in place?
210
- //
211
- // The four refusals below are not defensive padding; each is a real
212
- // document shape that the probe corpus produced, and each would corrupt
213
- // something different if the splice ran anyway:
214
- //
215
- // - a SPREAD contribution's site is inside the template, which
216
- // governs every other key too, so rewriting it there changes keys
217
- // the author did not name;
218
- // - a REFERENCE's site is the `$` that starts the path and has length
219
- // 1, so splicing over it writes the new value INTO the path
220
- // expression (`$.base` becomes `5.base`) — and the value the author
221
- // wants changed lives at the target anyway;
222
- // - TWO literals at one path (a duplicate key, two files merged) give
223
- // no single place to edit, and picking either silently is picking
224
- // for the author;
225
- // - a literal in an INCLUDED file is editable, but not by
226
- // `--overlay <this file>`: the write would land in a document the
227
- // caller did not name.
228
- //
229
- // A PREFERENCE is not refused here for the same reason it is not
230
- // replaced: appending already overrides a default correctly, so the
231
- // caller loses nothing by falling through to it.
232
111
  function editableLiteral(
233
112
  overlaySrc: string,
234
113
  path: string,
235
114
  overlayPath: string | undefined,
236
115
  ): { site: PatchReplacement | undefined, finding: VetFinding | undefined } {
237
- // THE AUTHORITY IS THE OVERLAY TEXT ALONE, WITH INCLUDES DENIED.
238
- //
239
- // The splice happens in the text this function was handed, so what it
240
- // has to establish is that the contribution is IN that text — and the
241
- // site's `file` cannot establish it. Two ways it fails: a caller of
242
- // the library API need not pass `overlayPath`, leaving nothing to
243
- // compare against; and the Go port names the ENTRY document for an
244
- // included value anyway (issue #66), so the comparison is the overlay
245
- // against itself. Either way an included literal's (row, col, len,
246
- // src) can COINCIDE with different text at the same coordinates here
247
- // — an include holding `a: 42` at 1:4 and an overlay holding `x: 42`
248
- // at 1:4 — and the span verification cannot tell them apart, because
249
- // the text really does match. The splice then rewrites `x` while
250
- // reporting a replacement of `$.a`, in both ports.
251
- //
252
- // Denying includes removes the ambiguity at its source rather than
253
- // detecting it: what resolves is what this text says by itself. An
254
- // overlay that loads other documents therefore cannot be edited in
255
- // place at all — the conservative answer, and the assignment still
256
- // appends. It costs nothing in the shape `set` is for, an overlay it
257
- // owns and appends to, and it does not depend on file attribution, so
258
- // both ports agree without waiting on #66.
259
116
  const alone = why(overlaySrc, path, {
260
117
  trust: { include: 'none' },
261
118
  ...(null == overlayPath ? {} : { path: overlayPath }),
262
119
  })
263
120
 
264
121
  if (true !== alone.ok || null == alone.record) {
265
- // Nothing here BY ITSELF. Two very different reasons, and they earn
266
- // different answers: the path may simply not be in this overlay, in
267
- // which case appending is the whole of the answer and nothing has
268
- // gone wrong — or it may be here only because something was loaded,
269
- // which is the case above and has to say so.
270
122
  const withLoads = why(overlaySrc, path,
271
123
  null == overlayPath ? undefined : { path: overlayPath })
272
124
  if (true !== withLoads.ok || null == withLoads.record) {
@@ -290,14 +142,6 @@ function editableLiteral(
290
142
  // coverage gate says so, an arm nothing can take.
291
143
  const conjuncts: WhyConjunct[] = record.conjuncts
292
144
 
293
- // A VALUE REACHED THROUGH A REFERENCE IS NOT THIS PATH'S TO EDIT.
294
- // Provenance travels through clones now, so `n: $.base` against
295
- // `base: 7` reports the literal `7` -- correctly, and at the site
296
- // where it was written, which is `base`'s line and not `n`'s. A
297
- // splice there would rewrite the REFERENT: every other reader of
298
- // `$.base` changes with it, and the path the caller named does not
299
- // move at all. The reference is what stands here, so the reference
300
- // is what has to be edited, wherever it points.
301
145
  const refs = conjuncts.filter((c) => 'ref' === c.role)
302
146
  if (0 < refs.length) {
303
147
  return {
@@ -343,17 +187,6 @@ function editableLiteral(
343
187
  }
344
188
 
345
189
 
346
- // THE SPAN MUST CHECK OUT before anything splices. The refusal arm is
347
- // unreachable through `patch` since ADR-018: the pipe (`x: hello |>
348
- // upper`) was the one spelling that synthesised a contribution the
349
- // parser never sited, and denying includes means every WRITTEN
350
- // contribution's coordinates describe this text by construction. The
351
- // verification is kept rather than deleted — splicing without it would
352
- // corrupt the file (a contribution with no `src` would splice ZERO
353
- // characters, INSERTING the new value into the middle of a line) — and
354
- // this last step is its own exported seam so the refusal can be tested
355
- // directly, against conjuncts the engine would never produce, on the
356
- // same footing as `spanHolds` itself.
357
190
  export function verifiedSite(
358
191
  overlaySrc: string,
359
192
  path: string,
@@ -371,29 +204,6 @@ export function verifiedSite(
371
204
  return { site: undefined, finding }
372
205
  }
373
206
 
374
- // DOES THE SPAN MEAN THE WHOLE CONTRIBUTION?
375
- //
376
- // This is the check that `role === 'literal'` looks like it makes and
377
- // does not. A site names the TOKEN it points at, so a COMPOUND value
378
- // reports its OPENING token while its canon is the whole thing:
379
- // `min(1)` is a literal-role contribution whose src is `min`, `1+2`
380
- // reports `1`, `$.k+1` reports `$`, `{b:1}` reports `{` and `[1,2]`
381
- // reports `[`. Splicing over any of those writes the new value INTO
382
- // the expression — `a: 5(1)`, `a: 5+2`, `a: 5.k+1` — which is the
383
- // same class of corruption as the canon-length arithmetic, reached by
384
- // a different route.
385
- //
386
- // Rather than enumerate the shapes (a list is a thing to be
387
- // incomplete about), ASK THE ENGINE: parse `src` on its own and
388
- // require the value it means to be the value the contribution
389
- // contributed. That is exactly the property a splice needs — this
390
- // text, alone, is this value — and it is decided by the same unifier
391
- // that produced the contribution, so it cannot drift from it.
392
- //
393
- // It also gets the interesting case right without special-casing it:
394
- // `0x1F` canons to `31`, which is not its own spelling, but IS the
395
- // contribution's canon, so a hex literal is editable while `min` is
396
- // not.
397
207
  const span = spanValue(one.src)
398
208
  if (null == span || span.canon !== one.canon) {
399
209
  return {
@@ -407,11 +217,6 @@ export function verifiedSite(
407
217
  }
408
218
  }
409
219
 
410
- // AN ABSTRACT CONTRIBUTION IS NOT A PIN. `a: integer` and
411
- // `a: above(0)` state a constraint, and appending already narrows
412
- // them — that is the one case the status report notes `set` could
413
- // always repair. Replacing them would silently DISCARD a constraint
414
- // the author wrote, to no benefit, so this falls through to append.
415
220
  if (true !== span.concrete) {
416
221
  return {
417
222
  site: undefined,
@@ -436,21 +241,8 @@ export function verifiedSite(
436
241
  }
437
242
 
438
243
 
439
- // What does this source text mean ON ITS OWN, and is it a value rather
440
- // than a constraint? Undefined when it does not stand alone at all
441
- // (`$` from a path, an unbalanced `{`).
442
- //
443
- // The wrapper key is arbitrary and the document it makes is thrown
444
- // away; what is wanted is the unifier's own reading of the fragment.
445
244
  export function spanValue(
446
245
  src: string): { canon: string, concrete: boolean } | undefined {
447
- // NO COLLECTING CONTEXT: `unify` THROWS on a source it cannot read,
448
- // so a ctx.err check here is a branch nothing can reach — the catch
449
- // below is the only path a bad fragment takes. (A first draft had
450
- // both, and the coverage gate called the pair what it was.) What the
451
- // nil test still earns is the fragment that PARSES and means nothing:
452
- // `$` is a path with no target, and answers a nil rather than
453
- // throwing.
454
246
  let canon: string
455
247
  try {
456
248
  const root: any = new Aontu().unify('v: ' + src)
@@ -477,11 +269,6 @@ export function spanValue(
477
269
  }
478
270
 
479
271
 
480
- // A refusal to replace, as a WARNING: the assignment still appends, so
481
- // nothing about the run got worse and the verdict must not move
482
- // (ts/src/vet.ts, "warnings never touch the verdict"). What the finding
483
- // adds is the reason, which is the whole value of asking for --in-place
484
- // over plain set.
485
272
  function notEditable(
486
273
  code: string, path: string, why: string, from: WhyConjunct[]
487
274
  ): VetFinding {
@@ -508,12 +295,6 @@ function notEditable(
508
295
  }
509
296
 
510
297
 
511
- // Append the assignments to the overlay and answer what the result
512
- // holds. The report's verdict is the vet verdict of the ENTRY against
513
- // the new overlay: `valid` when it holds and is concrete, `incomplete`
514
- // when nothing contradicts but the truth is not yet satisfied,
515
- // `invalid` when the overlay contradicts a pinned value, `error` when
516
- // the entry itself does not stand up.
517
298
  export function patch(
518
299
  entrySrc: string,
519
300
  overlaySrc: string,
@@ -555,9 +336,6 @@ export function patch(
555
336
  notes.push(found.finding)
556
337
  }
557
338
  if (null != found.site) {
558
- // Two assignments naming the same path would splice the same
559
- // span twice. The second is the one the author wrote last, so
560
- // it wins — and the first is dropped rather than layered.
561
339
  const at = offsetAt(overlaySrc, found.site.row, found.site.col)
562
340
  const dup = edits.findIndex((e) => e.at === at)
563
341
  const edit = { at, len: found.site.from.length, to: a.value }
@@ -578,10 +356,6 @@ export function patch(
578
356
 
579
357
  const overlay = joinOverlay(applyEdits(overlaySrc, edits), appended)
580
358
 
581
- // The file names ride as URLs as well as base paths, so a finding
582
- // names the entry and the overlay rather than vet's generic
583
- // `schema`/`data` labels — with two documents that both belong to
584
- // the caller, "which file" is the whole question.
585
359
  const report: VetReport = vet(entrySrc, overlay, {
586
360
  trust: options.trust,
587
361
  textExt: options.textExt,
@@ -604,8 +378,6 @@ export function patch(
604
378
  }
605
379
 
606
380
 
607
- // Apply the collected splices back to front, so an earlier edit's
608
- // offset is never invalidated by a later one having already run.
609
381
  function applyEdits(
610
382
  src: string, edits: { at: number, len: number, to: string }[]
611
383
  ): string {
@@ -620,10 +392,6 @@ function applyEdits(
620
392
  }
621
393
 
622
394
 
623
- // One line per assignment, after whatever the overlay already said. A
624
- // trailing newline is kept when the file had one and added when it
625
- // did not: a file that does not end in a newline is still a file, and
626
- // appending to it must not join two entries into one line.
627
395
  function joinOverlay(overlaySrc: string, appended: string[]): string {
628
396
  if (0 === appended.length) {
629
397
  return overlaySrc
package/src/profile.ts ADDED
@@ -0,0 +1,42 @@
1
+ /* Copyright (c) 2026 Richard Rodger, MIT License */
2
+
3
+
4
+ import { Aontu } from './aontu'
5
+ import { vet, failureFinding } from './vet'
6
+ import { hcanon } from './hcanon'
7
+ import { includeOpts } from './utility'
8
+
9
+ import type { IncludeOptions } from './utility'
10
+ import type { VetFinding } from './vet'
11
+
12
+
13
+ export type ProfileOptions = IncludeOptions & {
14
+ // Where the document CAME FROM, so a relative `@"file"` load inside
15
+ // it resolves from its own directory.
16
+ path?: string
17
+ }
18
+
19
+
20
+ const PROFILE_VOCABULARY = '@"aontu:profile"'
21
+
22
+
23
+ // A language declared as data, vetted, or the findings that refuse it.
24
+ export function loadProfile(src: string, options?: ProfileOptions):
25
+ { profile?: any, errors?: VetFinding[] } {
26
+ const opts = options ?? {}
27
+ const aontu = new Aontu(includeOpts(opts))
28
+ const actx = aontu.ctx({ collect: true })
29
+ const root: any = aontu.unify(src, { path: opts.path, collect: true }, actx)
30
+ if (0 < actx.err.length || true === root?.isNil) {
31
+ return { errors: [failureFinding(actx, opts.path, root)] }
32
+ }
33
+ const report = vet(PROFILE_VOCABULARY, hcanon(root))
34
+ if ('valid' !== report.verdict) {
35
+ return { errors: report.findings }
36
+ }
37
+ // The meet: the vocabulary requires `lang`, so a value the vet
38
+ // admitted has a `Lang`.
39
+ const instance = new Aontu().generate(
40
+ PROFILE_VOCABULARY + '\naontu: Lang: ' + hcanon(root.peg.aontu.peg.Lang))
41
+ return { profile: instance.aontu.Lang }
42
+ }
package/src/provenance.ts CHANGED
@@ -1,33 +1,5 @@
1
1
  /* Copyright (c) 2025 Richard Rodger, MIT License */
2
2
 
3
- // THE PROVENANCE RECORDER (G7 phase 3,
4
- // docs/capability-review/g7-machine-access.md): what CONTRIBUTED to
5
- // the value at a path, in order, with the site each contribution was
6
- // written at. `why` is the positive twin of G2's error report — errors
7
- // explain what failed to unify, this explains what did.
8
- //
9
- // The recorder rides the CONTEXT and is off by default: `unite` pays
10
- // one property load on the normal path, and an instrumented run pays
11
- // site materialisation knowingly. It records at `unite` and nowhere
12
- // else, because that is the one place every meet passes through — the
13
- // same reason G3's deprecation rider lives there. A meet is where
14
- // information currently vanishes, so a meet is what to record.
15
- //
16
- // Contributions are the operands that were NOT produced by an earlier
17
- // meet at the same path: a value that a previous meet made is an
18
- // intermediate, not a source. Deduplicated by (path, val id) — ids are
19
- // unique per run — so fixpoint revisits across up to `maxcc` passes do
20
- // not multiply the record.
21
- //
22
- // Roles come from the operand itself, with no further instrumentation:
23
- // a reference is still a RefVal when it meets its peer (its canon is
24
- // the path it names), a preference is still a PrefVal (its canon is
25
- // the `*` form), and a spread-applied template is marked once where
26
- // the spread is applied. Precedence is spread > ref > pref > literal:
27
- // a preference INSIDE a spread template is a spread contribution,
28
- // which is what the author needs to be told.
29
-
30
-
31
3
 
32
4
  export type WhyRole = 'literal' | 'spread' | 'ref' | 'pref'
33
5
 
@@ -36,8 +8,6 @@ export type WhyRole = 'literal' | 'spread' | 'ref' | 'pref'
36
8
  export type WhySite = {
37
9
  col: number
38
10
  file: string
39
- // The extent in UTF-16 code units, or -1 when unknown. The same
40
- // field, and the same meaning, as VetSite.len (ts/src/vet.ts).
41
11
  len: number
42
12
  row: number
43
13
  }
@@ -46,20 +16,7 @@ export type WhyConjunct = {
46
16
  canon: string
47
17
  role: WhyRole
48
18
  site: WhySite
49
- // The SOURCE TEXT this contribution was written as.
50
- //
51
- // `canon` is the value; `src` is the spelling. They are not the same
52
- // thing, and the difference is the whole reason this record exists:
53
- // `port: 0x1F` contributes canon `31` from source `0x1F`, so a reader
54
- // told only the canon cannot find, verify or replace what was
55
- // actually written. Empty when the contribution occupies no source —
56
- // a value unification minted rather than a document wrote.
57
19
  src: string
58
- // The PREFERENCE RANK, 0-based, when the contribution is one: `*x`
59
- // is 0, `**x` is 1. Absent for anything else. The engine's own
60
- // number (PrefVal.rank), so a reader arbitrating between ranked
61
- // contributions -- the meet ladder -- need not count stars in a
62
- // canon string.
63
20
  rank?: number
64
21
  }
65
22
 
@@ -75,77 +32,12 @@ export type WhyRecord = {
75
32
  export const FROM_SPREAD = '_fromSpread'
76
33
 
77
34
 
78
- // THE AUTHORED MARK, and it is a property of the VALUE rather than a
79
- // set of ids held beside it (the review's finding E). A contribution
80
- // is a value the author wrote, and the recorder used to decide that by
81
- // looking the operand's id up in a set stamped over the parsed tree --
82
- // which is true of the parsed tree and of nothing derived from it. So
83
- // every value that reached a path through a CLONE was dark: a default
84
- // flowing into a `pack()`-generated child, a shape carried by a `$ref`,
85
- // a value a spread template stamped. `why` answered "(no contributions:
86
- // nothing met at this path)" over a value it had just printed, with
87
- // exit 0 -- a false statement, and the one an audit surface may not
88
- // make (use-cases/BUGS.md §23, §24).
89
- //
90
- // A clone of a written value IS that written value, re-instantiated
91
- // somewhere else: it carries the author's site, so it can be pointed
92
- // at. Val.clone therefore carries this mark, exactly as it carries the
93
- // site -- provenance is part of the clone contract, not a recorder
94
- // bolted beside it. Values the engine MINTS (a kind lifted while a
95
- // disjunct trials its members, a fold's intermediate) are constructed
96
- // rather than cloned and stay unmarked, which is what keeps the record
97
- // to what the author can edit.
98
- //
99
- // The mark is only ever SET by an instrumented run (`why` calls
100
- // writtenFrom; nothing else does), so an ordinary evaluation pays one
101
- // undefined property read per clone.
102
35
  export const WRITTEN = '_written'
103
36
 
104
37
 
105
- // THE CONTAINER A VALUE IS PART OF, when the two stand at the SAME
106
- // path: a junction's members, a preference's inner value, a function's
107
- // arguments, an operator's operands. `*1|integer` is one thing the
108
- // author wrote, and `*1` is not a second thing beside it.
109
- //
110
- // The recorder already knew that where the container itself met
111
- // something -- contributing it marked its members `inside` and the
112
- // filter dropped them. But the container only appears as an operand
113
- // when the fixpoint happens to meet it whole; where it resolves
114
- // member-wise instead (a later sibling of a spread, a default reaching
115
- // a generated child) the members arrived alone and the record split
116
- // one written value into two contributions at two columns. Which
117
- // happened was decided by evaluation order, so `why` answered
118
- // differently for identical statements (use-cases/BUGS.md §22).
119
- //
120
- // So the relation is recorded as a fact about the DOCUMENT, at
121
- // stamping time, and an operand is reported as the outermost written
122
- // value it is part of. NOT set for a bag's children (they stand at
123
- // their own, deeper paths) nor for a conjunct's terms (a conjunct is
124
- // the statement that several things must all hold, and each term is
125
- // one of them -- which is exactly what the author needs shown).
126
38
  export const INNER_OF = '_innerOf'
127
39
 
128
40
 
129
- // Mark a spread clone and everything inside it, so a contribution
130
- // several levels down a template is still known to have come from the
131
- // template. ONLY on an instrumented run: the walk is O(template) per
132
- // key per pass, which is real money on a large model and buys nothing
133
- // when no one is recording.
134
- //
135
- // THE GUARD IS A CYCLE GUARD, NOT A "DONE" FLAG, and that distinction
136
- // is the whole of the review's finding E for sibling position. A
137
- // template is applied once per destination, and the fixpoint advances
138
- // values IN PLACE between those applications (AGENTS.md, the mutation
139
- // caveat): by the time the second key is spread, the template's
140
- // `replicas` child is no longer the disjunction the first key saw but
141
- // the value that meet produced. Skipping the walk because the
142
- // CONTAINER was already marked left every one of those replacements
143
- // unmarked, so `why` at the first sibling reported the written
144
- // `*1|integer` as one contribution and at the second reported `*1` and
145
- // `integer` as two -- identical statements, different answers, decided
146
- // by which key the fixpoint reached first (use-cases/BUGS.md §22).
147
- // Marking is idempotent, so re-walking costs a pass and changes
148
- // nothing where nothing moved.
149
41
  export function markSpread(v: any, seen?: Set<any>): void {
150
42
  const marked = seen ?? new Set<any>()
151
43
  if (null == v || true !== v.isVal || marked.has(v)) {
@@ -189,10 +81,6 @@ function samePathKids(v: any): any[] {
189
81
  }
190
82
 
191
83
 
192
- // Order contributions the way the document reads: by file, then row,
193
- // then column, with the canon as the last tiebreak so the order is
194
- // total even for two values written at the same position (which a
195
- // merged duplicate key can produce).
196
84
  function cmpSite(a: Contribution, b: Contribution): number {
197
85
  return a.site.file.localeCompare(b.site.file) ||
198
86
  a.site.row - b.site.row ||
@@ -231,20 +119,8 @@ type PathRecord = {
231
119
  export class Provenance {
232
120
  paths: Map<string, PathRecord> = new Map()
233
121
 
234
- // id -> the written container it names, for INNER_OF. The mark on a
235
- // value is the container's ID rather than the container itself: a
236
- // Val holding another Val as an own property is a reference cycle
237
- // through the tree, and enough of the engine walks a value's own
238
- // properties that one is not safe to introduce.
239
122
  containers: Map<number, any> = new Map()
240
123
 
241
- // Stamp the parsed tree with the AUTHORED mark: everything the
242
- // author wrote, before unification starts. A value minted during
243
- // unification — a kind lifted from a leaf while a disjunct trials
244
- // its members, a fold's intermediate — is the engine's own work, not
245
- // a contribution the author can be pointed at. A CLONE of a marked
246
- // value keeps the mark (see WRITTEN above), because it is the same
247
- // written value somewhere else. Called once, before unify, by `why`.
248
124
  writtenFrom(v: any): void {
249
125
  if (null == v || true !== v.isVal || true === v[WRITTEN]) {
250
126
  return
@@ -294,9 +170,6 @@ export class Provenance {
294
170
  }
295
171
 
296
172
  private contribute(rec: PathRecord, v: any): void {
297
- // TOP is the unit element and a nil is a failure, neither of which
298
- // is information the author wrote. A value an earlier meet MADE is
299
- // an intermediate; the source that made it is already recorded.
300
173
  if (null == v || true !== v.isVal || true === v.isTop || true === v.isNil ||
301
174
  rec.made.has(v.id) || rec.seen.has(v.id)) {
302
175
  return
@@ -318,11 +191,6 @@ export class Provenance {
318
191
  if (true !== v[WRITTEN] && true !== v[FROM_SPREAD]) {
319
192
  return
320
193
  }
321
- // A CONJUNCT is not one contribution, it is the statement that
322
- // several must all hold — duplicate keys merged at parse, an
323
- // explicit `a & b`. Its own site is nowhere (the merge has no
324
- // source position), while its terms each have one, which is what
325
- // the author needs to be shown.
326
194
  if (true === v.isConjunct && Array.isArray(v.peg)) {
327
195
  rec.seen.add(v.id)
328
196
  for (const term of v.peg) {
@@ -348,18 +216,6 @@ export class Provenance {
348
216
  })
349
217
  }
350
218
 
351
- // THE VALUE THAT STANDS at a path is a contribution when nothing met
352
- // there and the author wrote it. A meet is where information
353
- // vanishes, so a meet is what the recorder watches -- but a
354
- // generator PLACES a value without meeting anything, and `why` then
355
- // answered "(no contributions: nothing met at this path)" over a
356
- // value it had just printed. That is literally true and practically
357
- // false: the author is asking where the value came from, and it came
358
- // from somewhere they can be shown (use-cases/BUGS.md §23).
359
- //
360
- // Only when the record is otherwise EMPTY. Where something did meet,
361
- // the standing value is that meet's result -- an intermediate, and
362
- // the recorder's oldest rule is that a result is not a source.
363
219
  stands(path: string[], v: any): void {
364
220
  const key = path.join('.')
365
221
  const rec = this.paths.get(key)
@@ -369,50 +225,11 @@ export class Provenance {
369
225
  this.record(path, v, undefined, undefined)
370
226
  }
371
227
 
372
- // The record at one path. Empty when nothing met there and nothing
373
- // the author wrote stands there either — which is a true and useful
374
- // answer rather than an error.
375
- //
376
- // ONLY WHOLE WRITTEN VALUES are contributions. A Val's own unify
377
- // re-enters `unite` at the same path — a disjunct trials each member
378
- // there, a constraint meets its atoms there — and those members are
379
- // PARTS OF one written value, not further values beside it. That is
380
- // settled BEFORE a member is ever pushed, by the INNER_OF fact
381
- // stamped over the document (see `contribute`), which is why no
382
- // filter runs here: a per-path "inside" set used to do it, and it
383
- // could only work where the container itself happened to meet
384
- // something at the same path — the order-dependence finding E
385
- // records.
386
228
  at(path: string[]): WhyConjunct[] {
387
229
  const rec = this.paths.get(path.join('.'))
388
230
  if (null == rec) {
389
231
  return []
390
232
  }
391
- // SOURCE ORDER, not meet order: the two are the same in simple
392
- // cases and diverge with the fixpoint's fold order, which is an
393
- // engine detail and a parity risk. Sites are parse data, identical
394
- // in both ports, so ordering by them makes the record read as the
395
- // document reads and pins it across implementations.
396
- // ONE WRITTEN TOKEN IS ONE CONTRIBUTION, and the SITE is what
397
- // identifies it -- not the val id, and not the canon.
398
- //
399
- // Not the id, because provenance travels through clones now: a
400
- // written value and a clone of it are the same statement in the
401
- // same place, and a path that met both would list it twice.
402
- //
403
- // Not the canon, because the same written value reaches a path at
404
- // different stages of narrowing -- `3|(1|2)` as the author wrote
405
- // it and `3|1|2` after a fold -- and both name one token.
406
- //
407
- // Not the role either: the role says how the value REACHED this
408
- // path, not which value it is, and one written value can reach a
409
- // path both ways (a template applied to a key whose value is also
410
- // written there). Keeping the literal would throw away the more
411
- // informative half, so the roles have a precedence.
412
- //
413
- // ONLY WHERE THE SITE IS REAL. An unsited contribution (row -1)
414
- // cannot be told apart from another unsited one, so those are kept
415
- // as they come rather than collapsed into whichever arrived first.
416
233
  const shown = new Map<string, Contribution>()
417
234
  const order = ['spread', 'ref', 'pref', 'literal']
418
235
  const out: Contribution[] = []