aval-adr 1.5.0 → 1.6.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 +80 -2
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -59,6 +59,77 @@ that is where an agent left to its own judgment does damage.
|
|
|
59
59
|
| 6 | `retired` | an ADR deliberately retired this key |
|
|
60
60
|
| 7 | `unknown` | no such key or scope, or a key not decided on that axis |
|
|
61
61
|
|
|
62
|
+
## Which decisions bear on this change
|
|
63
|
+
|
|
64
|
+
`resolve` needs a key, which is a chicken-and-egg problem at the start of a
|
|
65
|
+
task: the way to learn that a decision governs the file you are about to edit
|
|
66
|
+
is to already know its name. The alternative is `HEADS.md`, which is every
|
|
67
|
+
decision the repository has ever made.
|
|
68
|
+
|
|
69
|
+
`aval relevant` ranks the vocabulary against what you are about to touch:
|
|
70
|
+
|
|
71
|
+
```console
|
|
72
|
+
$ aval relevant --path crates/aval/src/mcp.rs --text "release a new version by pushing a tag"
|
|
73
|
+
advisory A ranking is a suggestion: it resolves nothing. Only `aval resolve <key>` answers.
|
|
74
|
+
|
|
75
|
+
14.2104 release.trigger active ADR-0008 A pushed version tag, never a merge
|
|
76
|
+
11.5524 release.version-scheme active ADR-0012 Semantic Versioning 2.0.0
|
|
77
|
+
4.9182 ci.test-gate-stage active ADR-0009 pre-commit
|
|
78
|
+
4.7105 forge.primary undecided no accepted decision for forge.primary
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**This is retrieval, not resolution**, and the output says so on every run. The
|
|
82
|
+
order is a guess about attention. What is not a guess is the verdict on each
|
|
83
|
+
row: it comes from the same `resolve` the rest of the tool runs, which is what
|
|
84
|
+
makes the `undecided` row the interesting one — nobody decided it, and an agent
|
|
85
|
+
that quietly fills the gap is doing the thing the corpus exists to prevent.
|
|
86
|
+
|
|
87
|
+
### The signals
|
|
88
|
+
|
|
89
|
+
| Signal | Weight | What it reads |
|
|
90
|
+
|---|---|---|
|
|
91
|
+
| text | 1.0 | BM25 over `--text`, against one document per key: the key's name and description, then the title, choice, reason and body of whatever decides it, and superseded titles at a third of the weight |
|
|
92
|
+
| path | 0.6 | the same BM25 over the words in each `--path` — directories and file stems, extensions dropped |
|
|
93
|
+
| mention | 2.0 per path, three at most | a record's body names that path itself: backticked, as a markdown link, or as a glob matched by its literal directory |
|
|
94
|
+
| co-change | 0.5 per path, three at most | `git log` says the commits that wrote the record also touched that path |
|
|
95
|
+
|
|
96
|
+
A mention outranks any amount of word overlap, because it is the one signal an
|
|
97
|
+
author put there on purpose. Co-change is weakest and capped hardest: a record
|
|
98
|
+
and a config file in one commit may share nothing but a Tuesday. The tokenizer
|
|
99
|
+
is frozen — lowercase, ASCII-fold, split on every non-alphanumeric, drop stop
|
|
100
|
+
words and one-character tokens, light suffix stemming — and the conformance
|
|
101
|
+
battery compares the resulting order byte for byte, so changing it is a change
|
|
102
|
+
somebody reviews rather than a ranking that quietly moved.
|
|
103
|
+
|
|
104
|
+
`--changed` adds what git reports modified, staged and untracked, which is the
|
|
105
|
+
whole query for "what does this branch touch". `--scope S` ranks only the keys
|
|
106
|
+
answerable at S and resolves each one there. `--top N` defaults to 5, and a row
|
|
107
|
+
must also score a fifth of the top row to be printed, so a query with one good
|
|
108
|
+
answer reports one. Rules (below) that match the same words are listed after
|
|
109
|
+
the keys, clearly apart.
|
|
110
|
+
|
|
111
|
+
Exit is **always 0**, usage errors aside. A ranking has no verdict to report,
|
|
112
|
+
and "I ranked and found little" must not share a code with "I could not look".
|
|
113
|
+
|
|
114
|
+
### For a router
|
|
115
|
+
|
|
116
|
+
`--json` carries a `dependencies` array — the same keys, compacted:
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
{"dependencies":[
|
|
120
|
+
{"key":"release.trigger","state":"active","exit":0,"adr":"ADR-0008","unresolved":false},
|
|
121
|
+
{"key":"forge.primary","state":"undecided","exit":4,"unresolved":true}]}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
One row per ranked key, in ranked order, and `unresolved` is true for exactly
|
|
125
|
+
`undecided` and `contradiction`. That is what a dispatcher reads —
|
|
126
|
+
[relais](https://github.com/fredericrous/relais) routes on unresolved decision
|
|
127
|
+
dependencies — so a change whose decisions are not settled goes to a person
|
|
128
|
+
instead of to a worker. The full verdict, with the choice and the reason, is in
|
|
129
|
+
`keys`; `why` on each row says which signal earned it its place, and
|
|
130
|
+
`decided_elsewhere` names the scopes that do decide a key the asked scope does
|
|
131
|
+
not.
|
|
132
|
+
|
|
62
133
|
## In front of an agent
|
|
63
134
|
|
|
64
135
|
A corpus that resolves is half the point. The other half is that whatever is
|
|
@@ -120,10 +191,16 @@ a session:
|
|
|
120
191
|
$ claude mcp add aval -- aval mcp
|
|
121
192
|
```
|
|
122
193
|
|
|
123
|
-
|
|
124
|
-
`
|
|
194
|
+
Nine read-only tools: `aval_resolve`, `aval_relevant`, `aval_keys`,
|
|
195
|
+
`aval_heads`, `aval_show`, `aval_history`, `aval_rules`, `aval_rule` and
|
|
196
|
+
`aval_repos`. They resolve through the same graph the CLI does and return the
|
|
125
197
|
same bytes `--json` would, so the two surfaces cannot drift apart.
|
|
126
198
|
|
|
199
|
+
`aval_relevant` is the one whose result is **not** an answer, and its
|
|
200
|
+
description says so where a model will read it: the ranking is advisory, what
|
|
201
|
+
is authoritative is the verdict beside each key, and an `undecided` row is the
|
|
202
|
+
reason to have called it.
|
|
203
|
+
|
|
127
204
|
The distinction that matters: **a verdict is not an error**. `undecided`,
|
|
128
205
|
`retired`, `unknown` and `contradiction` all come back as ordinary results with
|
|
129
206
|
`isError: false`, because each is an answer. Reporting `contradiction` as a tool
|
|
@@ -179,6 +256,7 @@ different edges:
|
|
|
179
256
|
| | |
|
|
180
257
|
|---|---|
|
|
181
258
|
| `aval resolve <key> [--scope S]` | the authoritative lookup |
|
|
259
|
+
| `aval relevant [--path P]… [--text W] [--changed] [--top N]` | which keys bear on what you are about to touch, ranked, each with its verdict. Advisory: it resolves nothing |
|
|
182
260
|
| `aval check` | every invariant; what the git hook and CI run |
|
|
183
261
|
| `aval heads [--write\|--check]` | the projection |
|
|
184
262
|
| `aval show ADR-0015` | derived status, including partial supersession |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aval-adr",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"description": "Ask what the current architecture decision is, and get a typed answer",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"adr",
|
|
@@ -32,11 +32,11 @@
|
|
|
32
32
|
"node": ">=18"
|
|
33
33
|
},
|
|
34
34
|
"optionalDependencies": {
|
|
35
|
-
"@aval-adr/darwin-arm64": "1.
|
|
36
|
-
"@aval-adr/darwin-x64": "1.
|
|
37
|
-
"@aval-adr/linux-arm64-gnu": "1.
|
|
38
|
-
"@aval-adr/linux-x64-gnu": "1.
|
|
39
|
-
"@aval-adr/linux-x64-musl": "1.
|
|
40
|
-
"@aval-adr/win32-x64": "1.
|
|
35
|
+
"@aval-adr/darwin-arm64": "1.6.0",
|
|
36
|
+
"@aval-adr/darwin-x64": "1.6.0",
|
|
37
|
+
"@aval-adr/linux-arm64-gnu": "1.6.0",
|
|
38
|
+
"@aval-adr/linux-x64-gnu": "1.6.0",
|
|
39
|
+
"@aval-adr/linux-x64-musl": "1.6.0",
|
|
40
|
+
"@aval-adr/win32-x64": "1.6.0"
|
|
41
41
|
}
|
|
42
42
|
}
|