aontu 0.52.1 → 0.54.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 (310) hide show
  1. package/README.md +88 -0
  2. package/bin/aontu-mcp.js +4 -0
  3. package/dist/agentsmd.d.ts +16 -0
  4. package/dist/agentsmd.js +107 -0
  5. package/dist/agentsmd.js.map +1 -0
  6. package/dist/aontu.d.ts +15 -3
  7. package/dist/aontu.js +126 -5
  8. package/dist/aontu.js.map +1 -1
  9. package/dist/cli.d.ts +45 -1
  10. package/dist/cli.js +2845 -69
  11. package/dist/cli.js.map +1 -1
  12. package/dist/ctx.d.ts +18 -0
  13. package/dist/ctx.js +44 -0
  14. package/dist/ctx.js.map +1 -1
  15. package/dist/diff.d.ts +22 -0
  16. package/dist/diff.js +141 -0
  17. package/dist/diff.js.map +1 -0
  18. package/dist/err.d.ts +3 -1
  19. package/dist/err.js +45 -8
  20. package/dist/err.js.map +1 -1
  21. package/dist/graph.d.ts +13 -0
  22. package/dist/graph.js +110 -0
  23. package/dist/graph.js.map +1 -0
  24. package/dist/hcanon.d.ts +3 -0
  25. package/dist/hcanon.js +145 -0
  26. package/dist/hcanon.js.map +1 -0
  27. package/dist/hints.js +235 -8
  28. package/dist/hints.js.map +1 -1
  29. package/dist/jsonschema.d.ts +20 -0
  30. package/dist/jsonschema.js +425 -0
  31. package/dist/jsonschema.js.map +1 -0
  32. package/dist/lang.js +955 -110
  33. package/dist/lang.js.map +1 -1
  34. package/dist/lsp.d.ts +9 -2
  35. package/dist/lsp.js +343 -48
  36. package/dist/lsp.js.map +1 -1
  37. package/dist/mcp-server.d.ts +20 -0
  38. package/dist/mcp-server.js +147 -0
  39. package/dist/mcp-server.js.map +1 -0
  40. package/dist/mcp.d.ts +42 -0
  41. package/dist/mcp.js +941 -0
  42. package/dist/mcp.js.map +1 -0
  43. package/dist/mod-tool.d.ts +58 -0
  44. package/dist/mod-tool.js +532 -0
  45. package/dist/mod-tool.js.map +1 -0
  46. package/dist/mod.d.ts +35 -0
  47. package/dist/mod.js +345 -0
  48. package/dist/mod.js.map +1 -0
  49. package/dist/patch.d.ts +49 -0
  50. package/dist/patch.js +506 -0
  51. package/dist/patch.js.map +1 -0
  52. package/dist/provenance.d.ts +41 -0
  53. package/dist/provenance.js +336 -0
  54. package/dist/provenance.js.map +1 -0
  55. package/dist/query.d.ts +27 -0
  56. package/dist/query.js +294 -0
  57. package/dist/query.js.map +1 -0
  58. package/dist/reach.d.ts +15 -0
  59. package/dist/reach.js +168 -0
  60. package/dist/reach.js.map +1 -0
  61. package/dist/relation.d.ts +23 -0
  62. package/dist/relation.js +230 -0
  63. package/dist/relation.js.map +1 -0
  64. package/dist/report-sarif.d.ts +14 -0
  65. package/dist/report-sarif.js +102 -0
  66. package/dist/report-sarif.js.map +1 -0
  67. package/dist/sig.d.ts +25 -0
  68. package/dist/sig.js +277 -0
  69. package/dist/sig.js.map +1 -0
  70. package/dist/sigdecl.d.ts +2 -0
  71. package/dist/sigdecl.js +11 -0
  72. package/dist/sigdecl.js.map +1 -0
  73. package/dist/siggate.d.ts +4 -0
  74. package/dist/siggate.js +90 -0
  75. package/dist/siggate.js.map +1 -0
  76. package/dist/site.d.ts +4 -0
  77. package/dist/site.js +31 -0
  78. package/dist/site.js.map +1 -1
  79. package/dist/std.d.ts +1 -0
  80. package/dist/std.js +129 -0
  81. package/dist/std.js.map +1 -0
  82. package/dist/subsume.d.ts +39 -0
  83. package/dist/subsume.js +573 -0
  84. package/dist/subsume.js.map +1 -0
  85. package/dist/trim.d.ts +19 -0
  86. package/dist/trim.js +155 -0
  87. package/dist/trim.js.map +1 -0
  88. package/dist/tsconfig.tsbuildinfo +1 -1
  89. package/dist/type.d.ts +17 -1
  90. package/dist/type.js.map +1 -1
  91. package/dist/unify.d.ts +2 -1
  92. package/dist/unify.js +234 -38
  93. package/dist/unify.js.map +1 -1
  94. package/dist/utility.d.ts +8 -1
  95. package/dist/utility.js +68 -1
  96. package/dist/utility.js.map +1 -1
  97. package/dist/val/AggFuncVal.d.ts +44 -0
  98. package/dist/val/AggFuncVal.js +364 -0
  99. package/dist/val/AggFuncVal.js.map +1 -0
  100. package/dist/val/ArithFuncVal.d.ts +31 -0
  101. package/dist/val/ArithFuncVal.js +62 -0
  102. package/dist/val/ArithFuncVal.js.map +1 -0
  103. package/dist/val/BagVal.d.ts +7 -0
  104. package/dist/val/BagVal.js +150 -11
  105. package/dist/val/BagVal.js.map +1 -1
  106. package/dist/val/CloseFuncVal.js +9 -1
  107. package/dist/val/CloseFuncVal.js.map +1 -1
  108. package/dist/val/ConjunctVal.d.ts +1 -1
  109. package/dist/val/ConjunctVal.js +19 -0
  110. package/dist/val/ConjunctVal.js.map +1 -1
  111. package/dist/val/ConstraintVal.d.ts +7 -1
  112. package/dist/val/ConstraintVal.js +523 -45
  113. package/dist/val/ConstraintVal.js.map +1 -1
  114. package/dist/val/ContainerKindVal.d.ts +35 -0
  115. package/dist/val/ContainerKindVal.js +99 -0
  116. package/dist/val/ContainerKindVal.js.map +1 -0
  117. package/dist/val/CopyFuncVal.d.ts +1 -2
  118. package/dist/val/CopyFuncVal.js.map +1 -1
  119. package/dist/val/Decimal.d.ts +1 -0
  120. package/dist/val/Decimal.js +13 -0
  121. package/dist/val/Decimal.js.map +1 -1
  122. package/dist/val/DeprecateFuncVal.d.ts +11 -0
  123. package/dist/val/DeprecateFuncVal.js +47 -0
  124. package/dist/val/DeprecateFuncVal.js.map +1 -0
  125. package/dist/val/DisjunctVal.d.ts +1 -2
  126. package/dist/val/DisjunctVal.js +269 -53
  127. package/dist/val/DisjunctVal.js.map +1 -1
  128. package/dist/val/EachFuncVal.d.ts +15 -0
  129. package/dist/val/EachFuncVal.js +75 -0
  130. package/dist/val/EachFuncVal.js.map +1 -0
  131. package/dist/val/ExpectVal.js +62 -4
  132. package/dist/val/ExpectVal.js.map +1 -1
  133. package/dist/val/FeatureVal.js +1 -1
  134. package/dist/val/FeatureVal.js.map +1 -1
  135. package/dist/val/FilterFuncVal.d.ts +15 -0
  136. package/dist/val/FilterFuncVal.js +91 -0
  137. package/dist/val/FilterFuncVal.js.map +1 -0
  138. package/dist/val/FuncBaseVal.d.ts +7 -1
  139. package/dist/val/FuncBaseVal.js +183 -2
  140. package/dist/val/FuncBaseVal.js.map +1 -1
  141. package/dist/val/GraphAtomVal.d.ts +39 -0
  142. package/dist/val/GraphAtomVal.js +184 -0
  143. package/dist/val/GraphAtomVal.js.map +1 -0
  144. package/dist/val/HideFuncVal.js.map +1 -1
  145. package/dist/val/JunctionVal.js +24 -1
  146. package/dist/val/JunctionVal.js.map +1 -1
  147. package/dist/val/KeyFuncVal.d.ts +1 -1
  148. package/dist/val/KeyFuncVal.js +38 -30
  149. package/dist/val/KeyFuncVal.js.map +1 -1
  150. package/dist/val/ListVal.js +94 -14
  151. package/dist/val/ListVal.js.map +1 -1
  152. package/dist/val/LowerFuncVal.js.map +1 -1
  153. package/dist/val/MapVal.d.ts +1 -0
  154. package/dist/val/MapVal.js +146 -14
  155. package/dist/val/MapVal.js.map +1 -1
  156. package/dist/val/MatchFuncVal.d.ts +15 -0
  157. package/dist/val/MatchFuncVal.js +107 -0
  158. package/dist/val/MatchFuncVal.js.map +1 -0
  159. package/dist/val/MoveFuncVal.js.map +1 -1
  160. package/dist/val/NilVal.js +24 -0
  161. package/dist/val/NilVal.js.map +1 -1
  162. package/dist/val/OpBaseVal.d.ts +1 -1
  163. package/dist/val/OpBaseVal.js +19 -1
  164. package/dist/val/OpBaseVal.js.map +1 -1
  165. package/dist/val/OpenFuncVal.js +4 -1
  166. package/dist/val/OpenFuncVal.js.map +1 -1
  167. package/dist/val/PackFuncVal.d.ts +15 -0
  168. package/dist/val/PackFuncVal.js +108 -0
  169. package/dist/val/PackFuncVal.js.map +1 -0
  170. package/dist/val/PathFuncVal.d.ts +2 -2
  171. package/dist/val/PathFuncVal.js +75 -16
  172. package/dist/val/PathFuncVal.js.map +1 -1
  173. package/dist/val/PathVal.d.ts +25 -0
  174. package/dist/val/PathVal.js +150 -0
  175. package/dist/val/PathVal.js.map +1 -0
  176. package/dist/val/PlaceVal.d.ts +13 -0
  177. package/dist/val/PlaceVal.js +131 -0
  178. package/dist/val/PlaceVal.js.map +1 -0
  179. package/dist/val/PlusOpVal.d.ts +2 -1
  180. package/dist/val/PlusOpVal.js +61 -37
  181. package/dist/val/PlusOpVal.js.map +1 -1
  182. package/dist/val/PrefFuncVal.js.map +1 -1
  183. package/dist/val/PrefVal.d.ts +4 -2
  184. package/dist/val/PrefVal.js +223 -41
  185. package/dist/val/PrefVal.js.map +1 -1
  186. package/dist/val/RecurseVal.d.ts +19 -0
  187. package/dist/val/RecurseVal.js +217 -0
  188. package/dist/val/RecurseVal.js.map +1 -0
  189. package/dist/val/RefVal.d.ts +3 -2
  190. package/dist/val/RefVal.js +181 -66
  191. package/dist/val/RefVal.js.map +1 -1
  192. package/dist/val/ReferFuncVal.d.ts +59 -0
  193. package/dist/val/ReferFuncVal.js +604 -0
  194. package/dist/val/ReferFuncVal.js.map +1 -0
  195. package/dist/val/ScalarKindVal.d.ts +4 -3
  196. package/dist/val/ScalarKindVal.js +12 -12
  197. package/dist/val/ScalarKindVal.js.map +1 -1
  198. package/dist/val/SuperFuncVal.d.ts +4 -2
  199. package/dist/val/SuperFuncVal.js +118 -14
  200. package/dist/val/SuperFuncVal.js.map +1 -1
  201. package/dist/val/TopVal.d.ts +1 -1
  202. package/dist/val/TopVal.js.map +1 -1
  203. package/dist/val/TypeFuncVal.js.map +1 -1
  204. package/dist/val/UpperFuncVal.js.map +1 -1
  205. package/dist/val/Val.d.ts +7 -1
  206. package/dist/val/Val.js +170 -2
  207. package/dist/val/Val.js.map +1 -1
  208. package/dist/val/VarVal.js.map +1 -1
  209. package/dist/val/arith.d.ts +6 -0
  210. package/dist/val/arith.js +173 -0
  211. package/dist/val/arith.js.map +1 -0
  212. package/dist/vet.d.ts +45 -0
  213. package/dist/vet.js +802 -0
  214. package/dist/vet.js.map +1 -0
  215. package/dist/view.d.ts +85 -0
  216. package/dist/view.js +1948 -0
  217. package/dist/view.js.map +1 -0
  218. package/dist/walk.d.ts +2 -0
  219. package/dist/walk.js +91 -0
  220. package/dist/walk.js.map +1 -0
  221. package/grammar/aontu.gbnf +138 -0
  222. package/grammar/aontu.lark +118 -0
  223. package/grammar/aontu.tmLanguage.json +184 -0
  224. package/package.json +30 -8
  225. package/skill/SKILL.md +37 -0
  226. package/skill/error-codes.md +62 -0
  227. package/skill/examples.md +99 -0
  228. package/skill/grammar-card.md +56 -0
  229. package/src/agentsmd.ts +135 -0
  230. package/src/aontu.ts +166 -5
  231. package/src/cli.ts +3324 -72
  232. package/src/ctx.ts +93 -1
  233. package/src/diff.ts +198 -0
  234. package/src/err.ts +50 -8
  235. package/src/graph.ts +185 -0
  236. package/src/hcanon.ts +167 -0
  237. package/src/hints.ts +291 -8
  238. package/src/jsonschema.ts +552 -0
  239. package/src/lang.ts +1049 -110
  240. package/src/lsp.ts +351 -49
  241. package/src/mcp-server.ts +187 -0
  242. package/src/mcp.ts +1130 -0
  243. package/src/mod-tool.ts +718 -0
  244. package/src/mod.ts +453 -0
  245. package/src/patch.ts +628 -0
  246. package/src/provenance.ts +437 -0
  247. package/src/query.ts +381 -0
  248. package/src/reach.ts +213 -0
  249. package/src/relation.ts +298 -0
  250. package/src/report-sarif.ts +137 -0
  251. package/src/sig.ts +345 -0
  252. package/src/sigdecl.ts +11 -0
  253. package/src/siggate.ts +144 -0
  254. package/src/site.ts +36 -1
  255. package/src/std.ts +131 -0
  256. package/src/subsume.ts +739 -0
  257. package/src/trim.ts +195 -0
  258. package/src/tsconfig.json +10 -4
  259. package/src/type.ts +51 -2
  260. package/src/unify.ts +253 -38
  261. package/src/utility.ts +79 -1
  262. package/src/val/AggFuncVal.ts +546 -0
  263. package/src/val/ArithFuncVal.ts +108 -0
  264. package/src/val/BagVal.ts +158 -12
  265. package/src/val/CloseFuncVal.ts +9 -1
  266. package/src/val/ConjunctVal.ts +20 -0
  267. package/src/val/ConstraintVal.ts +576 -48
  268. package/src/val/ContainerKindVal.ts +158 -0
  269. package/src/val/CopyFuncVal.ts +0 -1
  270. package/src/val/Decimal.ts +15 -0
  271. package/src/val/DeprecateFuncVal.ts +84 -0
  272. package/src/val/DisjunctVal.ts +282 -59
  273. package/src/val/EachFuncVal.ts +133 -0
  274. package/src/val/ExpectVal.ts +65 -8
  275. package/src/val/FeatureVal.ts +1 -1
  276. package/src/val/FilterFuncVal.ts +154 -0
  277. package/src/val/FuncBaseVal.ts +206 -2
  278. package/src/val/GraphAtomVal.ts +264 -0
  279. package/src/val/HideFuncVal.ts +0 -2
  280. package/src/val/JunctionVal.ts +24 -1
  281. package/src/val/KeyFuncVal.ts +39 -35
  282. package/src/val/ListVal.ts +101 -15
  283. package/src/val/LowerFuncVal.ts +0 -1
  284. package/src/val/MapVal.ts +153 -14
  285. package/src/val/MatchFuncVal.ts +176 -0
  286. package/src/val/MoveFuncVal.ts +0 -2
  287. package/src/val/NilVal.ts +25 -0
  288. package/src/val/OpBaseVal.ts +20 -1
  289. package/src/val/OpenFuncVal.ts +4 -2
  290. package/src/val/PackFuncVal.ts +175 -0
  291. package/src/val/PathFuncVal.ts +107 -20
  292. package/src/val/PathVal.ts +221 -0
  293. package/src/val/PlaceVal.ts +193 -0
  294. package/src/val/PlusOpVal.ts +67 -39
  295. package/src/val/PrefFuncVal.ts +0 -1
  296. package/src/val/PrefVal.ts +251 -60
  297. package/src/val/RecurseVal.ts +285 -0
  298. package/src/val/RefVal.ts +183 -78
  299. package/src/val/ReferFuncVal.ts +732 -0
  300. package/src/val/ScalarKindVal.ts +12 -13
  301. package/src/val/SuperFuncVal.ts +137 -13
  302. package/src/val/TopVal.ts +1 -2
  303. package/src/val/TypeFuncVal.ts +0 -2
  304. package/src/val/UpperFuncVal.ts +0 -1
  305. package/src/val/Val.ts +216 -4
  306. package/src/val/VarVal.ts +0 -1
  307. package/src/val/arith.ts +319 -0
  308. package/src/vet.ts +1025 -0
  309. package/src/view.ts +2563 -0
  310. package/src/walk.ts +99 -0
