aontu 0.61.0 → 0.63.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (371) hide show
  1. package/README.md +4 -4
  2. package/dist/agentsmd.d.ts +1 -0
  3. package/dist/agentsmd.js +7 -28
  4. package/dist/agentsmd.js.map +1 -1
  5. package/dist/alias.js.map +1 -1
  6. package/dist/allow.d.ts +23 -0
  7. package/dist/allow.js +138 -0
  8. package/dist/allow.js.map +1 -0
  9. package/dist/aontu.d.ts +4 -2
  10. package/dist/aontu.js +4 -80
  11. package/dist/aontu.js.map +1 -1
  12. package/dist/aontumodel.d.ts +4 -0
  13. package/dist/aontumodel.js +33 -0
  14. package/dist/aontumodel.js.map +1 -0
  15. package/dist/cli.d.ts +10 -1
  16. package/dist/cli.js +877 -479
  17. package/dist/cli.js.map +1 -1
  18. package/dist/ctx.js +0 -48
  19. package/dist/ctx.js.map +1 -1
  20. package/dist/diff.js +0 -32
  21. package/dist/diff.js.map +1 -1
  22. package/dist/err.js +0 -40
  23. package/dist/err.js.map +1 -1
  24. package/dist/escape.js +0 -45
  25. package/dist/escape.js.map +1 -1
  26. package/dist/exactjson.d.ts +0 -35
  27. package/dist/exactjson.js +0 -131
  28. package/dist/exactjson.js.map +1 -1
  29. package/dist/format.js +55 -189
  30. package/dist/format.js.map +1 -1
  31. package/dist/grammar.d.ts +9 -0
  32. package/dist/grammar.js +54 -0
  33. package/dist/grammar.js.map +1 -0
  34. package/dist/graph.js +0 -26
  35. package/dist/graph.js.map +1 -1
  36. package/dist/hcanon.js +0 -82
  37. package/dist/hcanon.js.map +1 -1
  38. package/dist/helpdoc.d.ts +16 -0
  39. package/dist/helpdoc.js +59 -0
  40. package/dist/helpdoc.js.map +1 -0
  41. package/dist/hints.d.ts +0 -6
  42. package/dist/hints.js +59 -47
  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 +32 -877
  50. package/dist/lang.js.map +1 -1
  51. package/dist/lower.d.ts +3 -0
  52. package/dist/lower.js +14 -61
  53. package/dist/lower.js.map +1 -1
  54. package/dist/lsp-server.js +0 -16
  55. package/dist/lsp-server.js.map +1 -1
  56. package/dist/lsp.d.ts +1 -1
  57. package/dist/lsp.js +12 -159
  58. package/dist/lsp.js.map +1 -1
  59. package/dist/mcp-server.js +0 -26
  60. package/dist/mcp-server.js.map +1 -1
  61. package/dist/mcp.js +0 -113
  62. package/dist/mcp.js.map +1 -1
  63. package/dist/mod-tool.js +0 -130
  64. package/dist/mod-tool.js.map +1 -1
  65. package/dist/mod.js +0 -162
  66. package/dist/mod.js.map +1 -1
  67. package/dist/patch.js +0 -217
  68. package/dist/patch.js.map +1 -1
  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.d.ts +2 -0
  76. package/dist/relation.js +3 -58
  77. package/dist/relation.js.map +1 -1
  78. package/dist/render.js +33 -143
  79. package/dist/render.js.map +1 -1
  80. package/dist/report-sarif.d.ts +0 -11
  81. package/dist/report-sarif.js +0 -28
  82. package/dist/report-sarif.js.map +1 -1
  83. package/dist/sig.js +0 -35
  84. package/dist/sig.js.map +1 -1
  85. package/dist/sigdecl.js +1 -1
  86. package/dist/sigdecl.js.map +1 -1
  87. package/dist/siggate.js +0 -4
  88. package/dist/siggate.js.map +1 -1
  89. package/dist/site.js +3 -29
  90. package/dist/site.js.map +1 -1
  91. package/dist/subsume.d.ts +0 -10
  92. package/dist/subsume.js +0 -137
  93. package/dist/subsume.js.map +1 -1
  94. package/dist/template.d.ts +2 -1
  95. package/dist/template.js +58 -138
  96. package/dist/template.js.map +1 -1
  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 +12 -242
  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 +20 -0
  125. package/dist/val/CmpFuncVal.js +188 -0
  126. package/dist/val/CmpFuncVal.js.map +1 -0
  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.d.ts +1 -2
  141. package/dist/val/EachFuncVal.js +12 -29
  142. package/dist/val/EachFuncVal.js.map +1 -1
  143. package/dist/val/EmitFuncVal.d.ts +1 -1
  144. package/dist/val/EmitFuncVal.js +6 -119
  145. package/dist/val/EmitFuncVal.js.map +1 -1
  146. package/dist/val/ExpectVal.js +0 -62
  147. package/dist/val/ExpectVal.js.map +1 -1
  148. package/dist/val/FilterFuncVal.js +0 -25
  149. package/dist/val/FilterFuncVal.js.map +1 -1
  150. package/dist/val/FuncBaseVal.d.ts +1 -0
  151. package/dist/val/FuncBaseVal.js +7 -127
  152. package/dist/val/FuncBaseVal.js.map +1 -1
  153. package/dist/val/GraphAtomVal.js +0 -15
  154. package/dist/val/GraphAtomVal.js.map +1 -1
  155. package/dist/val/HideFuncVal.js +0 -13
  156. package/dist/val/HideFuncVal.js.map +1 -1
  157. package/dist/val/IntegerVal.js +0 -61
  158. package/dist/val/IntegerVal.js.map +1 -1
  159. package/dist/val/JunctionVal.js +0 -20
  160. package/dist/val/JunctionVal.js.map +1 -1
  161. package/dist/val/KeyFuncVal.js +0 -46
  162. package/dist/val/KeyFuncVal.js.map +1 -1
  163. package/dist/val/ListVal.js +0 -57
  164. package/dist/val/ListVal.js.map +1 -1
  165. package/dist/val/LowerFuncVal.js +11 -6
  166. package/dist/val/LowerFuncVal.js.map +1 -1
  167. package/dist/val/MapVal.js +0 -151
  168. package/dist/val/MapVal.js.map +1 -1
  169. package/dist/val/MatchFuncVal.js +0 -27
  170. package/dist/val/MatchFuncVal.js.map +1 -1
  171. package/dist/val/{FormFuncVal.d.ts → MaybeFuncVal.d.ts} +5 -5
  172. package/dist/val/MaybeFuncVal.js +50 -0
  173. package/dist/val/MaybeFuncVal.js.map +1 -0
  174. package/dist/val/MoveFuncVal.js +0 -18
  175. package/dist/val/MoveFuncVal.js.map +1 -1
  176. package/dist/val/NilVal.js +2 -36
  177. package/dist/val/NilVal.js.map +1 -1
  178. package/dist/val/NomFuncVal.d.ts +12 -0
  179. package/dist/val/NomFuncVal.js +153 -0
  180. package/dist/val/NomFuncVal.js.map +1 -0
  181. package/dist/val/NumberVal.js +0 -15
  182. package/dist/val/NumberVal.js.map +1 -1
  183. package/dist/val/OpBaseVal.d.ts +1 -0
  184. package/dist/val/OpBaseVal.js +3 -15
  185. package/dist/val/OpBaseVal.js.map +1 -1
  186. package/dist/val/PackFuncVal.js +0 -34
  187. package/dist/val/PackFuncVal.js.map +1 -1
  188. package/dist/val/PathFuncVal.js +0 -6
  189. package/dist/val/PathFuncVal.js.map +1 -1
  190. package/dist/val/PathVal.js +0 -41
  191. package/dist/val/PathVal.js.map +1 -1
  192. package/dist/val/PlaceVal.js +0 -25
  193. package/dist/val/PlaceVal.js.map +1 -1
  194. package/dist/val/PlusOpVal.d.ts +1 -7
  195. package/dist/val/PlusOpVal.js +13 -74
  196. package/dist/val/PlusOpVal.js.map +1 -1
  197. package/dist/val/PrefFuncVal.js +0 -1
  198. package/dist/val/PrefFuncVal.js.map +1 -1
  199. package/dist/val/PrefVal.js +0 -167
  200. package/dist/val/PrefVal.js.map +1 -1
  201. package/dist/val/RecurseVal.js +0 -55
  202. package/dist/val/RecurseVal.js.map +1 -1
  203. package/dist/val/RefVal.js +0 -282
  204. package/dist/val/RefVal.js.map +1 -1
  205. package/dist/val/ReferFuncVal.js +0 -232
  206. package/dist/val/ReferFuncVal.js.map +1 -1
  207. package/dist/val/ScalarKindVal.js +0 -49
  208. package/dist/val/ScalarKindVal.js.map +1 -1
  209. package/dist/val/ScalarVal.js +0 -11
  210. package/dist/val/ScalarVal.js.map +1 -1
  211. package/dist/val/StrFuncVal.js +0 -18
  212. package/dist/val/StrFuncVal.js.map +1 -1
  213. package/dist/val/SuperFuncVal.js +0 -32
  214. package/dist/val/SuperFuncVal.js.map +1 -1
  215. package/dist/val/TopVal.js +0 -1
  216. package/dist/val/TopVal.js.map +1 -1
  217. package/dist/val/TranslateFuncVal.d.ts +12 -0
  218. package/dist/val/TranslateFuncVal.js +99 -0
  219. package/dist/val/TranslateFuncVal.js.map +1 -0
  220. package/dist/val/UpperFuncVal.js +11 -6
  221. package/dist/val/UpperFuncVal.js.map +1 -1
  222. package/dist/val/Val.d.ts +1 -0
  223. package/dist/val/Val.js +2 -133
  224. package/dist/val/Val.js.map +1 -1
  225. package/dist/val/VarVal.js +0 -12
  226. package/dist/val/VarVal.js.map +1 -1
  227. package/dist/val/arith.js +0 -37
  228. package/dist/val/arith.js.map +1 -1
  229. package/dist/val/caserange.d.ts +3 -0
  230. package/dist/val/caserange.js +49 -0
  231. package/dist/val/caserange.js.map +1 -0
  232. package/dist/val/members.js +0 -6
  233. package/dist/val/members.js.map +1 -1
  234. package/dist/val/numcmp.js +0 -11
  235. package/dist/val/numcmp.js.map +1 -1
  236. package/dist/val/numkind.js +0 -145
  237. package/dist/val/numkind.js.map +1 -1
  238. package/dist/val/valutil.js +0 -16
  239. package/dist/val/valutil.js.map +1 -1
  240. package/dist/vet.d.ts +12 -0
  241. package/dist/vet.js +159 -412
  242. package/dist/vet.js.map +1 -1
  243. package/dist/view.js +0 -414
  244. package/dist/view.js.map +1 -1
  245. package/dist/walk.js +0 -41
  246. package/dist/walk.js.map +1 -1
  247. package/grammar/aontu.abnf +9 -7
  248. package/grammar/aontu.gbnf +5 -5
  249. package/grammar/aontu.lark +5 -5
  250. package/grammar/aontu.tmLanguage.json +1 -1
  251. package/package.json +4 -2
  252. package/skill/SKILL.md +8 -0
  253. package/skill/init/check.sh +28 -0
  254. package/skill/init/data.aon +12 -0
  255. package/skill/init/model.aon +19 -0
  256. package/skill/tasks.md +151 -0
  257. package/src/agentsmd.ts +8 -32
  258. package/src/alias.ts +0 -39
  259. package/src/allow.ts +221 -0
  260. package/src/aontu.ts +10 -108
  261. package/src/aontumodel.ts +32 -0
  262. package/src/cli.ts +1009 -540
  263. package/src/ctx.ts +0 -103
  264. package/src/diff.ts +0 -40
  265. package/src/err.ts +0 -40
  266. package/src/escape.ts +0 -46
  267. package/src/exactjson.ts +0 -131
  268. package/src/format.ts +63 -234
  269. package/src/grammar.ts +72 -0
  270. package/src/graph.ts +0 -61
  271. package/src/hcanon.ts +0 -82
  272. package/src/helpdoc.ts +77 -0
  273. package/src/hints.ts +72 -49
  274. package/src/jsonschema.ts +0 -123
  275. package/src/keyorder.ts +0 -42
  276. package/src/lang.ts +39 -895
  277. package/src/lower.ts +15 -65
  278. package/src/lsp-server.ts +0 -16
  279. package/src/lsp.ts +12 -180
  280. package/src/mcp-server.ts +0 -31
  281. package/src/mcp.ts +0 -130
  282. package/src/mod-tool.ts +0 -158
  283. package/src/mod.ts +0 -178
  284. package/src/patch.ts +0 -232
  285. package/src/provenance.ts +0 -183
  286. package/src/query.ts +0 -84
  287. package/src/reach.ts +0 -53
  288. package/src/relation.ts +7 -71
  289. package/src/render.ts +33 -180
  290. package/src/report-sarif.ts +0 -48
  291. package/src/sig.ts +0 -35
  292. package/src/sigdecl.ts +1 -1
  293. package/src/siggate.ts +0 -30
  294. package/src/site.ts +3 -29
  295. package/src/subsume.ts +1 -161
  296. package/src/template.ts +69 -140
  297. package/src/trim.ts +0 -53
  298. package/src/type.ts +2 -45
  299. package/src/unify.ts +13 -251
  300. package/src/utility.ts +0 -31
  301. package/src/val/AbnfFuncVal.ts +181 -0
  302. package/src/val/AbsentVal.ts +54 -0
  303. package/src/val/AggFuncVal.ts +152 -188
  304. package/src/val/ArithFuncVal.ts +0 -20
  305. package/src/val/BagVal.ts +1 -78
  306. package/src/val/BigDecimalVal.ts +0 -16
  307. package/src/val/BigIntegerVal.ts +0 -16
  308. package/src/val/CloseFuncVal.ts +0 -9
  309. package/src/val/CmpFuncVal.ts +249 -0
  310. package/src/val/ConjunctVal.ts +0 -33
  311. package/src/val/ConstraintVal.ts +2 -537
  312. package/src/val/ContainerKindVal.ts +0 -18
  313. package/src/val/CopyFuncVal.ts +0 -5
  314. package/src/val/Decimal.ts +1 -185
  315. package/src/val/DeprecateFuncVal.ts +0 -10
  316. package/src/val/DisjunctVal.ts +0 -157
  317. package/src/val/EachFuncVal.ts +12 -53
  318. package/src/val/EmitFuncVal.ts +8 -208
  319. package/src/val/ExpectVal.ts +0 -62
  320. package/src/val/FilterFuncVal.ts +0 -55
  321. package/src/val/FuncBaseVal.ts +9 -130
  322. package/src/val/GraphAtomVal.ts +0 -42
  323. package/src/val/HideFuncVal.ts +0 -15
  324. package/src/val/IntegerVal.ts +0 -61
  325. package/src/val/JunctionVal.ts +0 -20
  326. package/src/val/KeyFuncVal.ts +0 -48
  327. package/src/val/ListVal.ts +0 -59
  328. package/src/val/LowerFuncVal.ts +12 -7
  329. package/src/val/MapVal.ts +0 -151
  330. package/src/val/MatchFuncVal.ts +0 -59
  331. package/src/val/MaybeFuncVal.ts +86 -0
  332. package/src/val/MoveFuncVal.ts +0 -20
  333. package/src/val/NilVal.ts +2 -36
  334. package/src/val/NomFuncVal.ts +200 -0
  335. package/src/val/NumberVal.ts +0 -16
  336. package/src/val/OpBaseVal.ts +4 -17
  337. package/src/val/PackFuncVal.ts +0 -63
  338. package/src/val/PathFuncVal.ts +0 -32
  339. package/src/val/PathVal.ts +0 -66
  340. package/src/val/PlaceVal.ts +0 -45
  341. package/src/val/PlusOpVal.ts +18 -75
  342. package/src/val/PrefFuncVal.ts +0 -1
  343. package/src/val/PrefVal.ts +0 -179
  344. package/src/val/RecurseVal.ts +0 -81
  345. package/src/val/RefVal.ts +1 -285
  346. package/src/val/ReferFuncVal.ts +0 -255
  347. package/src/val/ScalarKindVal.ts +0 -50
  348. package/src/val/ScalarVal.ts +0 -12
  349. package/src/val/StrFuncVal.ts +0 -44
  350. package/src/val/SuperFuncVal.ts +0 -42
  351. package/src/val/TopVal.ts +0 -1
  352. package/src/val/TranslateFuncVal.ts +132 -0
  353. package/src/val/UpperFuncVal.ts +12 -7
  354. package/src/val/Val.ts +3 -192
  355. package/src/val/VarVal.ts +0 -15
  356. package/src/val/arith.ts +0 -92
  357. package/src/val/caserange.ts +53 -0
  358. package/src/val/members.ts +0 -23
  359. package/src/val/numcmp.ts +1 -27
  360. package/src/val/numkind.ts +0 -149
  361. package/src/val/valutil.ts +0 -16
  362. package/src/vet.ts +209 -504
  363. package/src/view.ts +0 -507
  364. package/src/walk.ts +0 -41
  365. package/dist/std.d.ts +0 -3
  366. package/dist/std.js +0 -637
  367. package/dist/std.js.map +0 -1
  368. package/dist/val/FormFuncVal.js +0 -55
  369. package/dist/val/FormFuncVal.js.map +0 -1
  370. package/src/std.ts +0 -648
  371. package/src/val/FormFuncVal.ts +0 -119
