aval-adr 1.4.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 +94 -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
|
|
@@ -79,6 +150,20 @@ Repo-specific caveats go in `.claude/aval-hook.local.md`. The hook appends that
|
|
|
79
150
|
file; installing again never touches it. `--check` is the drift detector for
|
|
80
151
|
CI: exit 0 wired, exit 1 stale.
|
|
81
152
|
|
|
153
|
+
The script's second line names the aval that wrote it:
|
|
154
|
+
|
|
155
|
+
```sh
|
|
156
|
+
#!/bin/sh
|
|
157
|
+
# aval-hook: written by aval 1.5.0
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
A script from a **newer** aval is not stale, and an older aval leaves it alone
|
|
161
|
+
rather than downgrading it, so a workstation that upgrades first does not
|
|
162
|
+
redden a CI job pinned to the release before. Both modes also print a `note`
|
|
163
|
+
for every `AVAL_VERSION:` pin under `.github/workflows` or `.forgejo/workflows`
|
|
164
|
+
that is behind or ahead of the running aval — advisory, never an exit code,
|
|
165
|
+
never an edit to the workflow.
|
|
166
|
+
|
|
82
167
|
Where the repository vendors packs, the hook also asks whether they are still
|
|
83
168
|
what their sources publish — at most once an hour per repository, under a
|
|
84
169
|
five-second budget that kills the remote call rather than waiting on it, and
|
|
@@ -106,10 +191,16 @@ a session:
|
|
|
106
191
|
$ claude mcp add aval -- aval mcp
|
|
107
192
|
```
|
|
108
193
|
|
|
109
|
-
|
|
110
|
-
`
|
|
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
|
|
111
197
|
same bytes `--json` would, so the two surfaces cannot drift apart.
|
|
112
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
|
+
|
|
113
204
|
The distinction that matters: **a verdict is not an error**. `undecided`,
|
|
114
205
|
`retired`, `unknown` and `contradiction` all come back as ordinary results with
|
|
115
206
|
`isError: false`, because each is an answer. Reporting `contradiction` as a tool
|
|
@@ -165,6 +256,7 @@ different edges:
|
|
|
165
256
|
| | |
|
|
166
257
|
|---|---|
|
|
167
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 |
|
|
168
260
|
| `aval check` | every invariant; what the git hook and CI run |
|
|
169
261
|
| `aval heads [--write\|--check]` | the projection |
|
|
170
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
|
}
|