@@ -0,0 +1,264 @@
1
+ /* Copyright (c) 2025 Richard Rodger, MIT License */
2
+
3
+ // THE GRAPH ATOMS (RELATIONS.0.md §3.3): `acyclic()` and
4
+ // `inverse(name)`, conjoined at the same field as the `rel()` they
5
+ // govern. Their model is the sizing atoms -- a property that cannot be
6
+ // decided while information can still arrive is HELD during
7
+ // unification and DECIDED at generation, where no more can.
8
+ //
9
+ // During unification they are lattice-inert: both properties are
10
+ // global and non-monotone (one more edge can make an acyclic graph
11
+ // cyclic), and the lattice guarantee -- more information never
12
+ // falsifies what has been observed -- forbids a constraint that could
13
+ // answer true and then false. So the atoms only RESIDUATE: they ride
14
+ // the field through meets, dedup additively, appear in canon and reach
15
+ // the `aon1-` hash, and REGISTER the declaration on the context. The
16
+ // predicate they govern is the key they sit on, evaluation-global,
17
+ // additive across declarations.
18
+ //
19
+ // The verdict lands at generation (relationVerdict,
20
+ // ts/src/relation.ts) and is reported identically by the `relations`
21
+ // verb -- one decision, two surfaces.
22
+
23
+ import type {
24
+ Val,
25
+ ValSpec,
26
+ } from '../type'
27
+
28
+ import {
29
+ DONE,
30
+ } from '../type'
31
+
32
+ import {
33
+ AontuContext,
34
+ } from '../ctx'
35
+
36
+ import { makeNilErr } from '../err'
37
+
38
+ import { FuncBaseVal } from './FuncBaseVal'
39
+ import { FeatureVal } from './FeatureVal'
40
+ import { unite } from '../unify'
41
+ import { propagateMarks } from '../utility'
42
+
43
+
44
+ // The declarations one evaluation accumulates: predicate -> what its
45
+ // atoms said. Additive, exactly as two statements of one map are. The
46
+ // map lives on the CONTEXT (created in the constructor, like the
47
+ // _depth box), so every clone shares one registry.
48
+ export type RelDecl = {
49
+ acyclic?: boolean
50
+ inverses: Set<string>
51
+ }
52
+
53
+ export function relDecls(ctx: any): Map<string, RelDecl> {
54
+ return ctx._reldecls
55
+ }
56
+
57
+
58
+ class GraphAtomVal extends FeatureVal {
59
+ isGraphAtom = true
60
+ isGenable = true
61
+ // AFTER rel() (45000): the atoms say nothing about the value.
62
+ cjo = 46000
63
+
64
+ akind: 'acyclic' | 'inverse'
65
+ invname?: string
66
+ // The value the atom rides on -- the sizing-constraint shape: the
67
+ // atom ABSORBS its fold neighbours (the rel, the container, another
68
+ // atom) and carries them, so the fold's pairwise walk still merges
69
+ // the value across it. Absent until the atom meets one.
70
+ held?: Val
71
+
72
+ constructor(spec: ValSpec, ctx?: AontuContext) {
73
+ super(spec, ctx)
74
+ this.akind = (spec as any).akind ?? 'acyclic'
75
+ this.invname = (spec as any).invname
76
+ this.held = (spec as any).held
77
+ // A settled residual, like an unmet rel(): the bare atom is its
78
+ // own value, and a type() body carrying one must settle. Holding
79
+ // an unsettled value, it is exactly as done as the value.
80
+ this.dc = undefined === this.held || true === this.held.done
81
+ ? DONE : 0
82
+ }
83
+
84
+ clone(ctx: AontuContext, spec?: ValSpec): Val {
85
+ const out: any = super.clone(ctx, spec)
86
+ out.akind = this.akind
87
+ out.invname = this.invname
88
+ out.held = this.held
89
+ out.dc = this.dc
90
+ return out
91
+ }
92
+
93
+ // A rebuilt atom around a new held, at this atom's position.
94
+ private carry(ctx: AontuContext, held: Val): Val {
95
+ const out: any = new GraphAtomVal(
96
+ { akind: this.akind, invname: this.invname, held } as any, ctx)
97
+ propagateMarks(this, out)
98
+ out.site = this.site
99
+ out.path = this.path
100
+ return out
101
+ }
102
+
103
+ // The predicate is the key the atom sits on -- and a predicate is a
104
+ // D-1 NAME, by exactly fieldkey's rule: an atom landed anywhere
105
+ // else declares nothing. Registration is idempotent (the
106
+ // declaration set is a set) and happens at every drive, so
107
+ // whichever pass first sees the atom at its landed position records
108
+ // it.
109
+ register(ctx: AontuContext): void {
110
+ const seg = this.path[this.path.length - 1]
111
+ if ('string' !== typeof seg || !GRAPH_ATOM_NAME.test(seg)) {
112
+ return
113
+ }
114
+ const decls = relDecls(ctx)
115
+ let d = decls.get(seg)
116
+ if (undefined === d) {
117
+ d = { inverses: new Set() }
118
+ decls.set(seg, d)
119
+ }
120
+ if ('acyclic' === this.akind) {
121
+ d.acyclic = true
122
+ }
123
+ else if (undefined !== this.invname) {
124
+ d.inverses.add(this.invname)
125
+ }
126
+ }
127
+
128
+ unify(peer: Val, ctx: AontuContext): Val {
129
+ const p: any = peer
130
+ this.register(ctx)
131
+
132
+ // The self-drive: unite's tail calls unify(top) directly on any
133
+ // not-done result, and the held is what still has work to do.
134
+ // (A null/nil peer never arrives -- unite's ladder absorbs both.)
135
+ if (null == peer || true === p.isTop) {
136
+ if (undefined === this.held) {
137
+ return this
138
+ }
139
+ if (true === this.held.done) {
140
+ // Doneness is monotone, so recording it in place is safe --
141
+ // and without it the bag walk keeps asking and generation
142
+ // refuses a finished value.
143
+ this.dc = DONE
144
+ return this
145
+ }
146
+ // The self-drive refines IN PLACE (the MapVal top-peer
147
+ // pattern): a fresh atom per pass changes object identity, so
148
+ // spread apply-once stamps and the entity merge's fast paths
149
+ // stop holding, and the enclosing bags re-open every pass --
150
+ // the service catalog never converged.
151
+ const held = unite(ctx, this.held, undefined, 'atom-drive')
152
+ if (true === held.isNil) {
153
+ return held
154
+ }
155
+ this.held = held
156
+ if (true === held.done) {
157
+ this.dc = DONE
158
+ }
159
+ return this
160
+ }
161
+
162
+ // The SAME declaration twice is one declaration; their helds
163
+ // merge.
164
+ if (true === p.isGraphAtom &&
165
+ p.akind === this.akind && p.invname === this.invname) {
166
+ const held = undefined === this.held ? p.held
167
+ : undefined === p.held ? this.held
168
+ : unite(ctx, this.held, p.held, 'atom-dup')
169
+ if (undefined !== held && true === held.isNil) {
170
+ return held
171
+ }
172
+ return undefined === held ? this : this.carry(ctx, held)
173
+ }
174
+
175
+ // Anything else -- the rel, the container, a different atom -- is
176
+ // ABSORBED: the atom carries the value and the fold's pairwise
177
+ // walk merges across it.
178
+ const held = undefined === this.held ? peer
179
+ : unite(ctx, this.held, peer, 'atom-held')
180
+ return true === held.isNil ? held : this.carry(ctx, held)
181
+ }
182
+
183
+ get canon(): string {
184
+ const own = 'acyclic' === this.akind
185
+ ? 'acyclic()'
186
+ : 'inverse(' + JSON.stringify(this.invname) + ')'
187
+ return undefined === this.held ? own : this.held.canon + '&' + own
188
+ }
189
+
190
+ gen(ctx: AontuContext) {
191
+ // The atom is transparent at generation -- its verdict is global
192
+ // (relationVerdict), never a value at this field -- and a BARE
193
+ // atom is silent, exactly as an unmet rel() is.
194
+ return undefined === this.held ? undefined : this.held.gen(ctx)
195
+ }
196
+ }
197
+
198
+
199
+ // D-1 (docs/design/RELATIONS.0.md): the name grammar shared by entity
200
+ // names, edge predicates and inverse names.
201
+ const GRAPH_ATOM_NAME = /^[_a-zA-Z][-_a-zA-Z0-9]*$/
202
+
203
+
204
+ class AcyclicFuncVal extends FuncBaseVal {
205
+ isAcyclicFunc = true
206
+
207
+ constructor(spec: ValSpec, ctx?: AontuContext) {
208
+ super(spec, ctx)
209
+ }
210
+
211
+ make(_ctx: AontuContext, spec: ValSpec): Val {
212
+ return new AcyclicFuncVal(spec)
213
+ }
214
+
215
+ funcname() {
216
+ return 'acyclic'
217
+ }
218
+
219
+ resolve(ctx: AontuContext, _args: Val[]) {
220
+ const out: any = new GraphAtomVal({ akind: 'acyclic' } as any, ctx)
221
+ out.site = this.site
222
+ out.path = this.path
223
+ return out
224
+ }
225
+ }
226
+
227
+
228
+ class InverseFuncVal extends FuncBaseVal {
229
+ isInverseFunc = true
230
+
231
+ constructor(spec: ValSpec, ctx?: AontuContext) {
232
+ super(spec, ctx)
233
+ }
234
+
235
+ make(_ctx: AontuContext, spec: ValSpec): Val {
236
+ return new InverseFuncVal(spec)
237
+ }
238
+
239
+ funcname() {
240
+ return 'inverse'
241
+ }
242
+
243
+ resolve(ctx: AontuContext, args: Val[]) {
244
+ const a: any = args[0]
245
+ // The mirroring predicate is a NAME -- D-1, spelled bare or
246
+ // quoted. A relation is a vocabulary term, not an address.
247
+ if (true !== a?.isScalar || 'string' !== typeof a.peg
248
+ || !GRAPH_ATOM_NAME.test(a.peg)) {
249
+ return makeNilErr(ctx, 'inverse_name', this, undefined, 'inverse')
250
+ }
251
+ const out: any = new GraphAtomVal(
252
+ { akind: 'inverse', invname: a.peg } as any, ctx)
253
+ out.site = this.site
254
+ out.path = this.path
255
+ return out
256
+ }
257
+ } /* node:coverage ignore next 7 */
258
+
259
+
260
+ export {
261
+ GraphAtomVal,
262
+ AcyclicFuncVal,
263
+ InverseFuncVal,
264
+ }
@@ -15,8 +15,6 @@ import { makeNilErr } from '../err'
15
15
 