package/src/trim.ts CHANGED
@@ -1,26 +1,6 @@
1
1
  /* Copyright (c) 2025 Richard Rodger, MIT License */
2
2
  import { includeOpts } from './utility'
3
3
 
4
- // The trim reporter (G3 phase 6,
5
- // docs/capability-review/g3-subsumption-evolution.md): report REDUNDANT
6
- // map entries — entries whose removal leaves the evaluated result
7
- // unchanged, the spread-implied case included — as paths. Report-only,
8
- // deliberately: canon discards comments and layout, so REWRITING the
9
- // file needs G7's format-preserving patch surface; trim ships as a
10
- // reporter here and becomes an editor there.
11
- //
12
- // The test is EVALUATE-AND-COMPARE: for each candidate entry, re-parse
13
- // the source, delete the entry from the parsed tree, evaluate, and
14
- // compare canons. This subsumes the design's spread case — an entry a
15
- // spread template re-supplies evaluates to the same canon without its
16
- // explicit spelling — and is honest about everything the fixpoint can
17
- // see (references, templates, duplicate-key merges), where a purely
18
- // structural test would guess. A removal that ERRORS is not redundant:
19
- // the entry is load-bearing.
20
- //
21
- // Parsed trees are single-use (docs/reference-api.md), so every probe
22
- // is its own parse: one evaluation per candidate plus one for the
23
- // baseline. A reporter can afford that; an editor loop belongs to G7.
24
4
 
