aontu 0.72.0 → 0.74.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.
- package/README.md +6 -6
- package/dist/agentsmd.js +2 -2
- package/dist/agentsmd.js.map +1 -1
- package/dist/aontu.d.ts +1 -1
- package/dist/aontu.js +1 -1
- package/dist/cli.js +27 -18
- package/dist/cli.js.map +1 -1
- package/dist/err.js +1 -1
- package/dist/err.js.map +1 -1
- package/dist/format.js +14 -16
- package/dist/format.js.map +1 -1
- package/dist/helpdoc.js +11 -11
- package/dist/helpdoc.js.map +1 -1
- package/dist/hints.js +6 -6
- package/dist/hints.js.map +1 -1
- package/dist/lang.js +5 -6
- package/dist/lang.js.map +1 -1
- package/dist/lsp.d.ts +1 -1
- package/dist/mod.d.ts +2 -2
- package/dist/mod.js +3 -3
- package/dist/mod.js.map +1 -1
- package/dist/pkg-net.js +30 -16
- package/dist/pkg-net.js.map +1 -1
- package/dist/pkg.d.ts +1 -1
- package/dist/pkg.js +6 -6
- package/dist/pkg.js.map +1 -1
- package/dist/view.js +3 -3
- package/dist/view.js.map +1 -1
- package/grammar/aontu.tmLanguage.json +2 -3
- package/package.json +17 -17
- package/skill/SKILL.md +7 -7
- package/skill/error-codes.md +3 -3
- package/skill/examples.md +5 -5
- package/skill/grammar-card.md +1 -1
- package/skill/init/check.sh +6 -6
- package/skill/init/{data.aon → data.aontu} +1 -1
- package/skill/init/{model.aon → model.aontu} +1 -1
- package/skill/tasks.md +21 -21
- package/src/agentsmd.ts +2 -2
- package/src/aontu.ts +1 -1
- package/src/cli.ts +28 -18
- package/src/err.ts +1 -1
- package/src/format.ts +16 -16
- package/src/helpdoc.ts +11 -11
- package/src/hints.ts +6 -6
- package/src/lang.ts +5 -6
- package/src/mod.ts +3 -3
- package/src/pkg-net.ts +32 -16
- package/src/pkg.ts +6 -6
- package/src/view.ts +4 -4
package/skill/error-codes.md
CHANGED
|
@@ -40,7 +40,7 @@ field of a `--format json` report.
|
|
|
40
40
|
## The repair loop
|
|
41
41
|
|
|
42
42
|
```
|
|
43
|
-
aontu vet schema.
|
|
43
|
+
aontu vet schema.aontu mine.aontu --format json
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
The exit code branches for you: `0` valid, `1` invalid (fix the
|
|
@@ -61,14 +61,14 @@ registry code; a **dynamic** code (`func:upper`, `op[+]`) is registered
|
|
|
61
61
|
through its prefix, and only `explain` falls back to the prefix's text,
|
|
62
62
|
so such a finding carries no `hint`.
|
|
63
63
|
|
|
64
|
-
For a conflict, `aontu model why <path> mine.
|
|
64
|
+
For a conflict, `aontu model why <path> mine.aontu` lists every contribution
|
|
65
65
|
to that path with its role and source line, which turns "these
|
|
66
66
|
disagree" into "these two lines disagree".
|
|
67
67
|
|
|
68
68
|
Then fix it:
|
|
69
69
|
|
|
70
70
|
```
|
|
71
|
-
aontu model set '$.replicas=5' --entry schema.
|
|
71
|
+
aontu model set '$.replicas=5' --entry schema.aontu --overlay mine.aontu --in-place
|
|
72
72
|
```
|
|
73
73
|
|
|
74
74
|
`--in-place` rewrites the pinned literal **where it was written**, so
|
package/skill/examples.md
CHANGED
|
@@ -28,7 +28,7 @@ service: {
|
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
Nothing generates yet — this is a truth, not a value. `aontu vet
|
|
31
|
-
service.
|
|
31
|
+
service.aontu deploy.aontu` says whether a deployment satisfies it.
|
|
32
32
|
|
|
33
33
|
## 3. Say what it SHOULD be
|
|
34
34
|
|
|
@@ -79,11 +79,11 @@ A port of `0` is now an error with a path, not a runtime surprise.
|
|
|
79
79
|
## 6. Layer it
|
|
80
80
|
|
|
81
81
|
```
|
|
82
|
-
# base.
|
|
82
|
+
# base.aontu
|
|
83
83
|
service: { image: string, replicas: *1 | integer }
|
|
84
84
|
|
|
85
|
-
# prod.
|
|
86
|
-
@"./base.
|
|
85
|
+
# prod.aontu
|
|
86
|
+
@"./base.aontu"
|
|
87
87
|
service: { image: "auth:v2.3", replicas: 5 }
|
|
88
88
|
```
|
|
89
89
|
|
|
@@ -91,7 +91,7 @@ Unification is order-independent: `base & prod` is `prod & base`. To
|
|
|
91
91
|
change a value without editing the file, append to an overlay:
|
|
92
92
|
|
|
93
93
|
```
|
|
94
|
-
aontu model set '$.service.replicas=7' --entry prod.
|
|
94
|
+
aontu model set '$.service.replicas=7' --entry prod.aontu --overlay local.aontu
|
|
95
95
|
```
|
|
96
96
|
|
|
97
97
|
If the value is PINNED rather than open, that command refuses and
|
package/skill/grammar-card.md
CHANGED
|
@@ -54,6 +54,6 @@ ranges meet to their overlap.
|
|
|
54
54
|
|
|
55
55
|
## Files
|
|
56
56
|
|
|
57
|
-
`@"./other.
|
|
57
|
+
`@"./other.aontu"` includes another document — it unifies in, it does not
|
|
58
58
|
concatenate. (A constrained decoder is not given this: generated
|
|
59
59
|
documents describe values, they do not load files.)
|
package/skill/init/check.sh
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env sh
|
|
2
2
|
# check.sh --- the four questions to ask of a model. Run it after
|
|
3
|
-
# every edit to model.
|
|
3
|
+
# every edit to model.aontu or data.aontu.
|
|
4
4
|
#
|
|
5
5
|
# `aontu help tasks` maps a job to a verb; `aontu explain <code>` says
|
|
6
6
|
# what a refusal means; `aontu help language` is the whole grammar on
|
|
@@ -13,16 +13,16 @@ cd "$(dirname "$0")"
|
|
|
13
13
|
# 1. Does the data satisfy the truth -- and did the check examine
|
|
14
14
|
# anything? --strict-coverage exits 1 on a check that constrained no
|
|
15
15
|
# value, which is the failure a passing gate hides.
|
|
16
|
-
$AONTU vet --strict-coverage model.
|
|
16
|
+
$AONTU vet --strict-coverage model.aontu data.aontu
|
|
17
17
|
|
|
18
18
|
# 2. What does it say at a path?
|
|
19
|
-
$AONTU model get '$.entity.planet.table' data.
|
|
19
|
+
$AONTU model get '$.entity.planet.table' data.aontu
|
|
20
20
|
|
|
21
21
|
# 3. Why does it say that? Every contribution, with the line it is on.
|
|
22
|
-
$AONTU model why '$.entity.planet.table' data.
|
|
22
|
+
$AONTU model why '$.entity.planet.table' data.aontu
|
|
23
23
|
|
|
24
24
|
# 4. A pin for the truth: it survives reformatting and moves on any
|
|
25
25
|
# change of meaning.
|
|
26
|
-
$AONTU hash model.
|
|
26
|
+
$AONTU hash model.aontu
|
|
27
27
|
|
|
28
|
-
echo "ok --- model.
|
|
28
|
+
echo "ok --- model.aontu and data.aontu agree"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# data.
|
|
1
|
+
# data.aontu --- an instance of the truth in model.aontu. Edit it and run
|
|
2
2
|
# check.sh: every change is checked against the model, and a change the
|
|
3
3
|
# model refuses is named with the line it is on.
|
|
4
4
|
entity: {
|
package/skill/tasks.md
CHANGED
|
@@ -13,8 +13,8 @@ aontu init model/ # or into a named one
|
|
|
13
13
|
sh check.sh # the four questions, on what was just written
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
-
`init` writes `model.
|
|
17
|
-
`data.
|
|
16
|
+
`init` writes `model.aontu` (an entity map constrained with `&:`),
|
|
17
|
+
`data.aontu` (an instance of it that holds) and `check.sh` (the four
|
|
18
18
|
checks to run after every edit). It never overwrites: if any
|
|
19
19
|
of the three already stands there, it refuses and writes none of them.
|
|
20
20
|
|
|
@@ -49,7 +49,7 @@ of every following element renumbered.
|
|
|
49
49
|
## Check data against a model
|
|
50
50
|
|
|
51
51
|
```
|
|
52
|
-
aontu vet model.
|
|
52
|
+
aontu vet model.aontu data.aontu
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
Exit `0` valid, `1` a contradiction, `3` incomplete (nothing
|
|
@@ -62,8 +62,8 @@ report, `--closed` to refuse keys the model does not declare,
|
|
|
62
62
|
nothing answers exactly like one that passed:
|
|
63
63
|
|
|
64
64
|
```
|
|
65
|
-
aontu vet --coverage model.
|
|
66
|
-
aontu vet --strict-coverage model.
|
|
65
|
+
aontu vet --coverage model.aontu data.aontu # what did it examine?
|
|
66
|
+
aontu vet --strict-coverage model.aontu data.aontu # exit 1 if nothing
|
|
67
67
|
```
|
|
68
68
|
|
|
69
69
|
`--coverage` reports how many data leaves a declaration constrained,
|
|
@@ -74,19 +74,19 @@ cause is the `"*"` mistake above: reach for `&:`.
|
|
|
74
74
|
## Check the model is coherent with itself
|
|
75
75
|
|
|
76
76
|
```
|
|
77
|
-
aontu relations model.
|
|
78
|
-
aontu reaches planet moon model.
|
|
79
|
-
aontu trim --check model.
|
|
77
|
+
aontu relations model.aontu # declared entity edges: targets resolve, no cycles
|
|
78
|
+
aontu reaches planet moon model.aontu # does one entity reach another, at any remove?
|
|
79
|
+
aontu trim --check model.aontu # entries whose removal changes nothing
|
|
80
80
|
```
|
|
81
81
|
|
|
82
82
|
## Generate code from a model, and hold it
|
|
83
83
|
|
|
84
84
|
```
|
|
85
|
-
aontu render gen.
|
|
86
|
-
aontu render --check gen.
|
|
85
|
+
aontu render gen.aontu build # write the files below build/
|
|
86
|
+
aontu render --check gen.aontu build # write nothing; exit 1 when build/ has drifted
|
|
87
87
|
aontu render gen/ build # every generator directly in gen/, as one run
|
|
88
|
-
aontu model get out gen.
|
|
89
|
-
aontu trace gen.
|
|
88
|
+
aontu model get out gen.aontu # the component tree: files, and the lines in them
|
|
89
|
+
aontu trace gen.aontu # what rule wrote each line
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
A generator answers a **component tree** -- `file(name, [lines])` and
|
|
@@ -101,10 +101,10 @@ and the rule behind it.
|
|
|
101
101
|
## Ask what a model says, and why
|
|
102
102
|
|
|
103
103
|
```
|
|
104
|
-
aontu model get $.entity.planet.table model.
|
|
105
|
-
aontu model why $.entity.planet.table model.
|
|
106
|
-
aontu model get $.entity --keys model.
|
|
107
|
-
aontu model get $.entity --types model.
|
|
104
|
+
aontu model get $.entity.planet.table model.aontu
|
|
105
|
+
aontu model why $.entity.planet.table model.aontu
|
|
106
|
+
aontu model get $.entity --keys model.aontu
|
|
107
|
+
aontu model get $.entity --types model.aontu
|
|
108
108
|
```
|
|
109
109
|
|
|
110
110
|
`why` names **every** contribution to a value, with the file and line
|
|
@@ -114,7 +114,7 @@ what you expected, and the second thing to run when `vet` refuses.
|
|
|
114
114
|
## Change a value without editing the file
|
|
115
115
|
|
|
116
116
|
```
|
|
117
|
-
aontu model set '$.entity.planet.table=planet_v2' --entry model.
|
|
117
|
+
aontu model set '$.entity.planet.table=planet_v2' --entry model.aontu --overlay local.aontu
|
|
118
118
|
```
|
|
119
119
|
|
|
120
120
|
The change is checked before it is written; a change that contradicts
|
|
@@ -123,15 +123,15 @@ a pinned value is refused, and the file is left alone.
|
|
|
123
123
|
## Gate a change to the model itself
|
|
124
124
|
|
|
125
125
|
```
|
|
126
|
-
aontu subsume old.
|
|
127
|
-
aontu breaking --against git#HEAD~1 model.
|
|
128
|
-
aontu hash model.
|
|
126
|
+
aontu subsume old.aontu new.aontu # does the general admit every specific?
|
|
127
|
+
aontu breaking --against git#HEAD~1 model.aontu
|
|
128
|
+
aontu hash model.aontu # a pin that survives reformatting
|
|
129
129
|
```
|
|
130
130
|
|
|
131
131
|
## Hand a model to another agent
|
|
132
132
|
|
|
133
133
|
```
|
|
134
|
-
aontu agentsmd --write AGENTS.md model.
|
|
134
|
+
aontu agentsmd --write AGENTS.md model.aontu
|
|
135
135
|
```
|
|
136
136
|
|
|
137
137
|
Splices a derived stanza — the pin, the root keys, the shape, and the
|
package/src/agentsmd.ts
CHANGED
|
@@ -86,11 +86,11 @@ export function agentsMd(
|
|
|
86
86
|
'aontu model why ' + example + ' ' + name,
|
|
87
87
|
'',
|
|
88
88
|
'# does my document satisfy it?',
|
|
89
|
-
'aontu vet ' + name + ' mine.
|
|
89
|
+
'aontu vet ' + name + ' mine.aontu',
|
|
90
90
|
'',
|
|
91
91
|
'# change it without editing it',
|
|
92
92
|
'aontu model set ' + example + '=<value> --entry ' + name +
|
|
93
|
-
' --overlay overlay.
|
|
93
|
+
' --overlay overlay.aontu',
|
|
94
94
|
'',
|
|
95
95
|
'# the language itself, offline: the whole grammar on one page',
|
|
96
96
|
'aontu help language',
|
package/src/aontu.ts
CHANGED
package/src/cli.ts
CHANGED
|
@@ -193,7 +193,7 @@ Options:
|
|
|
193
193
|
|
|
194
194
|
Package verbs (a module is imported; a package is published):
|
|
195
195
|
sync Make the project correct: resolve by minimum version
|
|
196
|
-
selection, fetch what is missing, write aontu_meta/pkg-lock.
|
|
196
|
+
selection, fetch what is missing, write aontu_meta/pkg-lock.aontu,
|
|
197
197
|
vendor, verify. --frozen refuses to change the lockfile
|
|
198
198
|
add Take on a dependency the project does not have, then sync;
|
|
199
199
|
refuses one it has and names get
|
|
@@ -214,15 +214,15 @@ Package options:
|
|
|
214
214
|
signs the manifest, for the key provider
|
|
215
215
|
--token <file> publish: the forge's OIDC token, read from a file
|
|
216
216
|
--base <url> the repository to read from (repeatable; overrides
|
|
217
|
-
pkg.
|
|
218
|
-
--write <url> publish: the write path (overrides pkg.
|
|
217
|
+
pkg.aontu repo.base)
|
|
218
|
+
--write <url> publish: the write path (overrides pkg.aontu repo.write)
|
|
219
219
|
--against <dir> manifest: a prior version's tree, to gate on
|
|
220
220
|
--upstream <u> serve: fetch on miss from this repository (repeatable)
|
|
221
221
|
--listen <a> serve: the address to listen on (default 127.0.0.1:8017)
|
|
222
222
|
|
|
223
223
|
pkg subcommands (the rest of the package operations):
|
|
224
224
|
tidy Resolve the closure by minimum version selection and
|
|
225
|
-
rewrite aontu_meta/pkg-lock.
|
|
225
|
+
rewrite aontu_meta/pkg-lock.aontu in canonical form
|
|
226
226
|
verify Check every locked package still is and still means what
|
|
227
227
|
the lockfile pins, bytes before meaning, and change nothing
|
|
228
228
|
(the CI gate; tidy rewrites)
|
|
@@ -402,7 +402,7 @@ View exit codes: 0 rendered, 1 --check mismatch or lossy under
|
|
|
402
402
|
--strict, 2 usage or --max-rows exceeded, 4 the document does not stand
|
|
403
403
|
up on its own, or a relation, root or path that names nothing.
|
|
404
404
|
|
|
405
|
-
A template entry file whose extension is not .
|
|
405
|
+
A template entry file whose extension is not .aontu is a GENERATOR: a
|
|
406
406
|
document in the target's own syntax, whose marker lines carry aontu and
|
|
407
407
|
whose other lines are output. It is desugared before it is evaluated,
|
|
408
408
|
and a language the table does not know names its marker with --marker,
|
|
@@ -541,7 +541,7 @@ Fmt options:
|
|
|
541
541
|
The fmt verb prints one document in the agreed form; with no file it
|
|
542
542
|
reads standard input. Several files need one of the options above.
|
|
543
543
|
|
|
544
|
-
A file whose extension is not .
|
|
544
|
+
A file whose extension is not .aontu is a GENERATOR, as it is for
|
|
545
545
|
template: the aontu its marker lines carry is formatted, the marker
|
|
546
546
|
stands at the left margin with the aontu indented after it, and every
|
|
547
547
|
line of output is held on a line of its own. A file with no marker line
|
|
@@ -1695,7 +1695,7 @@ function parseBreakingArgs(
|
|
|
1695
1695
|
|
|
1696
1696
|
type OldVersion = { src: string, path: string, temp?: string }
|
|
1697
1697
|
|
|
1698
|
-
const INCLUDABLE = /\.(
|
|
1698
|
+
const INCLUDABLE = /\.(aontu|jsonic|json)$/
|
|
1699
1699
|
|
|
1700
1700
|
function oldVersion(spec: string, file: string): OldVersion | undefined {
|
|
1701
1701
|
if (!spec.startsWith('git#')) {
|
|
@@ -2230,18 +2230,28 @@ function parsePkgArgs(argv: string[], verb: string, io: Io): PkgArgs | undefined
|
|
|
2230
2230
|
}
|
|
2231
2231
|
|
|
2232
2232
|
|
|
2233
|
-
// A verb that finds
|
|
2234
|
-
// reads nothing from it.
|
|
2233
|
+
// A verb that finds an older layout names the current one, once, and
|
|
2234
|
+
// reads nothing from it. `pkg.aon` is the sharper case: a project
|
|
2235
|
+
// carrying it declares nothing to any verb, so `verify` answers over an
|
|
2236
|
+
// empty package and `sync` writes a lock with every pin dropped.
|
|
2235
2237
|
function nameOldLayout(dir: string, io: Io): void {
|
|
2236
|
-
const
|
|
2237
|
-
|
|
2238
|
-
|
|
2238
|
+
const here = (f: string): boolean => existsSync(join(dir, f))
|
|
2239
|
+
const mod = ['aon_vendor', 'mod-lock.aon', 'mod.aon',
|
|
2240
|
+
join(META_DIR, 'mod-lock.aon')].filter(here)
|
|
2241
|
+
const aon = ['pkg.aon', join(META_DIR, 'pkg-lock.aon')].filter(here)
|
|
2242
|
+
if (0 < mod.length) {
|
|
2239
2243
|
io.err(
|
|
2240
|
-
'aontu: ' +
|
|
2244
|
+
'aontu: ' + mod.join(', ') + ' belong to an older layout: the package ' +
|
|
2241
2245
|
'file is ' + PKG_FILE + ', the lockfile ' + join(META_DIR, LOCK_FILE) +
|
|
2242
2246
|
' and the vendor tree ' + join(META_DIR, 'vendor') + '; rename ' +
|
|
2243
2247
|
PKG_FILE + '\'s `mod` block to `pkg`, then run aontu sync\n')
|
|
2244
2248
|
}
|
|
2249
|
+
if (0 < aon.length) {
|
|
2250
|
+
io.err(
|
|
2251
|
+
'aontu: ' + aon.join(', ') + ' carry the withdrawn .aon extension, so ' +
|
|
2252
|
+
'nothing here declares a package: rename them to ' + PKG_FILE + ' and ' +
|
|
2253
|
+
join(META_DIR, LOCK_FILE) + ', then run aontu sync\n')
|
|
2254
|
+
}
|
|
2245
2255
|
}
|
|
2246
2256
|
|
|
2247
2257
|
|
|
@@ -2913,7 +2923,7 @@ function runTrace(argv: string[]): number {
|
|
|
2913
2923
|
|
|
2914
2924
|
// A GENERATOR IS AN ENTRY, not a preprocessing step: the file whose
|
|
2915
2925
|
// provenance is asked for is the one the author edits.
|
|
2916
|
-
if (!rest[0].endsWith('.
|
|
2926
|
+
if (!rest[0].endsWith('.aontu')) {
|
|
2917
2927
|
src = desugarTemplate(src, marker ??
|
|
2918
2928
|
markerFromProfiles(declared, rest[0]) ?? markerFor(rest[0]))
|
|
2919
2929
|
}
|
|
@@ -3126,7 +3136,7 @@ async function runRender(argv: string[]): Promise<number> {
|
|
|
3126
3136
|
process.stderr.write(`aontu: cannot read ${err.path}: ${err.message}\n`)
|
|
3127
3137
|
return 2
|
|
3128
3138
|
}
|
|
3129
|
-
if (!/[.]
|
|
3139
|
+
if (!/[.]aontu$/.test(f)) {
|
|
3130
3140
|
const mark = marker ?? markerFromProfiles(declared, f) ?? markerFor(f)
|
|
3131
3141
|
if (!templateOutputs(src, mark).some((out) => !out)) {
|
|
3132
3142
|
process.stderr.write(`aontu: ${f} carries no ${mark} marker line, ` +
|
|
@@ -4802,7 +4812,7 @@ function runFmt(argv: string[]): number | Promise<number> {
|
|
|
4802
4812
|
marker ?? markerFromProfiles(declared, file))
|
|
4803
4813
|
if (false === mark) {
|
|
4804
4814
|
process.stderr.write(
|
|
4805
|
-
`aontu: ${file} is not aontu source (.
|
|
4815
|
+
`aontu: ${file} is not aontu source (.aontu) and carries no ` +
|
|
4806
4816
|
`${markerFor(file)} marker line, so there is no aontu in it to ` +
|
|
4807
4817
|
'format; --marker names the marker for a language the table ' +
|
|
4808
4818
|
'does not know, and --profile reads one that declares it\n')
|
|
@@ -4818,7 +4828,7 @@ function fmtMarker(
|
|
|
4818
4828
|
if (undefined !== marker) {
|
|
4819
4829
|
return marker
|
|
4820
4830
|
}
|
|
4821
|
-
if (/[.]
|
|
4831
|
+
if (/[.]aontu$/.test(file)) {
|
|
4822
4832
|
return undefined
|
|
4823
4833
|
}
|
|
4824
4834
|
const mark = markerFor(file)
|
|
@@ -5259,7 +5269,7 @@ const KNOWN_VERBS = [
|
|
|
5259
5269
|
|
|
5260
5270
|
// looksLikeVerb reports whether an unreadable argument was meant as a
|
|
5261
5271
|
// verb rather than as a path. A bare word has no separator and no
|
|
5262
|
-
// extension; `./help`, `help.
|
|
5272
|
+
// extension; `./help`, `help.aontu`, `/tmp/help` and `sub/dir` are paths
|
|
5263
5273
|
// and keep the file diagnosis. Mirrors go/cmd/aontu/main.go.
|
|
5264
5274
|
function looksLikeVerb(arg: string): boolean {
|
|
5265
5275
|
return '' !== arg &&
|
package/src/err.ts
CHANGED
|
@@ -163,7 +163,7 @@ function resolveFile(url: string | undefined) {
|
|
|
163
163
|
// The PLATFORM'S separator, not '/': a hardcoded slash never matched
|
|
164
164
|
// a Windows cwd, so every Windows report named the absolute path
|
|
165
165
|
// where the POSIX report (and the Go CLI, which prints the entry as
|
|
166
|
-
// typed) named `clash.
|
|
166
|
+
// typed) named `clash.aontu` -- caught by the docs transcript for
|
|
167
167
|
// reading a conflict error, which pins the relative spelling.
|
|
168
168
|
let out = url?.replace(cwd + sep, '') ?? '<no-file>'
|
|
169
169
|
out = out === cwd || '' === out ? '<no-file>' : out
|
package/src/format.ts
CHANGED
|
@@ -11,6 +11,9 @@ import { ALIAS_RE, EXPORT_DECL_NAME, isExportHoldKey } from './aliasname'
|
|
|
11
11
|
|
|
12
12
|
const BUDGET = 80
|
|
13
13
|
|
|
14
|
+
// The gap behind a comment that ends a line of code.
|
|
15
|
+
const TRAIL_GAP = ' '
|
|
16
|
+
|
|
14
17
|
const MAX_DEPTH = 1000
|
|
15
18
|
|
|
16
19
|
export type FormatOptions = {
|
|
@@ -50,7 +53,7 @@ export type FormatReport =
|
|
|
50
53
|
type Tok = { name: string, src: string, val: any, sI: number }
|
|
51
54
|
|
|
52
55
|
const stubResolver: Resolver = ((spec: any) => ({
|
|
53
|
-
...spec, kind: '
|
|
56
|
+
...spec, kind: 'aontu', full: '__fmt__.aontu', src: '', found: true, search: [],
|
|
54
57
|
})) as any
|
|
55
58
|
|
|
56
59
|
let ENGINE: Aontu | undefined
|
|
@@ -688,6 +691,11 @@ class Writer {
|
|
|
688
691
|
this.line += s
|
|
689
692
|
}
|
|
690
693
|
|
|
694
|
+
// One gap behind the code; alone on its line it keeps its indent.
|
|
695
|
+
trail(s: string): void {
|
|
696
|
+
this.line = this.fresh() ? this.line + s : rtrim(this.line) + TRAIL_GAP + s
|
|
697
|
+
}
|
|
698
|
+
|
|
691
699
|
// Nothing on the line yet but its indentation.
|
|
692
700
|
fresh(): boolean {
|
|
693
701
|
return '' === this.line.trim()
|
|
@@ -772,7 +780,7 @@ function emitBody(
|
|
|
772
780
|
const e = chain(node)
|
|
773
781
|
emitValue(w, e, indent)
|
|
774
782
|
if (undefined !== e.trail) {
|
|
775
|
-
w.
|
|
783
|
+
w.trail(e.trail)
|
|
776
784
|
}
|
|
777
785
|
}
|
|
778
786
|
if (root && from < w.mark()) {
|
|
@@ -797,7 +805,7 @@ function emitValue(w: Writer, node: Node, indent: number): void {
|
|
|
797
805
|
const v = chain(node.value!)
|
|
798
806
|
emitValue(w, v, indent)
|
|
799
807
|
if (undefined !== v.trail) {
|
|
800
|
-
w.
|
|
808
|
+
w.trail(v.trail)
|
|
801
809
|
}
|
|
802
810
|
return
|
|
803
811
|
}
|
|
@@ -855,7 +863,7 @@ function emitCall(w: Writer, node: Node, indent: number): void {
|
|
|
855
863
|
w.text(it.text!)
|
|
856
864
|
}
|
|
857
865
|
else {
|
|
858
|
-
w.
|
|
866
|
+
w.trail(it.text!)
|
|
859
867
|
}
|
|
860
868
|
noted = true
|
|
861
869
|
continue
|
|
@@ -917,7 +925,7 @@ function emitBlock(
|
|
|
917
925
|
}
|
|
918
926
|
w.text(open)
|
|
919
927
|
if (undefined !== node.open) {
|
|
920
|
-
w.
|
|
928
|
+
w.trail(node.open)
|
|
921
929
|
}
|
|
922
930
|
emitBody(w, node.body!, indent + 2, stmt)
|
|
923
931
|
w.open(indent, false)
|
|
@@ -926,7 +934,6 @@ function emitBlock(
|
|
|
926
934
|
|
|
927
935
|
function emitExpr(w: Writer, items: Node[], indent: number): void {
|
|
928
936
|
const cont = w.fresh() ? indent : indent + 2
|
|
929
|
-
let operand = false
|
|
930
937
|
let cur = indent
|
|
931
938
|
for (const it of items) {
|
|
932
939
|
if ('op' === it.t) {
|
|
@@ -940,26 +947,19 @@ function emitExpr(w: Writer, items: Node[], indent: number): void {
|
|
|
940
947
|
else {
|
|
941
948
|
w.text(TIGHT_OP === it.text ? it.text! : ' ' + it.text + ' ')
|
|
942
949
|
}
|
|
943
|
-
operand = false
|
|
944
950
|
continue
|
|
945
951
|
}
|
|
946
952
|
if ('prefix' === it.t) {
|
|
947
953
|
w.text(it.text!)
|
|
948
|
-
operand = false
|
|
949
954
|
continue
|
|
950
955
|
}
|
|
951
956
|
if ('note' === it.t) {
|
|
952
|
-
|
|
953
|
-
w.text(' ')
|
|
954
|
-
}
|
|
955
|
-
w.text(it.text!)
|
|
957
|
+
w.trail(it.text!)
|
|
956
958
|
cur = cont
|
|
957
959
|
w.open(cur, false)
|
|
958
|
-
operand = false
|
|
959
960
|
continue
|
|
960
961
|
}
|
|
961
962
|
emitValue(w, it, cur)
|
|
962
|
-
operand = true
|
|
963
963
|
}
|
|
964
964
|
}
|
|
965
965
|
|
|
@@ -1104,7 +1104,7 @@ function repeatLines(entries: Node[], prefix: string, indent: number): Line[] |
|
|
|
1104
1104
|
out.push({ t: 'comment', text: e.text })
|
|
1105
1105
|
continue
|
|
1106
1106
|
}
|
|
1107
|
-
const trail = undefined === e.trail ? '' :
|
|
1107
|
+
const trail = undefined === e.trail ? '' : TRAIL_GAP + e.trail
|
|
1108
1108
|
if ('spread' === e.t) {
|
|
1109
1109
|
// The repeated spread entry is a one-entry map holding only a
|
|
1110
1110
|
// spread, so by D1's exception it keeps its braces.
|
|
@@ -1205,7 +1205,7 @@ function emitStatement(w: Writer, p: Node, indent: number, stmt: Stmt, prefix: s
|
|
|
1205
1205
|
}
|
|
1206
1206
|
}
|
|
1207
1207
|
if (undefined !== p.trail) {
|
|
1208
|
-
w.
|
|
1208
|
+
w.trail(p.trail)
|
|
1209
1209
|
}
|
|
1210
1210
|
if (rewritten && !stmt.covered) {
|
|
1211
1211
|
const before = emitAt(p.orig ?? [p], indent)
|
package/src/helpdoc.ts
CHANGED
|
@@ -17,25 +17,25 @@ const HELPDOC: HelpTopic[] = [
|
|
|
17
17
|
"topic": "tasks",
|
|
18
18
|
"summary": "what do you want to do? — the verb for a job",
|
|
19
19
|
"source": "docs/skill/tasks.md",
|
|
20
|
-
"text": "# What do you want to do?\n\nThe verb for a job, found by the word you arrived with. aontu's own\nvocabulary is on the right; yours is probably on the left.\n\n## Start from a document that works\n\nNothing written yet? Do not invent the first document, edit one:\n\n```\naontu init # into the working directory\naontu init model/ # or into a named one\nsh check.sh # the four questions, on what was just written\n```\n\n`init` writes `model.
|
|
20
|
+
"text": "# What do you want to do?\n\nThe verb for a job, found by the word you arrived with. aontu's own\nvocabulary is on the right; yours is probably on the left.\n\n## Start from a document that works\n\nNothing written yet? Do not invent the first document, edit one:\n\n```\naontu init # into the working directory\naontu init model/ # or into a named one\nsh check.sh # the four questions, on what was just written\n```\n\n`init` writes `model.aontu` (an entity map constrained with `&:`),\n`data.aontu` (an instance of it that holds) and `check.sh` (the four\nchecks to run after every edit). It never overwrites: if any\nof the three already stands there, it refuses and writes none of them.\n\n## Describe a domain\n\nAn **ontology**, a **schema**, a **data model**, a **contract** — in\naontu these are all one thing: a document. Write the entities as a\n**map keyed by name**, and say what every entry must satisfy with the\n`&:` template:\n\n```\nentity: {\n &: {\n table: string\n fields: { &: { type: string, required: *false | boolean } }\n }\n planet: { table: \"planets\", fields: { name: { type: \"string\" } } }\n moon: { table: \"moons\", fields: { name: { type: \"string\" } } }\n}\n```\n\n`&:` is the construct to reach for first, and the one most easily\nmissed. It meets **every** key of the map it sits in. A quoted `\"*\"`\nis not a wildcard — it is a key named `*`, and a schema written that\nway constrains nothing while still reporting `valid`.\n\nPrefer a named map to a list unless the order is a fact (a migration\nsequence, a rule table tried in order). A key is an address, a name\nother parts can refer to, and a diff that shows one insertion instead\nof every following element renumbered.\n\n## Check data against a model\n\n```\naontu vet model.aontu data.aontu\n```\n\nExit `0` valid, `1` a contradiction, `3` incomplete (nothing\ncontradicts, but the model is not yet satisfied), `4` the model does\nnot stand up on its own. `--format json` for the machine-readable\nreport, `--closed` to refuse keys the model does not declare,\n`--max-errors <n>` to cap the list.\n\n**Make the check prove it checked something.** A check that examined\nnothing answers exactly like one that passed:\n\n```\naontu vet --coverage model.aontu data.aontu # what did it examine?\naontu vet --strict-coverage model.aontu data.aontu # exit 1 if nothing\n```\n\n`--coverage` reports how many data leaves a declaration constrained,\nthe data paths none did, and the declarations no data met.\n`--strict-coverage` exits 1 when the answer is nothing. The usual\ncause is the `\"*\"` mistake above: reach for `&:`.\n\n## Check the model is coherent with itself\n\n```\naontu relations model.aontu # declared entity edges: targets resolve, no cycles\naontu reaches planet moon model.aontu # does one entity reach another, at any remove?\naontu trim --check model.aontu # entries whose removal changes nothing\n```\n\n## Generate code from a model, and hold it\n\n```\naontu render gen.aontu build # write the files below build/\naontu render --check gen.aontu build # write nothing; exit 1 when build/ has drifted\naontu render gen/ build # every generator directly in gen/, as one run\naontu model get out gen.aontu # the component tree: files, and the lines in them\naontu trace gen.aontu # what rule wrote each line\n```\n\nA generator answers a **component tree** -- `file(name, [lines])` and\nits neighbours -- which `aontu render` hands to jostraca, the generator\nruntime, to write. A tree that is one file is written to the path\nitself, and a folder of generators is one run. `--check` compares with\nwhat is committed: the model is the\ntruth, the code is the claim, and drift is a finding. `aontu trace`\nanswers the other direction: for a line of the output, the model node\nand the rule behind it.\n\n## Ask what a model says, and why\n\n```\naontu model get $.entity.planet.table model.aontu\naontu model why $.entity.planet.table model.aontu\naontu model get $.entity --keys model.aontu\naontu model get $.entity --types model.aontu\n```\n\n`why` names **every** contribution to a value, with the file and line\neach was written on. It is the first thing to run when a value is not\nwhat you expected, and the second thing to run when `vet` refuses.\n\n## Change a value without editing the file\n\n```\naontu model set '$.entity.planet.table=planet_v2' --entry model.aontu --overlay local.aontu\n```\n\nThe change is checked before it is written; a change that contradicts\na pinned value is refused, and the file is left alone.\n\n## Gate a change to the model itself\n\n```\naontu subsume old.aontu new.aontu # does the general admit every specific?\naontu breaking --against git#HEAD~1 model.aontu\naontu hash model.aontu # a pin that survives reformatting\n```\n\n## Hand a model to another agent\n\n```\naontu agentsmd --write AGENTS.md model.aontu\n```\n\nSplices a derived stanza — the pin, the root keys, the shape, and the\ncommands spelled with paths that exist — between two markers, and\nleaves the rest of the file alone. Re-run it in the commit that\nchanges the model.\n\n## When something refuses\n\nRead the code in the brackets, then look it up:\n\n```\naontu explain no_scalar_unify\n```\n\nEvery finding carries a `code`, a `class`, a `path` and the **two\nsites** that disagree — the value and the constraint it failed, each\nwith its file and line. The class says what kind of answer it is:\n`conflict` (two things cannot both hold), `incomplete` (nothing is\nwrong yet, something is missing), `parse`, `reference`, `budget`.\n\nFull index: [`error-codes.md`](error-codes.md). The language on one\npage: [`grammar-card.md`](grammar-card.md). The worked ladder from\nplain JSON upward: [`examples.md`](examples.md).\n"
|
|
21
21
|
},
|
|
22
22
|
{
|
|
23
23
|
"topic": "language",
|
|
24
24
|
"summary": "the grammar card — everything the language spells, on one page",
|
|
25
25
|
"source": "docs/skill/grammar-card.md",
|
|
26
|
-
"text": "# aontu grammar card\n\nEverything the language spells, on one page. The published machine\ngrammars are [`grammar/aontu.abnf`](../../grammar/aontu.abnf) — the\nnotation a person reads, with railroad diagrams — and\n[`aontu.gbnf`](../../grammar/aontu.gbnf), `aontu.lark` and\n`aontu.tmLanguage.json` for constrained decoding, parsing and\nhighlighting; this is their human twin.\n\n## Values\n\n| Write | Means |\n|-------|-------|\n| `{\"a\":1}`, `a: 1` | a map; keys may be bare or quoted |\n| `[1,2]` | a list |\n| `\"s\"`, `1`, `1.5`, `true`, `null` | scalars, as JSON |\n| `0d9007199254740993` | an EXACT number, at any magnitude |\n| `string integer number float boolean null` | kinds: any value of that kind |\n| `top` | anything at all; `nil` is the failure |\n\n## Combining\n\n| Write | Means |\n|-------|-------|\n| `a & b` | both must hold — the meet |\n| `a \\| b` | either may hold — the join |\n| `*1 \\| integer` | either, with `1` the DEFAULT a generation picks |\n| | the branch keeps its kind: a later `1.5` is refused, not admitted |\n| `x: 1` twice | the two meet; `1 & 2` is an error, `1 & integer` is `1` |\n| `$.a.b` | the value at that path of this document |\n| `1 + 2` | arithmetic on concrete numbers |\n\n## Maps that say more\n\n| Write | Means |\n|-------|-------|\n| `{&: {k: integer}}` | a TEMPLATE every key must satisfy |\n| `close({a:1})` | no key beyond those named |\n| `{a?: 1}` | optional: dropped if unresolved |\n| `hide(x)` | evaluated, then dropped from the output |\n| `type(x)` | a definition, not a value: it generates nothing |\n| `deprecate(x, {msg:\"…\"})` | still works, and says so |\n| `refer(t) & path($.a.b)` | a checked LINK: the tree address must resolve, and `t` flows into it |\n\n## Constraints\n\n`min(n) max(n) above(n) below(n)` bound a number;\n`length(n)` and `unique()` bound a list or string;\n`re(\"^…$\")` matches a string; `neq(v)` refuses one value;\n`must(cond, \"why\")` is the escape hatch.\n\nBounds compose: `integer & min(1) & max(10)` is a range, and two\nranges meet to their overlap.\n\n## Files\n\n`@\"./other.
|
|
26
|
+
"text": "# aontu grammar card\n\nEverything the language spells, on one page. The published machine\ngrammars are [`grammar/aontu.abnf`](../../grammar/aontu.abnf) — the\nnotation a person reads, with railroad diagrams — and\n[`aontu.gbnf`](../../grammar/aontu.gbnf), `aontu.lark` and\n`aontu.tmLanguage.json` for constrained decoding, parsing and\nhighlighting; this is their human twin.\n\n## Values\n\n| Write | Means |\n|-------|-------|\n| `{\"a\":1}`, `a: 1` | a map; keys may be bare or quoted |\n| `[1,2]` | a list |\n| `\"s\"`, `1`, `1.5`, `true`, `null` | scalars, as JSON |\n| `0d9007199254740993` | an EXACT number, at any magnitude |\n| `string integer number float boolean null` | kinds: any value of that kind |\n| `top` | anything at all; `nil` is the failure |\n\n## Combining\n\n| Write | Means |\n|-------|-------|\n| `a & b` | both must hold — the meet |\n| `a \\| b` | either may hold — the join |\n| `*1 \\| integer` | either, with `1` the DEFAULT a generation picks |\n| | the branch keeps its kind: a later `1.5` is refused, not admitted |\n| `x: 1` twice | the two meet; `1 & 2` is an error, `1 & integer` is `1` |\n| `$.a.b` | the value at that path of this document |\n| `1 + 2` | arithmetic on concrete numbers |\n\n## Maps that say more\n\n| Write | Means |\n|-------|-------|\n| `{&: {k: integer}}` | a TEMPLATE every key must satisfy |\n| `close({a:1})` | no key beyond those named |\n| `{a?: 1}` | optional: dropped if unresolved |\n| `hide(x)` | evaluated, then dropped from the output |\n| `type(x)` | a definition, not a value: it generates nothing |\n| `deprecate(x, {msg:\"…\"})` | still works, and says so |\n| `refer(t) & path($.a.b)` | a checked LINK: the tree address must resolve, and `t` flows into it |\n\n## Constraints\n\n`min(n) max(n) above(n) below(n)` bound a number;\n`length(n)` and `unique()` bound a list or string;\n`re(\"^…$\")` matches a string; `neq(v)` refuses one value;\n`must(cond, \"why\")` is the escape hatch.\n\nBounds compose: `integer & min(1) & max(10)` is a range, and two\nranges meet to their overlap.\n\n## Files\n\n`@\"./other.aontu\"` includes another document — it unifies in, it does not\nconcatenate. (A constrained decoder is not given this: generated\ndocuments describe values, they do not load files.)\n"
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
"topic": "examples",
|
|
30
30
|
"summary": "the ladder — plain JSON, then one addition at a time",
|
|
31
31
|
"source": "docs/skill/examples.md",
|
|
32
|
-
"text": "# aontu by example\n\nThe ladder: start with the JSON you already know, add one thing at a\ntime. Every rung is a valid document.\n\n## 1. It is JSON\n\n```\n{\"service\": {\"name\": \"auth\", \"port\": 8080}}\n```\n\nBare keys and no commas also parse, so this is the same document:\n\n```\nservice: {\n name: \"auth\"\n port: 8080\n}\n```\n\n## 2. Say what a value MAY be\n\n```\nservice: {\n name: string\n port: integer\n}\n```\n\nNothing generates yet — this is a truth, not a value. `aontu vet\nservice.
|
|
32
|
+
"text": "# aontu by example\n\nThe ladder: start with the JSON you already know, add one thing at a\ntime. Every rung is a valid document.\n\n## 1. It is JSON\n\n```\n{\"service\": {\"name\": \"auth\", \"port\": 8080}}\n```\n\nBare keys and no commas also parse, so this is the same document:\n\n```\nservice: {\n name: \"auth\"\n port: 8080\n}\n```\n\n## 2. Say what a value MAY be\n\n```\nservice: {\n name: string\n port: integer\n}\n```\n\nNothing generates yet — this is a truth, not a value. `aontu vet\nservice.aontu deploy.aontu` says whether a deployment satisfies it.\n\n## 3. Say what it SHOULD be\n\n```\nservice: {\n name: string\n port: *8080 | integer # 8080 unless told otherwise\n replicas: *1 | integer\n}\n```\n\nNow it generates: `{\"service\":{\"name\":…,\"port\":8080,\"replicas\":1}}` —\nexcept `name`, which nothing has supplied. Defaults are picked at\ngeneration; they do not stop a caller from choosing something else.\n\n`*8080 | integer` means what it reads as: a caller's `9090` overrides\nit, and a caller's `1.5` is refused, because the branch admits only the\nkind it names. Write `*8080 | number` if any numeric value should be\nallowed to win.\n\n## 4. Say it once, for every key\n\n```\nservices: {\n &: { port: integer, replicas: *1 | integer }\n auth: { port: 8080 }\n db: { port: 5432, replicas: 3 }\n}\n```\n\nThe `&:` template meets EVERY key. `aontu model why $.services.db.replicas`\nreports both contributions — the template's `*1|integer` and the\nliteral `3` — with the line each was written on.\n\n## 5. Bound it\n\n```\nservices: {\n &: {\n port: integer & min(1) & max(65535)\n name: string & re(\"^[a-z][a-z0-9-]*$\")\n }\n}\n```\n\nA port of `0` is now an error with a path, not a runtime surprise.\n\n## 6. Layer it\n\n```\n# base.aontu\nservice: { image: string, replicas: *1 | integer }\n\n# prod.aontu\n@\"./base.aontu\"\nservice: { image: \"auth:v2.3\", replicas: 5 }\n```\n\nUnification is order-independent: `base & prod` is `prod & base`. To\nchange a value without editing the file, append to an overlay:\n\n```\naontu model set '$.service.replicas=7' --entry prod.aontu --overlay local.aontu\n```\n\nIf the value is PINNED rather than open, that command refuses and\nnames the pinning site — which is the honest answer, and where\n`aontu model why` takes you next.\n"
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
"topic": "codes",
|
|
36
36
|
"summary": "what a refusal means, and what to do about it",
|
|
37
37
|
"source": "docs/skill/error-codes.md",
|
|
38
|
-
"text": "# What a refusal means\n\nEvery aontu error carries a **code**, and every code has a **class**.\nThe class says what kind of thing went wrong, which is what decides\nyour next move. The full registry — every code, its class, and the\nversion it appeared in — is\n[`test/spec/errcodes.tsv`](../../test/spec/errcodes.tsv), which the\ntest suite holds to the engine in both implementations.\n\n| Class | Meaning | What to do |\n|-------|---------|------------|\n| `parse` | the text is not a document | fix the syntax at the site the frame points at |\n| `conflict` | two values cannot both hold | one of them is wrong: `aontu model why <path>` names both and where they were written |\n| `incomplete` | nothing contradicts, but the value is not concrete | supply what is missing, or accept it with `--partial` |\n| `reference` | a path names nothing | check the spelling; `aontu model get $ --keys` lists what is there |\n| `compat` | a change breaks an earlier version | that is `aontu subsume` / `aontu breaking` talking: widen the change or version it |\n| `budget` | evaluation hit a deterministic limit | usually a cycle; simplify, or raise the budget deliberately |\n| `internal` | the engine surprised itself | a bug worth reporting |\n\n## Looking a code up\n\n```\naontu explain constraint # what one code means, and its class\naontu explain --list # every registered code, with its class\n```\n\nA report prints two bracketed spans, and only one of them is a code:\n\n```\n$.note.n1.id: constraint [conflict]\n [aontu/constraint]: Cannot unify values at path $.note.n1.id\n```\n\n`[conflict]` is the **class**. `[aontu/constraint]` is the **code**,\ncarrying the `aontu/` prefix. `explain` takes either spelling —\n`constraint` or `aontu/constraint` — and answers under the registered\none. The headline carries the bare code as well, and so does the `code`\nfield of a `--format json` report.\n\n## The repair loop\n\n```\naontu vet schema.
|
|
38
|
+
"text": "# What a refusal means\n\nEvery aontu error carries a **code**, and every code has a **class**.\nThe class says what kind of thing went wrong, which is what decides\nyour next move. The full registry — every code, its class, and the\nversion it appeared in — is\n[`test/spec/errcodes.tsv`](../../test/spec/errcodes.tsv), which the\ntest suite holds to the engine in both implementations.\n\n| Class | Meaning | What to do |\n|-------|---------|------------|\n| `parse` | the text is not a document | fix the syntax at the site the frame points at |\n| `conflict` | two values cannot both hold | one of them is wrong: `aontu model why <path>` names both and where they were written |\n| `incomplete` | nothing contradicts, but the value is not concrete | supply what is missing, or accept it with `--partial` |\n| `reference` | a path names nothing | check the spelling; `aontu model get $ --keys` lists what is there |\n| `compat` | a change breaks an earlier version | that is `aontu subsume` / `aontu breaking` talking: widen the change or version it |\n| `budget` | evaluation hit a deterministic limit | usually a cycle; simplify, or raise the budget deliberately |\n| `internal` | the engine surprised itself | a bug worth reporting |\n\n## Looking a code up\n\n```\naontu explain constraint # what one code means, and its class\naontu explain --list # every registered code, with its class\n```\n\nA report prints two bracketed spans, and only one of them is a code:\n\n```\n$.note.n1.id: constraint [conflict]\n [aontu/constraint]: Cannot unify values at path $.note.n1.id\n```\n\n`[conflict]` is the **class**. `[aontu/constraint]` is the **code**,\ncarrying the `aontu/` prefix. `explain` takes either spelling —\n`constraint` or `aontu/constraint` — and answers under the registered\none. The headline carries the bare code as well, and so does the `code`\nfield of a `--format json` report.\n\n## The repair loop\n\n```\naontu vet schema.aontu mine.aontu --format json\n```\n\nThe exit code branches for you: `0` valid, `1` invalid (fix the\ndata), `3` incomplete (supply more), `4` the schema itself is\nunusable (fix the truth, not the data). Every finding carries\n`path`, `code`, and the sites on both sides — the data site first,\nbecause that is the one to edit. A site names **the file whose text\nit excerpts**, so its row and column are safe to edit at even when\nthe document loads others.\n\nRead `hint` before guessing. `message` is the one-line headline;\n`hint` is the engine's own explanation of the failure class with the\noffending values filled in, and for several codes it names the fix\noutright — `lossy_integer_literal` tells you to write the literal as\n`0d…`. Every code in the registry has hint text, which is what\n`aontu explain` prints. A finding carries it inline for an exact\nregistry code; a **dynamic** code (`func:upper`, `op[+]`) is registered\nthrough its prefix, and only `explain` falls back to the prefix's text,\nso such a finding carries no `hint`.\n\nFor a conflict, `aontu model why <path> mine.aontu` lists every contribution\nto that path with its role and source line, which turns \"these\ndisagree\" into \"these two lines disagree\".\n\nThen fix it:\n\n```\naontu model set '$.replicas=5' --entry schema.aontu --overlay mine.aontu --in-place\n```\n\n`--in-place` rewrites the pinned literal **where it was written**, so\ncomments and layout survive. Without it, `set` APPENDS — which is the\nright thing when the document left a hole, and cannot work when it\npinned the wrong value, because unification only narrows.\n\nThe edit is verified before a byte is written: a site carries the\nsource text it covers, and the text at the span must match it. Where\nthat cannot be established — the value comes from a `&:` template or a\n`$ref`, two statements pin the path, the site names the opening token\nof a compound like `min(1)`, or the overlay `@\"includes\"` another\ndocument — the assignment is appended as usual and a **warning** says\nwhich case it hit. A warning never changes the verdict, so asking for\n`--in-place` cannot make a run fail that would have succeeded.\n"
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
"topic": "grammar",
|
|
@@ -54,22 +54,22 @@ type InitFile = {
|
|
|
54
54
|
|
|
55
55
|
const INITDOC: InitFile[] = [
|
|
56
56
|
{
|
|
57
|
-
"file": "docs/skill/init/model.
|
|
58
|
-
"name": "model.
|
|
57
|
+
"file": "docs/skill/init/model.aontu",
|
|
58
|
+
"name": "model.aontu",
|
|
59
59
|
"mode": 420,
|
|
60
|
-
"text": "# model.
|
|
60
|
+
"text": "# model.aontu --- the truth. `aontu vet model.aontu data.aontu` asks whether\n# a document satisfies it.\n#\n# `&:` is the construct to learn first: it meets EVERY key of the map\n# it sits in, so one statement constrains every entity. A quoted \"*\" is\n# not a wildcard -- it is a key named `*`, it meets nothing, and a\n# schema written that way reports `valid` over data that violates it.\n# `aontu vet --strict-coverage` refuses to pass such a check.\nentity: {\n &: {\n table: string & re(\"^[a-z][a-z0-9_]*$\")\n fields: {\n &: {\n type: \"string\" | \"integer\" | \"boolean\"\n required: *false | boolean\n }\n }\n }\n}\n"
|
|
61
61
|
},
|
|
62
62
|
{
|
|
63
|
-
"file": "docs/skill/init/data.
|
|
64
|
-
"name": "data.
|
|
63
|
+
"file": "docs/skill/init/data.aontu",
|
|
64
|
+
"name": "data.aontu",
|
|
65
65
|
"mode": 420,
|
|
66
|
-
"text": "# data.
|
|
66
|
+
"text": "# data.aontu --- an instance of the truth in model.aontu. Edit it and run\n# check.sh: every change is checked against the model, and a change the\n# model refuses is named with the line it is on.\nentity: {\n planet: {\n table: \"planets\"\n fields: {\n name: { type: \"string\", required: true }\n diameter: { type: \"integer\" }\n }\n }\n}\n"
|
|
67
67
|
},
|
|
68
68
|
{
|
|
69
69
|
"file": "docs/skill/init/check.sh",
|
|
70
70
|
"name": "check.sh",
|
|
71
71
|
"mode": 493,
|
|
72
|
-
"text": "#!/usr/bin/env sh\n# check.sh --- the four questions to ask of a model. Run it after\n# every edit to model.
|
|
72
|
+
"text": "#!/usr/bin/env sh\n# check.sh --- the four questions to ask of a model. Run it after\n# every edit to model.aontu or data.aontu.\n#\n# `aontu help tasks` maps a job to a verb; `aontu explain <code>` says\n# what a refusal means; `aontu help language` is the whole grammar on\n# one page. None of them needs a network.\nset -eu\n\nAONTU=\"${AONTU:-aontu}\"\ncd \"$(dirname \"$0\")\"\n\n# 1. Does the data satisfy the truth -- and did the check examine\n# anything? --strict-coverage exits 1 on a check that constrained no\n# value, which is the failure a passing gate hides.\n$AONTU vet --strict-coverage model.aontu data.aontu\n\n# 2. What does it say at a path?\n$AONTU model get '$.entity.planet.table' data.aontu\n\n# 3. Why does it say that? Every contribution, with the line it is on.\n$AONTU model why '$.entity.planet.table' data.aontu\n\n# 4. A pin for the truth: it survives reformatting and moves on any\n# change of meaning.\n$AONTU hash model.aontu\n\necho \"ok --- model.aontu and data.aontu agree\"\n"
|
|
73
73
|
}
|
|
74
74
|
]
|
|
75
75
|
|