16
16
  import {
17
17
  walk,
18
- explainOpen,
19
- explainClose,
20
18
  } from '../utility'
21
19
 
22
20
 
@@ -33,7 +33,30 @@ abstract class JunctionVal extends FeatureVal {
33
33
 
34
34
  clone(ctx: AontuContext, spec?: ValSpec): Val {
35
35
  let out = (super.clone(ctx, spec) as JunctionVal)
36
- out.peg = this.peg.map((entry: Val) => entry.clone(ctx, spec?.mark ? { mark: spec.mark } : {}))
36
+ // A JUNCTION'S MEMBERS SIT AT THE JUNCTION'S OWN POSITION. That is
37
+ // the rule `repathInstance` (Val.ts) states for the instance walk
38
+ // -- a conjunct's members occupy the conjunct's position, which is
39
+ // what `A & B` means -- and it holds for every clone, not only for
40
+ // marked ones.
41
+ //
42
+ // Val.clone's ctx cut cannot derive it: MapVal.clone hands a child
43
+ // its path through the SPEC rather than by descending the ctx, so
44
+ // a member left to the cut takes the DRIVING context's path -- the
45
+ // map's -- and loses the field key it sits under. A conjunct
46
+ // member reached through a reference into a position at least as
47
+ // deep as its definition then carried the entity's path, and every
48
+ // reader of `Val.path` was told the wrong position: a rel()-minted
49
+ // link took the ENTITY's key as its predicate, so `inverse(n)`
50
+ // looked for a mirror under a relation nobody declared and
51
+ // reported a written mirror missing.
52
+ //
53
+ // The instantiation flag still descends with the mark (ADR-005).
54
+ // Go states the same invariant directly (go/clone.go, cloneAt), so
55
+ // this restores parity rather than inventing a behaviour.
56
+ const childspec: any = spec?.mark || spec?.dup ?
57
+ { mark: spec?.mark, dup: spec?.dup, path: out.path }
58
+ : { path: out.path }
59
+ out.peg = this.peg.map((entry: Val) => entry.clone(ctx, childspec))
37
60
  return out
38
61
  }
39
62
 
@@ -12,7 +12,6 @@ import {
12
12
  } from '../ctx'
13
13
 
14
14
  import { StringVal } from '../val/StringVal'
15
- import { ConjunctVal } from '../val/ConjunctVal'
16
15
 
17
16
 
18
17
 
@@ -41,39 +40,13 @@ class KeyFuncVal extends FuncBaseVal {
41
40
  }
42
41
 
43
42
 
44
- unify(peer: Val, ctx: AontuContext): Val {
45
- // TODO: this delay makes keys in spreads and refs work, but it is a hack - find a better way.
46
- let out: Val = this
47
-
48
- if (ctx.cc < 3) {
49
- this.notdone()
50
-
51
- if (peer.isTop || (peer.id === this.id)) {
52
- // TODO: clone needed to avoid triggering unify_cycle - find a better way
53
- out = this.clone(ctx)
54
- }
55
- else if (peer.isNil) {
56
- out = peer
57
- }
58
- else {
59
- if (
60
- peer.isKeyFunc
61
- && peer.path.join('.') === this.path.join('.')
62
- && peer.peg?.[0]?.peg === this.peg?.[0]?.peg
63
- ) {
64
- out = this
65
- }
66
- else {
67
- out = new ConjunctVal({ peg: [this, peer] }, ctx)
68
- }
69
- }
70
- }
71
- else {
72
- out = super.unify(peer, ctx)
73
- }
74
-
75
- return out
76
- }
43
+ // `key()` is the first value to take THE STAGING RULE (G8 phase 0,
44
+ // see AontuContext.settle): its answer is a segment of its own path,
45
+ // so it must not answer while a spread, a reference or a `move` can
46
+ // still move it. It residuates until the model stops changing, and
47
+ // fires on the settle pass. The residuation itself is FuncBaseVal's,
48
+ // shared with the generation combinators.
49
+ staged = true
77
50
 
78
51
 
79
52
  resolve(ctx: AontuContext, _args: Val[]) {
@@ -113,7 +86,38 @@ class KeyFuncVal extends FuncBaseVal {
113
86
  }
114
87
  }
115
88
 
116
- const key = this.path[this.path.length - (1 + move)] ?? ''
89
+ // THE PATH IS THE ONE IT IS BEING DRIVEN AT, not the one it
90
+ // remembers. `this.path` is a cache that the residuation clone
91
+ // refreshes each pass, and it is right for a key() the bag walk
92
+ // reaches directly -- but a key() nested inside a function or
93
+ // operator ARGUMENT is never reached that way: it is driven by its
94
+ // enclosing call, which re-paths nothing, so it kept the position
95
+ // the SOURCE TEXT put it at. Inside a template that is fatal: the
96
+ // source position of `&: {k: "x" + key()}` (or of `pack`'s
97
+ // template) is the template, not any of the destinations, and the
98
+ // parse-time path of a function argument is not a document
99
+ // position at all.
100
+ // A stored path is only usable if it IS one: a path segment that is
101
+ // not a key is not a position, and the parse-time path of a value
102
+ // written inside a function ARGUMENT carries exactly that -- the
103
+ // argument has no key, so its segment is not a string. Those values
104
+ // are also the ones the bag walk never re-paths (a call re-paths
105
+ // nothing it holds), which is why the stored path stays wrong
106
+ // forever rather than being refreshed on the next pass. For them
107
+ // the driving context is the only truth. For everything else the
108
+ // stored path stays authoritative, because a TRANSPLANTED value
109
+ // (move(), a shared clone) must answer for where it was put, not
110
+ // for whichever driver happened to reach it first.
111
+ let positioned = true
112
+ for (const seg of this.path) {
113
+ if ('string' !== typeof seg) {
114
+ positioned = false
115
+ break
116
+ }
117
+ }
118
+
119
+ const here = positioned ? this.path : ctx.path
120
+ const key = here[here.length - (1 + move)] ?? ''
117
121
  // console.log('KEY', this.path, move, key)
118
122
 
119
123
  out = new StringVal({ peg: key })
@@ -17,6 +17,7 @@ import { unite } from '../unify'
17
17
 
18
18
  import {
19
19
  propagateMarks,
20
+ canonRiders,
20
21
  explainOpen,
21
22
  ec,
22
23
  explainClose,
@@ -32,6 +33,8 @@ import {
32
33
  import { ConjunctVal } from './ConjunctVal'
33
34
  import { NilVal } from './NilVal'
34
35
  import { BagVal } from './BagVal'
36
+ import { repathInstance, spreadId } from './Val'
37
+ import { markSpread } from '../provenance'
35
38
 
36
39
 
37
40
  class ListVal extends BagVal {
@@ -55,7 +58,10 @@ class ListVal extends BagVal {
55
58
  if (spread) {
56
59
  if ('&' === spread.o) {
57
60
 
58
- // TODO: handle existing spread!
61
+ // Multiple same-level spreads conjoin; an unequal spread from
62
+ // another statement meets this one in unify's combination
63
+ // below (see the MapVal constructor note — the combined
64
+ // template is stateless, BUGS.md §6-§7).
59
65
  this.spread.cj =
60
66
  Array.isArray(spread.v) ?
61
67
  1 < spread.v.length ?
@@ -73,6 +79,12 @@ class ListVal extends BagVal {
73
79
  // NOTE: order of keys is not preserved!
74
80
  // not possible in any case - consider {a,b} unify {b,a}
75
81
  unify(peer: Val, ctx: AontuContext): Val {
82
+ // A rel() peer drives: the relation constraint rewrites this list
83
+ // leaf by leaf (RELATIONS.0.md §3.2); see the twin arm in MapVal.
84
+ if (true === (peer as any)?.isRel) {
85
+ return (peer as any).unify(this, ctx)
86
+ }
87
+
76
88
  const TOP = top()
77
89
  peer = peer ?? TOP
78
90
 
@@ -86,6 +98,19 @@ class ListVal extends BagVal {
86
98
  return peer.unify(this, ctx)
87
99
  }
88
100
 
101
+ // A DISJUNCT ALTERNATIVE MATCHES ITS OWN LENGTH (BUGS.md §52
102
+ // regime 4, the X-C3 adjudication): in a trial, a literal list
103
+ // with no spread admits only a peer list of the same length -- a
104
+ // spread makes it variadic. Outside trials the ordinary
105
+ // elementwise merge stands (two statements of one list are one
106
+ // list), so `[] | [&: T]` stops admitting every list through the
107
+ // empty arm while `a: [] a: [1]` still merges.
108
+ if (true === ctx._trialMode && true === (peer as any).isList
109
+ && null == this.spread.cj && null == (peer as any).spread.cj
110
+ && this.peg.length !== (peer as any).peg.length) {
111
+ return makeNilErr(ctx, 'list_length', this, peer)
112
+ }
113
+
89
114
  const te = ctx.explain && explainOpen(ctx, ctx.explain, 'List', this, peer)
90
115
  let done: boolean = true
91
116
  let exit = false
@@ -124,21 +149,63 @@ class ListVal extends BagVal {
124
149
  // Always unify children first
125
150
  for (let key in this.peg) {
126
151
  const keyctx = ctx.descend(key)
127
- const key_spread_cj = spread_cj.spreadClone(keyctx)
128
152
  const child = this.peg[key]
129
153
 
130
154
  propagateMarks(this, child)
131
155
 
132
- // child is non-nullish: propagateMarks above dereferences it.
133
- out.peg[key] =
134
- child.isNil ? child :
135
- key_spread_cj.isNil ? key_spread_cj :
136
- key_spread_cj.isTop && child.done ? child :
137
- child.isTop && key_spread_cj.done ? key_spread_cj :
138
- unite(te ? keyctx.clone({ explain: ec(te, 'PEG:' + key) }) : keyctx,
139
- child, key_spread_cj, 'list-own')
156
+ // APPLIED ONCE PER ELEMENT, the guard MapVal has carried since
157
+ // the spread was written: an element that already holds this
158
+ // template's contribution is progressed by self-unification
159
+ // instead of having the template met into it a second time.
160
+ // Re-applying is the identity for a template that has already
161
+ // RESOLVED, which is why the missing guard went unnoticed here
162
+ // — but a template that residuates (`&: {k: key(1)}`, G8 phase
163
+ // 0) is not yet a value to be idempotent about, so each pass
164
+ // conjoined another copy and the element's canon DOUBLED per
165
+ // pass. The old `ctx.cc < 3` key delay hid it by ending the
166
+ // growth at three passes; the staging rule waits for the model
167
+ // to settle, and a model whose canon doubles every pass never
168
+ // does.
169
+ let oval: Val
170
+ if (!spread_cj.isTop
171
+ && (child as any)._spr === spreadId(spread_cj)) {
172
+ oval = child.done ? child :
173
+ unite(te ? keyctx.clone({ explain: ec(te, 'PEG:' + key) }) : keyctx,
174
+ child, TOP, 'list-own')
175
+ ; (oval as any)._spr = spreadId(spread_cj)
176
+ }
177
+ else {
178
+ const key_spread_cj = spread_cj.spreadClone(keyctx)
179
+ // The spread mark the provenance recorder reads (G7 phase 3),
180
+ // as in MapVal: this is where a template becomes a per-element
181
+ // contribution. Instrumented runs only.
182
+ if (undefined !== keyctx.prov) {
183
+ markSpread(key_spread_cj)
184
+ }
140
185
 
141
- done = (done && DONE === out.peg[key].dc)
186
+ // child is non-nullish: propagateMarks above dereferences it.
187
+ oval =
188
+ child.isNil ? child :
189
+ key_spread_cj.isNil ? key_spread_cj :
190
+ // The no-op meet is SKIPPED on the normal path (it is the
191
+ // identity) but TAKEN while recording: a value written once
192
+ // and never met is still a contribution the author wants
193
+ // pointed at, and the Go port's unite sees that meet (G7
194
+ // phase 4). Instrumented runs pay knowingly.
195
+ key_spread_cj.isTop && child.done && undefined === keyctx.prov
196
+ ? child :
197
+ child.isTop && key_spread_cj.done ? key_spread_cj :
198
+ unite(te ? keyctx.clone({ explain: ec(te, 'PEG:' + key) }) : keyctx,
199
+ child, key_spread_cj, 'list-own')
200
+
201
+ if (!spread_cj.isTop && !oval.isNil) {
202
+ ; (oval as any)._spr = spreadId(spread_cj)
203
+ }
204
+ }
205
+
206
+ out.peg[key] = oval
207
+
208
+ done = (done && DONE === oval.dc)
142
209
  }
143
210
 
144
211
  const allowedKeys: string[] = this.closed ? Object.keys(this.peg) : []
@@ -171,6 +238,9 @@ class ListVal extends BagVal {
171
238
 
172
239
  if (this.spread.cj) {
173
240
  let key_spread_cj = spread_cj.spreadClone(peerctx)
241
+ if (undefined !== peerctx.prov) {
242
+ markSpread(key_spread_cj)
243
+ }
174
244
 
175
245
  oval = out.peg[peerkey] =
176
246
  unite(te ? peerctx.clone({ explain: ec(te, 'PSP:' + peerkey) }) : peerctx,
@@ -182,6 +252,12 @@ class ListVal extends BagVal {
182
252
  done = (done && DONE === oval.dc)
183
253
  }
184
254
  }
255
+ else if (true === (peer as any).isContainerKind) {
256
+ // The container KIND delegates to its own arm, exactly as a
257
+ // scalar delegates to a ScalarKindVal peer (MapVal has the
258
+ // same arm).
259
+ out = peer.unify(this, ctx) as any
260
+ }
185
261
  else if (!peer.isTop) {
186
262
  out = makeNilErr(ctx, 'list', this, peer)
187
263
  }
@@ -226,7 +302,11 @@ class ListVal extends BagVal {
226
302
  }
227
303
 
228
304
  if (!allScalarKind) {
229
- return this.clone(ctx)
305
+ // A full instance (`dup`, ADR-005), paths normalised to the
306
+ // destination: see Val.spreadClone and repathInstance.
307
+ const out = this.clone(ctx, { dup: true })
308
+ repathInstance(out, out.path)
309
+ return out
230
310
  }
231
311
 
232
312
  let out = (super.clone(ctx) as ListVal)
@@ -249,12 +329,16 @@ class ListVal extends BagVal {
249
329
 
250
330
  clone(ctx: AontuContext, spec?: ValSpec): Val {
251
331
  let out = (super.clone(ctx, spec) as ListVal)
332
+ // The instantiation flag descends with the mark (ADR-005): a
333
+ // template's elements are part of the instance.
334
+ const childspec = spec?.mark || spec?.dup ?
335
+ { mark: spec?.mark, dup: spec?.dup } : {}
252
336
  for (let entry of Object.entries(this.peg)) {
253
337
  out.peg[entry[0]] =
254
- (entry[1] as any)?.isVal ? (entry[1] as Val).clone(ctx, spec?.mark ? { mark: spec.mark } : {}) : entry[1]
338
+ (entry[1] as any)?.isVal ? (entry[1] as Val).clone(ctx, childspec) : entry[1]
255
339
  }
256
340
  if (this.spread.cj) {
257
- out.spread.cj = this.spread.cj.clone(ctx, spec?.mark ? { mark: spec.mark } : {})
341
+ out.spread.cj = this.spread.cj.clone(ctx, childspec)
258
342
  }
259
343
 
260
344
  out.closed = this.closed
@@ -280,7 +364,9 @@ class ListVal extends BagVal {
280
364
  // key. The Go port's ListVal.Canon has no such arm either, and the
281
365
  // two canons must agree -- a canon is round-trippable, and a marker
282
366
  // on an element the grammar cannot produce would not reparse.
283
- keys.map(k => this.peg[k].canon).join(',') +
367
+ // canonRiders, not .canon: a deprecated element renders
368
+ // back as its `deprecate(x, m)` call, reparseably (G3).
369
+ keys.map(k => canonRiders(this.peg[k])).join(',') +
284
370
  ']'
285
371
  }
286
372
  } /* node:coverage ignore next 8 */
@@ -13,7 +13,6 @@ import {
13
13
  import { makeNilErr } from '../err'
14
14
 
15
15
 
16
- import { NilVal } from '../val/NilVal'
17
16
  import { ScalarKindVal } from '../val/ScalarKindVal'
18
17
  import { makeScalarLike } from '../val/valutil'
19
18
  import { Decimal } from '../val/Decimal'