25
5
  import { Aontu } from './aontu'
26
6
  import { failureFinding } from './vet'
@@ -34,12 +14,6 @@ export type TrimReport = {
34
14
  verdict: TrimVerdict
35
15
  redundant: string[]
36
16
 
37
- // WHY the run could not be made, in the same finding shape vet
38
- // reports in (the review's finding F). An `error` verdict used to
39
- // arrive with an empty report -- something is wrong with the
40
- // document, and nothing about what -- which is the one answer a
41
- // repair loop cannot act on. Present ONLY on an `error` verdict, so
42
- // a clean report stays exactly the two fields it always was.
43
17
  errors?: VetFinding[]
44
18
  }
45
19
 
@@ -47,14 +21,8 @@ export type TrimOptions = {
47
21
  // Where the document CAME FROM, so a relative `@"file"` load inside
48
22
  // it resolves from its own directory (vet's schemaPath precedent).
49
23
  path?: string
50
- // The include capability this document evaluates under (G5,
51
- // docs/trust.md). vet's precedent: the verb passes the profile the
52
- // caller asked for, and an absent option means today's default.
53
24
  trust?: TrustOptions
54
25
 
55
- // Extensions additionally read as text (the CLI's `--text-ext`).
56
- // Rides beside `trust` because it is the other half of what an
57
- // include may read.
58
26
  textExt?: string[]
59
27
  }
60
28
 
@@ -64,14 +32,6 @@ function pathText(path: string[]): string {
64
32
  }
65
33
 
66
34
 
67
- // Every (map, key) pair in a PARSED tree, parent-first. Candidates come
68
- // from the parse rather than the evaluation: an entry the fixpoint
69
- // erases or rewrites still has to be addressable for deletion. The
70
- // non-Val guard is for a bag's raw peg entries, which degenerate
71
- // parses can leave behind. Exported (with deleteAt and evalCanon) for
72
- // the direct unit tests (ADR-002, ts/test/coverage3.test.ts): the
73
- // defensive arms are unreachable through trimCheck, whose candidates
74
- // come from an identical parse.
75
35
  export function candidates(v: any, path: string[], out: string[][]): void {
76
36
  if (null == v || true !== v.isVal) {
77
37
  return
@@ -118,21 +78,12 @@ export function deleteAt(root: any, path: string[]): boolean {
118
78
  }
119
79
 
120
80
 
121
- // One evaluation: parse (deleting the entry at delPath, when given),
122
- // unify under collect, and answer the canon — or undefined when the
123
- // source does not stand up, which for the baseline is the caller's
124
- // error verdict and for a probe means "load-bearing".
125
81
  export function evalCanon(
126
82
  src: string, opts: TrimOptions, delPath?: string[],
127
83
  sink?: { ctx?: any, failed?: any }): string | undefined {
128
84
  const aontu = new Aontu(includeOpts(opts))
129
85
  const ctx = aontu.ctx({ collect: true })
130
86
  const parseOpts = null == opts.path ? undefined : { path: opts.path }
131
- // WHY the run failed, for the one caller that reports it. The
132
- // BASELINE run passes a sink and a probe does not: a probe's failure
133
- // means "load-bearing", which is an answer rather than a fault, and
134
- // reporting it would bury the one real finding under one entry's
135
- // worth of noise per candidate.
136
87
  const fail = (failed?: any): undefined => {
137
88
  if (null != sink) {
138
89
  sink.ctx = ctx
@@ -158,10 +109,6 @@ export function evalCanon(
158
109
  }
159
110
 
160
111
 
161
- // The whole reporter: the baseline canon, then one probe per candidate
162
- // entry, parent-first — and a child of a redundant parent is SKIPPED,
163
- // because "remove the whole entry" already covers it and reporting
164
- // both would tell the author to delete the same text twice.
165
112
  export function trimCheck(src: string, opts?: TrimOptions): TrimReport {
166
113
  const options = opts ?? {}
167
114
 
package/src/type.ts CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  import * as Fs from 'node:fs'
4
4
 
5
- // TODO: refactor these out
6
5
 
7
6
  import { Resolver } from '@tabnas/multisource'
8
7
 
@@ -13,35 +12,12 @@ import type { ValMark, ValSpec } from './val/Val'
13
12
  type FST = typeof Fs
14
13
 
15
14
 
16
-
17
- // The trust profile (G5, docs/trust.md): what an evaluation may read,
18
- // and how much work it may do. Trust is a property of the EVALUATION,
19
- // not the document -- a .aon file cannot request more capability -- and
20
- // the profile adds zero language syntax.
21
- //
22
- // The include capability:
23
- // 'none' @"..." is always denied
24
- // { mem: {...} } a virtual file set only; nothing else resolves
25
- // { root: '/dir' } real files, realpath-confined below root;
26
- // no package resolution
27
- // 'system' the full memory -> file -> package chain
28
- // (today's default, and the unconfined posture)
29
- //
30
- // Budgets are integer counts of engine events -- never wall-clock, which
31
- // would make identical inputs fail differently across machines (the
32
- // exact nondeterminism docs/trust.md forbids). The defaults are the
33
- // shared spec-visible constants pinned by test/spec/budget.tsv.
34
15
  type TrustInclude =
35
16
  | 'none'
36
17
  | 'system'
37
18
  | { mem: Record<string, string> }
38
19
  | { root: string }
39
20
 
40
- // Only the budgets BOTH ports can honour are profile surface: passes
41
- // and depth. The per-pair revisit bound (999) stays a TS-internal
42
- // constant — the Go dispatcher has no revisit counter (it is
43
- // depth-guarded), and a knob one port cannot implement would break the
44
- // parity contract (ADR-001) by construction.
45
21
  type TrustBudget = {
46
22
  passes?: number // fixpoint passes (default 9)
47
23
  depth?: number // structural recursion depth (default 1000)
@@ -53,21 +29,14 @@ type TrustOptions = {
53
29
  }
54
30
 
55
31
  type AontuOptions = {
56
- src?: string // Source text.
32
+ src?: string
57
33
  print?: number // Print debug verbosity
58
- resolver?: Resolver // Source resolver
34
+ resolver?: Resolver
59
35
  base?: string // Base path for resolver
60
36
  path?: string // Path of entry file
61
37
  debug?: boolean
62
38
  trace?: boolean
63
39
  fs?: FST
64
- // errfs READS FOR THE ERROR RENDERER ONLY, never for resolution.
65
- // A frame excerpts the file its arrow names, which means reading
66
- // that file -- but handing the same reader to `fs` would change
67
- // which leg the include RESOLVER takes (its file leg reads through
68
- // the host filesystem when one is given, so a package hit can
69
- // become a file hit), and a diagnostic must not move the boundary
70
- // it is describing.
71
40
  errfs?: FST
72
41
  deps?: any
73
42
  log?: any
@@ -77,19 +46,8 @@ type AontuOptions = {
77
46
  explain?: any[]
78
47
  trust?: TrustOptions // Trust profile (G5, docs/trust.md)
79
48
 
80
- // EXTENSIONS ADDITIONALLY READ AS TEXT, without their dots. `.txt`
81
- // is read as text with no option at all; this widens that set for a
82
- // host that keeps its prose in `.md`, its queries in `.sql`, or its
83
- // templates under some name only it knows. The file's bytes become
84
- // one string scalar -- no parser is chosen for it, which is what
85
- // makes widening the set safe to offer.
86
49
  textExt?: string[]
87
50
 
88
- // The staged-flip warning window (G5 phase 6, CLI only): under the
89
- // default 'system' capability the CLI supplies these, and the
90
- // resolver calls trustWarn for every resolution that escapes
91
- // trustWarnRoot or goes through package resolution — naming the flag
92
- // a future default will require. Not a stable embedding API.
93
51
  trustWarn?: (kind: 'escape' | 'pkg', path: string) => void
94
52
  trustWarnRoot?: string
95
53
  }
@@ -108,7 +66,6 @@ type ValMap = { [key: string]: Val }
108
66
  type ValList = Val[]
109
67
 
110
68
 
111
-
112
69
  type ErrContext = {
113
70
  src?: string,
114
71
  fs?: FST,
package/src/unify.ts CHANGED
@@ -29,36 +29,6 @@ import {
29
29
  } from './val/top'
30
30
 
31
31
 
32
- // The evaluation budgets live on the context (ctx.budget: passes,
33
- // revisits, depth), defaulted there to the shared spec-visible
34
- // constants test/spec/budget.tsv pins in both ports (9 / 999 / 1000)
35
- // and configurable through the trust profile (G5, docs/trust.md) —
36
- // deterministically: a budget is an integer count of engine events,
37
- // never wall-clock.
38
- //
39
- // Why the revisit default is 999: how many times one (Val, path) pair
40
- // may be re-unified within a single fixpoint pass before the evaluator
41
- // calls it non-convergence (`unify_cycle`). The old false positive here
42
- // -- a legal model with many sibling conjunct terms at one path, each
43
- // re-running the TOP self-unify -- is fixed by the per-pass memo below
44
- // (_tcc/_tpi); test/spec/budget.tsv drives 1200 sibling terms through
45
- // both engines as the regression guard.
46
- //
47
- // Why the depth default is 1000: the whole shared suite peaks at 603
48
- // (the deliberately extreme 1200-sibling-term fixture; ordinary
49
- // documents are two orders below), and V8 exhausts its call stack
50
- // somewhere past depth ~1500 in this evaluator. 1000 sits above every
51
- // real document and below the host limit, so the budget -- not the
52
- // host -- decides the verdict.
53
-
54
- // Charge a DIRECT `Val.unify` recursion to the same depth budget that
55
- // `unite` enforces. Function and operator arguments evaluate through
56
- // `arg.unify(top(), ...)` rather than through the dispatcher, so without
57
- // this the counter stays flat while the JavaScript stack keeps growing:
58
- // a 1500-deep `upper(upper(...))` resolved in TypeScript while Go — which
59
- // routes its arguments through the counted dispatcher — reported
60
- // `unify_cycle`. Returns the budget nil instead of running when the
61
- // budget is spent.
62
32
  const withDepth = (
63
33
  ctx: AontuContext, a: any, b: any, run: () => any
64
34
  ): any => {
@@ -78,27 +48,10 @@ const withDepth = (
78
48
  // Vals should only have to unify downwards (in .unify) over Vals they understand.
79
49
  // and for complex Vals, TOP, which means self unify if not yet done
80
50
  const unite = (ctx: AontuContext, a: any, b: any, whence: string) => {
81
- // Fast paths that don't recurse and so don't need cycle-detection:
82
- // short-circuit before the saw-key build and seen-map lookup (which
83
- // together cost ~2.5µs per call). Only return early when the result
84
- // is already `done` — a non-done result would need the trailing
85
- // top() unify below.
86
- //
87
- // A6a: same ref, already done
88
- // A6b: different ref but same id + both done
89
- // P1: exact-equal scalars that are already done (14% of calls
90
- // in foo-sdk, ~100% with a.done=true)
91
51
  if (a !== undefined && a !== null) {
92
52
  if (a === b) {
93
53
  if (a.done) return a
94
54
  }
95
- // ... and NOT on an instrumented run (G7 provenance). Both arms
96
- // below answer with one operand and never reach the recorder at
97
- // the tail, so an equal pair — two positions of one entity that
98
- // agree, a clone meeting its source — contributed silently and
99
- // `why` named one site where the Go port, whose recorder wraps the
100
- // whole dispatcher, named both. Instrumented runs pay the slow
101
- // path knowingly; uninstrumented ones pay one undefined check.
102
55
  else if (b !== undefined && b !== null && undefined === ctx.prov) {
103
56
  if (a.done && b.done) {
104
57
  if (a.id === b.id) {
@@ -113,19 +66,7 @@ const unite = (ctx: AontuContext, a: any, b: any, whence: string) => {
113
66
  && !a.isMap && !a.isList
114
67
  && !a.isConjunct && !a.isDisjunct
115
68
  && !a.isRef && !a.isPref && !a.isFunc && !a.isExpect
116
- // NOT two TOPs: every top has the same (absent) peg, so
117
- // this path would treat any two as the same value and
118
- // return one of them whole — dropping a rider the other
119
- // carries. The slow path answers the same thing for two
120
- // plain tops, so nothing is lost by declining the shortcut.
121
69
  && !a.isTop && !b.isTop
122
- // NOT two rel residuals (RELATIONS P1) for the same
123
- // reason: a settled rel is DONE with an absent peg, so
124
- // any two matched here — dropping one side's type and
125
- // held constraints. RelVal.unify merges them instead.
126
- // NOT two graph atoms (P2) either: acyclic() and
127
- // inverse(x) share a constructor and an absent peg
128
- // without being the same declaration.
129
70
  && !a.isRel && !a.isGraphAtom && !a.isRecurse) {
130
71
  // The deprecation record survives the fast path too (G3):
131
72
  // `deprecate(5) & 5` short-circuits here.
@@ -138,6 +79,17 @@ const unite = (ctx: AontuContext, a: any, b: any, whence: string) => {
138
79
  }
139
80
  }
140
81
 
82
+ // ABSENCE IS THE UNIT OF THE MEET (ADR-034). The dispatch below is
83
+ // the LEFT operand's, so `&` commutes only if it is answered here.
84
+ if (null != a && null != b) {
85
+ if (true === a.isAbsent) {
86
+ return a.unify(b, ctx)
87
+ }
88
+ if (true === b.isAbsent) {
89
+ return b.unify(a, ctx)
90
+ }
91
+ }
92
+
141
93
  const te = ctx.explain && explainOpen(ctx, ctx.explain, 'unite', a, b)
142
94
 
143
95
  let out = a
@@ -155,16 +107,9 @@ const unite = (ctx: AontuContext, a: any, b: any, whence: string) => {
155
107
  // See for example PrefVal peg.id equality inspection.
156
108
  const sawCount = ctx.seen[saw] ?? 0
157
109
  if (ctx.budget.depth <= ctx._depth.n) {
158
- // Structural recursion budget. Without it, deep nesting exhausts the
159
- // V8 call stack and the catch-all below reports a RangeError as
160
- // `internal` — a verdict that depends on the host's stack size
161
- // rather than on the document, which is exactly what the
162
- // determinism clause forbids (docs/trust.md). Tripping here instead
163
- // makes it a stated budget error, like the pass budget.
164
110
  out = makeNilErr(ctx, 'unify_cycle', a, b)
165
111
  }
166
112
  else if (ctx.budget.revisits < sawCount) {
167
- // console.log('SAW', sawCount, saw, a?.id, a?.canon, b?.id, b?.canon, ctx.cc)
168
113
  out = makeNilErr(ctx, 'unify_cycle', a, b)
169
114
  }
170
115
  else {
@@ -174,18 +119,6 @@ const unite = (ctx: AontuContext, a: any, b: any, whence: string) => {
174
119
  try {
175
120
  let unified = false
176
121
 
177
- // Dispatch ladder. Structure note:
178
- // - `a == null` is degenerate (shouldn't happen in practice:
179
- // the top-level call seeds with a real Val). Kept for safety.
180
- // - TOP is the unit element: unifying with it returns the
181
- // other side. Handle both sides.
182
- // - Otherwise route by Val type. Complex Vals (Conjunct,
183
- // Disjunct, Ref, Pref, Func, Expect) have their own unify
184
- // that knows how to absorb the peer; prefer `a.unify` when
185
- // `a` is complex, else `b.unify` when `b` is complex. If
186
- // neither is complex and it's not a plain-scalar match, fall
187
- // through to the generic `a.unify` (concrete Val classes
188
- // each handle their own peer case).
189
122
  if (a == null) {
190
123
  out = b
191
124
  why = 'b'
@@ -219,18 +152,9 @@ const unite = (ctx: AontuContext, a: any, b: any, whence: string) => {
219
152
  || b.isVar
220
153
  || b.isFunc
221
154
  || b.isExpect
222
- // The refer residual (G4 phase 2) DRIVES, like the other
223
- // residuals here: its peer is a plain string, which knows
224
- // nothing about entity addresses, so letting the string drive
225
- // dropped the address and left the constraint standing.
226
155
  || b.isRefer
227
- // An operator holding a HOLE (G8 phase 3) drives for the same
228
- // reason: its peer is what FILLS it, and a scalar asked to
229
- // unify with `_ + 2` sees an operator rather than a hole and
230
- // refuses it on kind. Narrow to placeheld operators on
231
- // purpose -- every other operator meets its peer the way it
232
- // always has, through the conjunct fold that drives it.
233
- || (b.isOp && hasPlace(b))
156
+ // An op DRIVES while an operand has not decided (ADR-037).
157
+ || (b.isOp && (hasPlace(b) || b.holdsStaged))
234
158
  // A graph atom DRIVES (RELATIONS P2): its peer is the value
235
159
  // it rides beside -- a container, a rel, a scalar -- and none
236
160
  // of them know the atom; the atom knows to residuate.
@@ -243,10 +167,6 @@ const unite = (ctx: AontuContext, a: any, b: any, whence: string) => {
243
167
  unified = true
244
168
  why = 'bv'
245
169
  }
246
- // Exactly equal scalars (not caught by early fast-path — e.g.
247
- // because a or b isn't .done yet). Rel residuals are excluded
248
- // exactly as in the fast path: their pegs are equally absent
249
- // without the values being the same relation.
250
170
  else if (a.constructor === b.constructor && a.peg === b.peg
251
171
  && !a.isRel && !a.isGraphAtom && !a.isRecurse) {
252
172
  out = update(a, b)
@@ -263,18 +183,7 @@ const unite = (ctx: AontuContext, a: any, b: any, whence: string) => {
263
183
  why += 'N'
264
184
  }
265
185
 
266
- // Any non-done top-level result self-unifies with TOP to ensure
267
- // its children finish converging. Skipped when `unified` is true
268
- // because the branch that set `out = X.unify(Y, ctx)` already
269
- // ran that Val's own unify logic.
270
186
  if (!out.done && !unified) {
271
- // Once per pass per (Val, path): within a single fixpoint pass
272
- // nothing external to the subtree changes, so repeating the TOP
273
- // self-unify — which conjunct folds otherwise trigger once per
274
- // fold term — is pure re-work, and on large models (hundreds of
275
- // sibling terms) the repeats trip the MAXCYCLE guard as a false
276
- // positive. The path is part of the key: a shared Val can
277
- // resolve path-dependent content differently per location.
278
187
  if (undefined !== ctx.cc
279
188
  && (out as any)._tcc === ctx.cc && (out as any)._tpi === ctx.pathidx) {
280
189
  why += 't'
@@ -290,12 +199,6 @@ const unite = (ctx: AontuContext, a: any, b: any, whence: string) => {
290
199
  }
291
200
  }
292
201
  catch (err: any) {
293
- // This catch-all converts an unexpected exception into an 'internal'
294
- // Nil so one bad node doesn't crash a whole unify. To avoid fully
295
- // masking regressions, preserve the original error message (and a
296
- // RangeError flag — i.e. stack overflow from runaway recursion) on
297
- // the Nil's details so it surfaces in the formatted error rather
298
- // than vanishing. See err.ts (descErr) for how details render.
299
202
  out = makeNilErr(ctx, 'internal', a, b, undefined, {
300
203
  error: String(err?.message ?? err),
301
204
  ...(err instanceof RangeError ? { overflow: true } : {}),
@@ -308,20 +211,10 @@ const unite = (ctx: AontuContext, a: any, b: any, whence: string) => {
308
211
 
309
212
  ctx.explain && explainClose(te, out)
310
213
 
311
- // The provenance record (G7 phase 3), at the one place every meet
312
- // passes through — the same reason the deprecation rider below lives
313
- // here. Off by default: an uninstrumented run pays this one property
314
- // load, and an instrumented one pays site materialisation knowingly.
315
214
  if (undefined !== ctx.prov) {
316
215
  ctx.prov.record(ctx.path, a, b, out)
317
216
  }
318
217
 
319
- // The deprecation record survives EVERY meet (G3 phase 4): the
320
- // boolean marks have their own sweeps (ConjunctVal, the bag walks),
321
- // but a record lost in one meet shape is a use the tooling never
322
- // warns about, so it rides here, at the one place all meets pass
323
- // through. First record wins; TOP and nil stay clean (TOP is the
324
- // unit, and an error needs no deprecation).
325
218
  if (null != out && true === (out as any).isVal &&
326
219
  !out.isTop && !out.isNil && null == out.deprecation) {
327
220
  const dep = (null != a ? a.deprecation : undefined) ??
@@ -331,12 +224,6 @@ const unite = (ctx: AontuContext, a: any, b: any, whence: string) => {
331
224
  }
332
225
  }
333
226
 
334
- // THE RENDER RIDERS SURVIVE EVERY MEET (RENDER.0.md P7), and here
335
- // for the deprecation record's reason: a reference resolves by
336
- // MEETING its target with the peer at the referring position, and an
337
- // emitted piece meets the vocabulary's alternative before the fold
338
- // ever sees it, so a record lost in one meet shape is a line the
339
- // trace cannot name. Both are absent unless the run is instrumented.
340
227
  if (undefined !== ctx.reads &&
341
228
  null != out && true === (out as any).isVal && !out.isTop && !out.isNil) {
342
229
  riders(a, b, out)
@@ -346,18 +233,6 @@ const unite = (ctx: AontuContext, a: any, b: any, whence: string) => {
346
233
  }
347
234
 
348
235
 
349
- // The two P7 riders, carried from the operands to the result: the read
350
- // address a value was found at, and the dispatch that emitted it.
351
- // First record wins, as the deprecation record's does. Reached only
352
- // from an instrumented run (AontuContext.reads), so an ordinary meet
353
- // pays the one property load its call site makes and nothing else.
354
- //
355
- // AN OPERAND MAY BE ABSENT and reading through it is not a decision:
356
- // `unite` is called with no peer wherever a bag holds a key its peer
357
- // does not, and `Object(undefined)` is an empty object, so both riders
358
- // are read the same way whether the operand is there or not. Written
359
- // with a test first, that test had an arm no instrumented document
360
- // reached -- true of the reading, not of the engine.
361
236
  function riders(a: any, b: any, to: any): void {
362
237
  const av = Object(a)
363
238
  const bv = Object(b)
@@ -377,7 +252,6 @@ function riders(a: any, b: any, to: any): void {
377
252
 
378
253
 
379
254
  function update(x: Val, _y: Val) {
380
- // TODO: update x with y.site
381
255
  return x
382
256
  }
383
257
 
@@ -406,26 +280,6 @@ function residuePaths(v: Val, max: number): string[] {
406
280
  }
407
281
 
408
282
 
409
- // THE TYPE FLOW, APPLIED (G4 phase 2). `refer(t)` unifies `t` INTO the
410
- // node it addresses, which is a write at a position the meet is not
411
- // currently at -- the one non-local effect in the evaluator.
412
- //
413
- // It cannot be only a write made during the pass. A pass BUILDS a new
414
- // tree from the old one, and `ctx.root` during pass N is pass N-1's
415
- // result; a subtree rebuilt by pass N (which is exactly what happens
416
- // when the link sits inside its own target, or when two nodes link at
417
- // each other) drops a write made into the previous one. So each flow is
418
- // also RECORDED, keyed by the target's path, and re-applied to the
419
- // pass's own result here.
420
- //
421
- // Keyed by PATH, so there is no registry of names to collide in
422
- // (ADR-014) -- the key is the position the address resolved to, and
423
- // re-uniting the same type at the same position is idempotent, which is
424
- // what makes replaying every recorded flow every pass correct rather
425
- // than merely cheap.
426
- //
427
- // The pass loop is its only caller; it is EXPORTED for the test that
428
- // pins the unresolved-path guard below (see there).
429
283
  function applyFlows(ctx: AontuContext, root: Val): Val {
430
284
  const flows: Map<string, Val> | undefined = (ctx as any).referflows
431
285
  // NOTHING TO APPLY is the common case -- a document with no links
@@ -433,32 +287,8 @@ function applyFlows(ctx: AontuContext, root: Val): Val {
433
287
  if (null == flows || 0 === flows.size) {
434
288
  return root
435
289
  }
436
- // Sorted, so two flows landing at overlapping positions arrive in the
437
- // same order in both ports.
438
290
  for (const key of [...flows.keys()].sort()) {
439
291
  const path = key.split('\x00')
440
- // The SHARED resolver, the one `refer` itself uses: a second
441
- // descent written here would be a second answer to "what does this
442
- // path name", and the two would drift (the Go twin calls the same
443
- // findAt, arm for arm -- ADR-001).
444
- //
445
- // A RECORDED PATH THAT NO LONGER RESOLVES is skipped rather than
446
- // refused: the record outliving its position is a question about
447
- // the tree, and the link that named it answers it
448
- // (test/spec/refer.tsv, `flow-target-moved-away`).
449
- //
450
- // NO DOCUMENT REACHES IT: a record is written only for a path that
451
- // HAD resolved, and unification never takes a node back out of the
452
- // tree — `move` copies and hides its source rather than removing
453
- // it, which is the one rearrangement that looked like it would
454
- // (probed in both ports: the flow still resolves on every pass,
455
- // `flow-lands-then-its-parent-moves`). The guard is the contract
456
- // for a rearrangement that does, and it is pinned by a direct call
457
- // (`apply-flows-skips-a-record-that-stops-resolving` in
458
- // ts/test/coverage3.test.ts) rather than by an ignore marker: node's
459
- // `coverage ignore` drops LINES, and the gate reads BRANCH records,
460
- // which survive it. The Go twin in go/unify.go can use the marker
461
- // because that gate counts statements.
462
292
  const found = findAt(root, path)
463
293
  if (undefined === found) {
464
294
  continue
@@ -517,8 +347,6 @@ class Unify {
517
347
  })
518
348
  }
519
349
 
520
- // TODO: messy
521
- // uctx.seterr(this.err)
522
350
  uctx.err = this.err
523
351
  uctx.explain = this.explain
524
352
 
@@ -526,12 +354,6 @@ class Unify {
526
354
  // keyed by ref canon + source site, shared across all passes.
527
355
  ; (uctx as any).snapmap = new Map()
528
356
 
529
- // The RECORDED TYPE FLOWS (G4 phase 2): target path -> the type
530
- // `refer(t)` unified into it, replayed onto each pass's result by
531
- // applyFlows. Seeded HERE, on the unify root, for the reason the
532
- // snapshot map above is: a descended context is Object.create'd
533
- // from its parent, so a `??=` in the descendant would make its
534
- // OWN map and the root would never see what was recorded.
535
357
  ; (uctx as any).referflows = new Map()
536
358
 
537
359
  // The re-entrancy guard for those flows: the set of target paths
@@ -547,71 +369,23 @@ class Unify {
547
369
  let lastCanon: string | undefined = undefined
548
370
  let settle = false
549
371
  for (; this.cc < maxcc && DONE !== res.dc; this.cc++) {
550
- // console.log('CC', this.cc, res.canon)
551
372
  uctx.cc = this.cc
552
373
  uctx.seen = {}
553
374
 
554
- // THE STAGING RULE (G8 phase 0,
555
- // docs/capability-review/g8-generation.md), stated once, here,
556
- // for every value whose answer depends on WHERE IT IS. Such a
557
- // value residuates while the model is still moving and fires on
558
- // the first pass whose input is IDENTICAL to the previous
559
- // pass's input: nothing moved, so nothing will move it again,
560
- // and the position it reports is the position it ends at.
561
- //
562
- // Why the whole model and not the value's own path. A spread, a
563
- // reference or a `move` can place a value under a path it has
564
- // already been driven at and THEN change what encloses it --
565
- // `move` hides its source one pass AFTER it copies it, and a
566
- // `key()` that answered on the strength of its path alone would
567
- // answer for the ghost. Stability of the model is the only
568
- // signal that says every such rearrangement is finished.
569
375
  uctx.settle = settle
570
376
 
571
- // Snapshot BEFORE the final pass (the loop condition has
572
- // already established the tree is not done), so exhaustion can
573
- // tell "still refining" from "stable residue" below. Taken at
574
- // the final pass's ENTRY rather than the previous pass's exit
575
- // — the same value when the budget allows two passes, and the
576
- // only possible value when the trust profile sets passes to 1,
577
- // where the old placement (cc === maxcc - 2, never true) made
578
- // exhaustion silent, exactly the truncation docs/trust.md
579
- // forbids. `lastCanon` IS that entry canon whenever a previous
580
- // pass rendered one, so this costs nothing extra.
581
377
  if (this.cc === maxcc - 1) {
582
378
  prevCanon = lastCanon ?? res.canon
583
379
  }
584
380
 
585
381
  res = unite(te ? uctx.clone({ explain: ec(te, 'run') }) : uctx, res, top(), 'unify')
586
382
 
587
- // MULTI-ERROR COLLECTION (G2 phase 6): the pass loop CONTINUES
588
- // past an erroring pass, so independent failures a later pass
589
- // would reach are collected in the same run — the break that
590
- // stood here made every multi-error report truncated at the
591
- // first erroring pass.
592
- //
593
- // What controls the cascade the design feared: a nil is
594
- // ABSORBING (unite's isNil arms return the existing nil, no new
595
- // error), so one failure stays ONE NilVal however many later
596
- // meets touch it — a reference resolving to a failed target
597
- // takes the same nil identity, which is exactly what lets the
598
- // report layer dedup by identity. The probes that established
599
- // this (fan-in refs, spread templates, disjunct trials, nested
600
- // conjuncts) are pinned as vet.tsv's multi-* rows in both
601
- // ports.
602
383
 
603
384
  // The recorded type flows, re-applied to the tree THIS pass
604
385
  // built: a pass rebuilds subtrees, and a flow written into the
605
386
  // previous pass's tree does not survive that.
606
387
  res = applyFlows(uctx, res)
607
388
 
608
- // The staging signal for the NEXT pass, rendered here rather
609
- // than at the top of the loop so a model that is FINISHED is
610
- // never rendered at all: canon walks references, and the only
611
- // trees that close a cycle are hand-built ones (the pass loop
612
- // is what a test drives them through), which converge in one
613
- // pass and must not be walked to decide a question that no
614
- // longer arises.
615
389
  if (DONE !== res.dc) {
616
390
  const nowCanon = res.canon
617
391
  settle = undefined !== lastCanon && lastCanon === nowCanon
@@ -621,16 +395,6 @@ class Unify {
621
395
  uctx = uctx.clone({ root: res })
622
396
  }
623
397
 
624
- // The pass budget is spent AND the final pass still made
625
- // progress: the model was cut off while converging, and no other
626
- // error explains why. Silent truncation would surface later as
627
- // ordinary incompleteness, so exhaustion is a semantic error of
628
- // its own (class budget, docs/trust.md clause 2) -- retrying with
629
- // a larger budget is a valid response to THIS code and useless
630
- // for path_cycle or no_path. A STABLE residue (the final pass
631
- // changed nothing -- e.g. a stuck `1+true`) is not a budget
632
- // failure: it is ordinary incompleteness and stays silent here,
633
- // surfacing at generate exactly as before.
634
398
  if (maxcc <= this.cc && DONE !== res.dc && 0 === uctx.err.length
635
399
  && undefined !== prevCanon && prevCanon !== res.canon) {
636
400
  makeNilErr(uctx, 'budget_passes', undefined, undefined, 'resolve', {
@@ -653,8 +417,6 @@ class Unify {
653
417
  } /* node:coverage ignore next 10 */
654
418
 
655
419
 
656
-
657
-
658
420
  export {
659
421
  Unify,
660
422
  unite,