agent-doc-system 1.0.0 → 1.2.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/CHANGELOG.md +269 -0
- package/README.md +97 -112
- package/adapters/ansible.mjs +306 -0
- package/adapters/cache.mjs +8 -2
- package/adapters/contract-consumers.mjs +1 -1
- package/adapters/database.mjs +18 -4
- package/adapters/events.mjs +1 -1
- package/adapters/github-actions.mjs +244 -85
- package/adapters/go.mjs +1 -1
- package/adapters/index.mjs +5 -2
- package/adapters/object-store.mjs +2 -2
- package/adapters/python.mjs +1142 -0
- package/adapters/resource-client.mjs +1 -1
- package/adapters/rust.mjs +987 -0
- package/adapters/typescript.mjs +1 -1
- package/bin/agentdoc.mjs +60 -44
- package/bin/commands.mjs +169 -0
- package/bin/usage.txt +5 -3
- package/core/audit.mjs +55 -4
- package/core/authority/engine.mjs +27 -4
- package/core/codes.mjs +11 -0
- package/core/compile.mjs +263 -13
- package/core/dependents.mjs +42 -0
- package/core/descriptors.mjs +5 -2
- package/core/discover.mjs +60 -9
- package/core/fsx.mjs +27 -4
- package/core/graph.mjs +1 -1
- package/core/impact.mjs +55 -44
- package/core/normative.mjs +171 -0
- package/core/query.mjs +18 -8
- package/core/scaffold.mjs +87 -22
- package/core/sourcescan.mjs +11 -2
- package/core/toml.mjs +463 -140
- package/core/yaml.mjs +5 -3
- package/docs/ADAPTERS.md +232 -7
- package/docs/AUTHORITY.md +10 -1
- package/docs/BENCHMARK.md +68 -0
- package/docs/CI.md +3 -1
- package/docs/EVALS.md +33 -2
- package/docs/MIGRATION.md +76 -6
- package/docs/QUERY.md +53 -4
- package/docs/SPEC.md +22 -0
- package/docs/assets/readme/agentdoc-hero.webp +0 -0
- package/docs/assets/readme/agentdoc-in-action.webp +0 -0
- package/docs/assets/readme/how-agentdoc-works.webp +0 -0
- package/docs/assets/readme/why-agentdoc.webp +0 -0
- package/docs/ci/github-actions.yml +1 -1
- package/evals/harness.mjs +32 -6
- package/evals/scenarios/fixture-b-03-change-shared-lib.json +8 -1
- package/evals/scenarios/fixture-c-03-shared-vocabulary.json +7 -1
- package/evals/scenarios/fixture-e-01-change-shared-lib.json +14 -0
- package/evals/scenarios/fixture-e-02-change-manifest.json +9 -0
- package/evals/scenarios/fixture-e-03-local-module.json +9 -0
- package/evals/scenarios/fixture-e-04-ambiguous-crate.json +14 -0
- package/evals/scenarios/fixture-f-01-change-shared-lib.json +9 -0
- package/evals/scenarios/fixture-f-02-change-manifest.json +9 -0
- package/evals/scenarios/fixture-f-03-shadowed-import.json +9 -0
- package/evals/scenarios/fixture-f-04-nested-workspace.json +9 -0
- package/evals/scenarios/fixture-f-05-alembic-database.json +9 -0
- package/evals/scenarios/fixture-f-06-unittest-job.json +9 -0
- package/package.json +2 -1
- package/schemas/common.schema.json +40 -0
- package/schemas/component.schema.json +5 -1
- package/schemas/config.schema.json +117 -1
- package/skills/agent-doc-system/SKILL.md +5 -1
- package/skills/agent-doc-system/references/cli.md +12 -4
- package/skills/agent-doc-system/references/create-migrate.md +28 -6
- package/templates/ci.yml +1 -1
package/docs/ADAPTERS.md
CHANGED
|
@@ -43,9 +43,18 @@ Available on `ctx`:
|
|
|
43
43
|
| `transitiveDependencies(ref)` | manifest-declared dependencies, order-independent |
|
|
44
44
|
| `productionDependencies(ref)` | production dependency names, for client-of-resource rules |
|
|
45
45
|
| `deferSecondPass(fn)` | run after every unit is known |
|
|
46
|
-
| `
|
|
46
|
+
| `requirements` | declared normative requirements (`subject`, `key`, `value`, `source`, `satisfiedBy`, `expects`) an adapter may derive the implementation side of |
|
|
47
|
+
| `unitByPkgName`, `unitByGoModule`, `unitByCrateName` | cross-unit resolution built before extraction |
|
|
48
|
+
| `unitByPythonDist`, `unitByPythonImport` | Python distribution names (PEP 503) and import names, built before extraction |
|
|
47
49
|
| `errors.push({ code, message })` | a hard error, collected rather than thrown |
|
|
48
50
|
|
|
51
|
+
For per-unit source inventories, use `sourceFiles(repo, unit.root)` or
|
|
52
|
+
`repo.walkUnit(unit.root, directory = unit.root)`. Discovery computes ownership
|
|
53
|
+
once from eligible units: these scans prune nested unit roots, so a file belongs
|
|
54
|
+
only to its deepest enclosing unit. `repo.ownsUnitPath(unit.root, path)` applies
|
|
55
|
+
the same boundary to custom traversals. Keep `repo.walk` for repository-wide
|
|
56
|
+
discovery and authored inputs; explicit cross-unit references can still be read.
|
|
57
|
+
|
|
49
58
|
## The three rules
|
|
50
59
|
|
|
51
60
|
### 1. An adapter may not know the repository
|
|
@@ -89,10 +98,12 @@ cannot name the file a fact came from, you cannot add the fact.
|
|
|
89
98
|
| `turborepo` | `turbo.json` (nearest ancestor) | per-package task commands |
|
|
90
99
|
| `typescript` | `tsconfig.json` | language, project references, file-router routes |
|
|
91
100
|
| `go` | `go.mod`, `go.work` | module roots, module graph, `go test`/`go vet` |
|
|
101
|
+
| `rust` | `Cargo.toml` (`[package]`), workspace `members` (including a workspace below the repository root) | crate roots, path, workspace, and `[patch]`/`[replace]` dependency edges, `cargo test`/`cargo clippy` |
|
|
102
|
+
| `python` | `pyproject.toml`, `setup.py`, `setup.cfg`, `requirements*.txt` | distribution graph, import edges, evidence-backed test and static commands |
|
|
92
103
|
| `openapi` | `*.openapi.y[a]ml` | operation inventory, deterministic consumers |
|
|
93
104
|
| `protobuf` / `graphql` | contract files | method/type inventory, consumers |
|
|
94
105
|
| `oidc` | discovery-path literals | OIDC client consumers |
|
|
95
|
-
| `github-actions` | `.github/workflows` | component-scoped checks and repository gates |
|
|
106
|
+
| `github-actions` | repository-root `.github/workflows` (not a unit marker; a nested one is ignored, as GitHub ignores it) | component-scoped checks and repository gates |
|
|
96
107
|
| `dockerfile` | `Dockerfile`, `Containerfile` | deployable evidence |
|
|
97
108
|
| `deploy-config` | `fly.toml`, `Procfile`, … | deployable evidence |
|
|
98
109
|
| `wrangler` | `wrangler.toml/json` | bindings, crons, service bindings, trigger targets |
|
|
@@ -100,10 +111,207 @@ cannot name the file a fact came from, you cannot add the fact.
|
|
|
100
111
|
| `object-store` | bucket literals | logical-dataset edges, or an ambiguity |
|
|
101
112
|
| `cache` | cache client evidence | cache bindings |
|
|
102
113
|
| `events` | subject literals, declared constants, event-contract files | producers, consumers, reserved subjects |
|
|
114
|
+
| `ansible` | playbooks (YAML lists of plays) | deployable evidence, installed paths and managed services, the DERIVED side of provisioning requirements |
|
|
103
115
|
|
|
104
116
|
`generic` is always on. Everything else is opt-in through `adapters: [...]`, and
|
|
105
117
|
an unknown name is `AGENTDOC_CONFIG`, not a silent no-op.
|
|
106
118
|
|
|
119
|
+
### `github-actions`
|
|
120
|
+
|
|
121
|
+
Recognizable test, lint and build invocations in `run` steps contribute
|
|
122
|
+
checks. The executable and task determine the tier; a shell `test`, a step
|
|
123
|
+
name or text printed by `echo` does not. Turbo (including package-manager
|
|
124
|
+
wrappers), Nx (`run`, `run-many`, `affected`), Make and Just tasks are resolved
|
|
125
|
+
by task name. Multi-task commands contribute a check for each distinct tier.
|
|
126
|
+
Repository scripts invoked directly (`./scripts/test.sh`) or through `bash`,
|
|
127
|
+
`sh`, `node`, `python` or `python3` also contribute checks when their basename,
|
|
128
|
+
without its extension, matches the task vocabulary (`test`, `lint`, `check`,
|
|
129
|
+
`typecheck`, `build`, `e2e`, `integration`, `contract`, etc.). The script must
|
|
130
|
+
resolve to a literal file inside the repository, relative to the current
|
|
131
|
+
step directory. Its path and arguments use the same scope rules as other
|
|
132
|
+
invocations; without component scope it is a repository gate. Scripts with
|
|
133
|
+
other names, such as `deploy.sh`, are ignored. Script contents are not executed
|
|
134
|
+
or interpreted.
|
|
135
|
+
Simple scripts are split into individual commands, never copied wholesale or
|
|
136
|
+
truncated. A literal `cd` updates the directory for following commands in the
|
|
137
|
+
same step, including across lines. Shell control flow, pipelines,
|
|
138
|
+
substitutions and heredocs are not interpreted; a non-literal `cd`, directory
|
|
139
|
+
stack operation, `source`, `eval` or `export` stops extraction for that step.
|
|
140
|
+
|
|
141
|
+
`uses` actions whose names contain lint, test, check, scan or audit also
|
|
142
|
+
contribute checks. Setup, checkout, cache, upload, download and artifact
|
|
143
|
+
actions are excluded. Action scope comes from `with.working-directory`,
|
|
144
|
+
`with.working_directory` or `with.path`; run-step defaults do not apply. The
|
|
145
|
+
action reference is recorded as its command, with the workflow as its evidence.
|
|
146
|
+
|
|
147
|
+
Scope comes from the step's `working-directory` (including job and workflow
|
|
148
|
+
defaults), a component path argument, an explicit package selector, or a
|
|
149
|
+
workflow trigger's `paths` filter with a literal directory prefix. Paths match
|
|
150
|
+
whole segments; a mention in another step cannot scope a check. Turbo filters
|
|
151
|
+
match literal package names or directory paths; Nx project selectors match a
|
|
152
|
+
package name, `project.json` name or component root; Make's `-C` resolves a
|
|
153
|
+
directory relative to the step's working directory. Unscoped checks are
|
|
154
|
+
repository gates. A working directory is retained in the recorded
|
|
155
|
+
command so the check can be run from the repository root.
|
|
156
|
+
|
|
157
|
+
`impact` on a workflow follows its recorded check configuration paths to the
|
|
158
|
+
covered components, which seed the same reverse build/test dependency closure
|
|
159
|
+
as directly changed components. Their own checks precede their dependents'
|
|
160
|
+
checks, with test-only routes contributing only unit checks. Repository gates
|
|
161
|
+
from that file appear in `affectedGates` and are appended after component
|
|
162
|
+
checks in `recommendedVerification`. The combined list is capped at 25;
|
|
163
|
+
`recommendedVerificationTotal` and `recommendedVerificationTruncated` include
|
|
164
|
+
gates. A workflow matched by a check or gate is removed from `unmatchedFiles`.
|
|
165
|
+
|
|
166
|
+
### `ansible`
|
|
167
|
+
|
|
168
|
+
Reads playbooks under a unit root and follows what they reach — plays,
|
|
169
|
+
`roles:`, `include_role`/`import_role`, `include_tasks`/`import_tasks`,
|
|
170
|
+
`import_playbook`, `block`/`rescue`/`always` — inside the repository only.
|
|
171
|
+
Nothing is executed and no Jinja is evaluated.
|
|
172
|
+
|
|
173
|
+
| it derives | from |
|
|
174
|
+
|---|---|
|
|
175
|
+
| an installed path | `copy`/`template`/`get_url`/`git`/`synchronize` `dest`, `unarchive` `dest`/`creates`, `pip` `virtualenv`, `file` with `state: directory\|touch\|link\|hard`, `lineinfile`/`blockinfile` with `create: true`, a command's literal `creates` |
|
|
176
|
+
| a managed service | `systemd`, `systemd_service`, `service` `name` |
|
|
177
|
+
|
|
178
|
+
The inventory lands on the component as `derived.provisioning`. For a normative
|
|
179
|
+
requirement on that component with `satisfiedBy: [ansible]` and an `expects`
|
|
180
|
+
(`installs: <path>` or `service: <name>`), it adds a `DERIVED` fact on the
|
|
181
|
+
requirement key:
|
|
182
|
+
|
|
183
|
+
| value | confidence | when |
|
|
184
|
+
|---|---|---|
|
|
185
|
+
| `provided` | deterministic | a reachable task without `when` installs the path (or a path below it), or manages the service |
|
|
186
|
+
| `provided` | candidate | the only matching task is conditional (`when`, `rescue`, a conditional role or include) |
|
|
187
|
+
| `absent` | deterministic | no reachable task matches **and** every reachable task is transparent |
|
|
188
|
+
| `absent` | candidate | no task matches, but something opaque was reached |
|
|
189
|
+
|
|
190
|
+
**What it cannot see, and therefore never rules out:** a command
|
|
191
|
+
(`shell`/`command`/`script`/`raw`) without a literal `creates`; a module it does
|
|
192
|
+
not model (`apt`, `dnf`, `package`, collections, …); a templated path or a
|
|
193
|
+
`loop`; a role, include or imported playbook that is not in the repository or is
|
|
194
|
+
templated; a file that does not parse. Any of these makes an absence a
|
|
195
|
+
candidate, which is never elected — the requirement stays
|
|
196
|
+
`AGENTDOC_REQUIREMENT_UNVERIFIED` and the diagnostic names what was opaque.
|
|
197
|
+
Inventory files, `group_vars`/`host_vars` and variables are not read.
|
|
198
|
+
|
|
199
|
+
### `rust`
|
|
200
|
+
|
|
201
|
+
Reads `Cargo.toml`. A `[package]` is a unit. A virtual workspace manifest (only
|
|
202
|
+
`[workspace]`) is not. Nothing is executed, and `Cargo.lock` is not read.
|
|
203
|
+
|
|
204
|
+
| it derives | from |
|
|
205
|
+
|---|---|
|
|
206
|
+
| `languages: rust`, `runtimes: rust` | the package manifest |
|
|
207
|
+
| deployable | `[[bin]]`, `src/main.rs`, or a `src/bin/` directory |
|
|
208
|
+
| importable | `[lib]` or `src/lib.rs`; both shapes when both are present |
|
|
209
|
+
| `buildDependsOn` | `[dependencies]`, `[build-dependencies]`, and `[target.<cfg>.dependencies]` / `[target.<cfg>.build-dependencies]`, when the entry is a `path`, `workspace = true` resolved through the nearest `[workspace.dependencies]`, or a `[patch.<registry>]` / `[replace]` path redirect to a sibling inside the repository. A production `use`, `extern crate`, or `<crate>::` path (`-` and `_` are the same ident) adds provenance to that edge; it never creates one |
|
|
210
|
+
| `testDependsOn` | `[dev-dependencies]` and target-specific dev-dependencies, resolved the same way |
|
|
211
|
+
| `hasTests` | a `tests/` directory, or `#[test]` / `#[cfg(test)]` in a `.rs` file |
|
|
212
|
+
| verification | `cargo test -p <name>` (unit) and `cargo clippy -p <name>` (static) |
|
|
213
|
+
|
|
214
|
+
`-p <name>` is the whole scope of the recorded command. Cargo, run at a virtual
|
|
215
|
+
workspace root, has no current package; `-p` is what makes the command mean
|
|
216
|
+
this crate rather than every member. `configPaths` is that crate's
|
|
217
|
+
`Cargo.toml`.
|
|
218
|
+
|
|
219
|
+
Workspace roots come from every `Cargo.toml` that has `[workspace]`, not only
|
|
220
|
+
the one at the repository root. The search is bounded to five directories
|
|
221
|
+
down, stays inside the repository, and does not enter `discovery.notUnitRoots`
|
|
222
|
+
or their descendants (the authored-descriptor exception is described below),
|
|
223
|
+
`discovery.generatedDirs`, dot-directories, or `test` / `tests` / `examples` /
|
|
224
|
+
`example`. `members` minus `exclude` are still relative to the manifest that
|
|
225
|
+
declares them; `*` matches one path segment, and a member that leaves the
|
|
226
|
+
repository is ignored. `workspace = true` resolves against the nearest
|
|
227
|
+
enclosing workspace. A virtual manifest (no `[package]`) is not a unit and is
|
|
228
|
+
not scaffolded. A manifest that has both `[package]` and `[workspace]` is a
|
|
229
|
+
unit, the same as any other package. Scaffold types a crate from its shape: deployable-only
|
|
230
|
+
(`[[bin]]`, `src/main.rs`, `src/bin/`) is `service`, importable-only is
|
|
231
|
+
`library`, and a crate that is both follows the usual rule (deployable wins,
|
|
232
|
+
so `service`).
|
|
233
|
+
|
|
234
|
+
The manifest route and a corroborating import share the target crate's
|
|
235
|
+
package name as their edge key, so one dependency is one edge. A rename
|
|
236
|
+
(`package = "…"`) is the crates.io name; the `use` path is the table key.
|
|
237
|
+
`[patch.<registry>]` and `[replace]` contribute only when the value is a
|
|
238
|
+
`path` that stays inside the repository and the package is already a
|
|
239
|
+
dependency. A path and a patch that name two different siblings is
|
|
240
|
+
`AGENTDOC_BINDING_AMBIGUOUS` and no edge is created.
|
|
241
|
+
|
|
242
|
+
**What it cannot see, and therefore never invents:** a dependency that exists
|
|
243
|
+
only as a `use`, `extern crate`, or `<crate>::` path. Rust will not link a
|
|
244
|
+
crate the manifest does not declare, and a local module (`mod engine;
|
|
245
|
+
engine::run()`) is the same spelling as a crate path, so an import that the
|
|
246
|
+
manifest did not already resolve creates no edge. An import whose ident
|
|
247
|
+
matches two sibling crates (`foo-bar` and `foo_bar` are both `foo_bar`) is
|
|
248
|
+
`AGENTDOC_BINDING_AMBIGUOUS` and still creates no edge. Also invisible: a
|
|
249
|
+
`Cargo.lock` resolution or any version requirement that merely shares a name
|
|
250
|
+
with a sibling; a workspace member outside the repository; a workspace
|
|
251
|
+
manifest deeper than the search bound; a `#[cfg(test)]` or `#[test]` item,
|
|
252
|
+
which is not a production import; a duplicate package name, which is not
|
|
253
|
+
elected either. A `Cargo.toml` this TOML reader rejects yields
|
|
254
|
+
`AGENTDOC_YAML_PARSE` and no dependency edges. The unit is still recognised when a `[package]` header is present, so
|
|
255
|
+
a parse failure is not an empty unit and not a crash. Char literals and
|
|
256
|
+
lifetimes are not strings: a lifetime does not hide the imports after it, and
|
|
257
|
+
a `"` string that spans lines does not leak the idents inside it.
|
|
258
|
+
|
|
259
|
+
### `python`
|
|
260
|
+
|
|
261
|
+
Reads a unit's Python manifest and its `import` / `from` statements. It does
|
|
262
|
+
not run Python, resolve a lockfile, or inspect a virtualenv.
|
|
263
|
+
|
|
264
|
+
| it derives | from |
|
|
265
|
+
|---|---|
|
|
266
|
+
| deployable | `[project.scripts]`, `[project.gui-scripts]`, `[tool.poetry.scripts]`, a `console_scripts` entry point, `__main__.py`, `manage.py`, or an ASGI/WSGI app object (`app` / `application` assigned from `FastAPI`, `Flask`, `Starlette`, `Litestar`, `Sanic` or `Quart`, or a call to `get_asgi_application` / `get_wsgi_application`) |
|
|
267
|
+
| importable | a build backend (`[build-system] build-backend`, or `setup.py` / `setup.cfg`) and a package |
|
|
268
|
+
| the import name | an explicit package list (`[tool.setuptools] packages`, `[tool.poetry] packages`, `[tool.hatch.build.targets.wheel] packages`); otherwise the distribution name with `-` turned into `_` when that directory exists; otherwise the only package directory |
|
|
269
|
+
| `buildDependsOn` | `[project] dependencies`, `[tool.uv.sources]` (`path`, or `workspace = true` resolved against the nearest enclosing uv workspace), Poetry `path`, `-e <dir>` in a production `requirements*.txt`, or a production `import` / `from` of a sibling's import name |
|
|
270
|
+
| `testDependsOn` | `[dependency-groups]`, `[project.optional-dependencies]` groups named dev/test/lint/type, `[tool.poetry.group.*]`, or a requirements file whose name contains `dev` or `test` |
|
|
271
|
+
| `languages` / `runtimes` | the manifest. `requiresPython` only when `requires-python`, `python_requires`, or Poetry's `python` dependency is written down |
|
|
272
|
+
| `pytest` | a pytest dependency or group, `[tool.pytest.ini_options]`, `pytest.ini`, or `conftest.py` |
|
|
273
|
+
| `python -m unittest discover` | test modules that import `unittest`, and only when nothing above proves pytest |
|
|
274
|
+
| `ruff check` / `mypy` | the tool declared as a dependency or configured (`[tool.ruff]`, `ruff.toml`, `[tool.mypy]`, `mypy.ini`) |
|
|
275
|
+
|
|
276
|
+
`uv run` or `poetry run` is prefixed only when that lockfile contains a
|
|
277
|
+
`name = "<tool>"` entry. Both lockfiles proving the same tool is ambiguous:
|
|
278
|
+
the command is left unprefixed. PEP 508 extras, versions and markers are
|
|
279
|
+
parsed and not evaluated. Two import packages and no explicit list, or two
|
|
280
|
+
units publishing the same distribution or import name, produce
|
|
281
|
+
`AGENTDOC_BINDING_AMBIGUOUS` and no cross-unit link.
|
|
282
|
+
|
|
283
|
+
An import under `if TYPE_CHECKING:` is still an import. The adapter does not
|
|
284
|
+
evaluate control flow, so the name is classified like any other import:
|
|
285
|
+
`buildDependsOn` when it resolves to a sibling, or `testDependsOn` when the
|
|
286
|
+
manifest puts that distribution in a dev group. It is not a separate edge.
|
|
287
|
+
|
|
288
|
+
A uv workspace manifest is read at the repository root and below it, to a
|
|
289
|
+
fixed depth, in path order, staying inside the repository. `notUnitRoots`, their
|
|
290
|
+
descendants, and generated directories are not searched; the authored-descriptor
|
|
291
|
+
exception is described below. `workspace = true` names the member of
|
|
292
|
+
the nearest enclosing workspace whose distribution name matches; another unit
|
|
293
|
+
with the same name is not substituted. Every declared member that has a Python
|
|
294
|
+
manifest is a unit, including one with no build backend and no entrypoint.
|
|
295
|
+
Its shape is still only the evidence, so scaffold writes `other` when the
|
|
296
|
+
manifest is neither deployable nor importable. A manifest that only declares
|
|
297
|
+
the workspace, with no distribution of its own, is not a unit.
|
|
298
|
+
|
|
299
|
+
A `.py` file uses the shared source inventory and is indexed for the deepest
|
|
300
|
+
eligible unit that contains it. Package, entrypoint and test discovery use the
|
|
301
|
+
same ownership boundaries; workspace-member discovery remains repository-wide. A
|
|
302
|
+
parent unit does not gain an import edge from a file that lives in a nested
|
|
303
|
+
member.
|
|
304
|
+
|
|
305
|
+
An import is not evidence of a sibling when the importing unit itself provides
|
|
306
|
+
that top-level module or package — at the unit root, under `src/`, or in the
|
|
307
|
+
importing file's own directory. If a sibling publishes the same import name,
|
|
308
|
+
the result is `AGENTDOC_BINDING_AMBIGUOUS` and no edge.
|
|
309
|
+
|
|
310
|
+
**What it cannot see:** a namespace package with no `__init__.py`; a
|
|
311
|
+
`setup.py` dependency that is not a list of string literals; a `requirements`
|
|
312
|
+
file pulled in with `-r` / `-c`; a lockfile's resolved versions; a PDM
|
|
313
|
+
workspace; a workspace manifest deeper than the search bound.
|
|
314
|
+
|
|
107
315
|
`asyncapi` is a contract **type** (declared on an API descriptor, validated by
|
|
108
316
|
the contract layer), not an adapter — there is no `asyncapi` entry in
|
|
109
317
|
`adapters: [...]`.
|
|
@@ -151,16 +359,33 @@ vocabulary. It does, however, know the shape of a manifest filename in three
|
|
|
151
359
|
places, and those are the honest exceptions worth naming:
|
|
152
360
|
|
|
153
361
|
- `core/compile.mjs` builds a manifest pre-pass over `package.json`, `go.mod`
|
|
154
|
-
and `go.work`,
|
|
362
|
+
and `go.work`, and, when the `rust` adapter is enabled, over `Cargo.toml`.
|
|
363
|
+
`unitByPkgName`, `unitByGoModule`, `unitByCrateName` and
|
|
155
364
|
`transitiveDependencies` are available to every adapter regardless of
|
|
156
|
-
execution order.
|
|
365
|
+
execution order. Cargo is probed only when `rust` is enabled: an existence
|
|
366
|
+
probe is part of the input hash, and probing `Cargo.toml` in every unit
|
|
367
|
+
would change every graph that does not ask for it.
|
|
368
|
+
- The same pre-pass reads a Python manifest (`pyproject.toml`, otherwise
|
|
369
|
+
`setup.cfg` / `setup.py` / `requirements*.txt`) into `unitByPythonDist` and
|
|
370
|
+
`unitByPythonImport`, and feeds those siblings into `dependencyMap` and
|
|
371
|
+
`productionDependencies`, only when the `python` adapter is enabled. Each
|
|
372
|
+
unit root is then listed so `requirements*.txt` is visible; that listing is
|
|
373
|
+
part of the input hash. A repository that does not enable `python` is not
|
|
374
|
+
probed, and its graph does not change.
|
|
157
375
|
- `core/impact.mjs` classifies a changed file by consulting the compiled graph —
|
|
158
376
|
its contracts, its provenance paths, its extractor identities — rather than a
|
|
159
377
|
hand-written list of technology filenames. A list would silently under-report
|
|
160
378
|
for every repository that is not Node-and-Go.
|
|
161
|
-
- `core/discover.mjs`
|
|
162
|
-
|
|
163
|
-
|
|
379
|
+
- `core/discover.mjs` excludes `agentdoc`, `docs`, `scripts`, `node_modules`, and
|
|
380
|
+
`.github` by default. `discovery.notUnitRoots` replaces that list (`[]`
|
|
381
|
+
disables it). These roots and their descendants cannot be inferred from
|
|
382
|
+
adapter markers, adapter `roots()`, or supplemental roots, and scaffold never
|
|
383
|
+
proposes or writes descriptors there in dry run or `--write`. An existing
|
|
384
|
+
authored descriptor strictly below an excluded root still claims a unit and
|
|
385
|
+
is preserved; the adapter must corroborate its artifact type at that unit's
|
|
386
|
+
own root as usual. A descriptor exactly at an excluded root is refused with
|
|
387
|
+
`AGENTDOC_COMPONENT_UNCORROBORATED` naming `notUnitRoots` and asking the author
|
|
388
|
+
to remove the exclusion or move the descriptor.
|
|
164
389
|
|
|
165
390
|
Each is a place a future change should push outward, not a licence to add more.
|
|
166
391
|
|
package/docs/AUTHORITY.md
CHANGED
|
@@ -175,7 +175,16 @@ For a group of assertions on one `(subject, key)`:
|
|
|
175
175
|
- `recency` — only when the rule names `OBSERVED_RUNTIME` and more than one
|
|
176
176
|
dated observation exists. The newest wins, and the rule is cited.
|
|
177
177
|
- otherwise `basis: none`, status `unresolved`, and an **error**.
|
|
178
|
-
3.
|
|
178
|
+
3. **Normative requirements are never elected on their own word.** An
|
|
179
|
+
assertion from a component's `spec.requirements` (`requirement.*` keys) is a
|
|
180
|
+
claim about what the implementation *must* do:
|
|
181
|
+
- alone on its key it stays `unresolved` (`AGENTDOC_REQUIREMENT_UNVERIFIED`);
|
|
182
|
+
- with agreeing implementation evidence it is corroborated and `elected`;
|
|
183
|
+
- with disagreeing evidence **no basis is attempted** — not even a
|
|
184
|
+
`reviewed-override` rule. Electing the implementation would waive the
|
|
185
|
+
specification; electing the requirement would hide the missing
|
|
186
|
+
implementation. The conflict is an error until one of them changes.
|
|
187
|
+
4. Every non-elected assertion is kept with `status: contradicted` (or
|
|
179
188
|
`candidate`). **The contradicted value stays in the graph.** A system that
|
|
180
189
|
discards the repository's own claim cannot explain the divergence to a human.
|
|
181
190
|
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# BENCHMARK
|
|
2
|
+
|
|
3
|
+
Two measurements back the numbers in the README. Both are reproducible from a
|
|
4
|
+
checkout. Neither involves a model, so phrasing cannot move them.
|
|
5
|
+
|
|
6
|
+
## Routing quality: `node evals/run-all.mjs`
|
|
7
|
+
|
|
8
|
+
The routing evaluation is described in [EVALS.md](EVALS.md). It has 30 scenarios
|
|
9
|
+
on six repositories (Node, TypeScript, Go, Rust and Python), with thresholds
|
|
10
|
+
registered on 2026-09-28 and not moved since. For each scenario, it compares
|
|
11
|
+
the context `agentdoc query` + `agentdoc impact` returns with what an agent
|
|
12
|
+
gets by reading only the component it is changing.
|
|
13
|
+
|
|
14
|
+
| | reading the touched component | AgentDoc |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| facts the change needs, retrieved | 58% | **100%** |
|
|
17
|
+
| retrieved facts that are unrelated (noise) | 40% | **8.7%** |
|
|
18
|
+
| share of the repository's checks returned (selectivity) | 100% | **46%** (29% on the golden corpus) |
|
|
19
|
+
| context size vs. reading the whole catalog | — | **−70%** |
|
|
20
|
+
|
|
21
|
+
Every check a scenario requires is in AgentDoc's answer (verification recall
|
|
22
|
+
1.0). The baseline never misses one either, because it runs every check in the
|
|
23
|
+
repository. Selectivity is therefore the meaningful comparison: the share of
|
|
24
|
+
the repository's checks the answer contains, counting everything the agent is
|
|
25
|
+
shown. It is reported, not gated; small corpora inflate it, and a
|
|
26
|
+
one-component corpus scores 100% because there is nothing to narrow.
|
|
27
|
+
|
|
28
|
+
The size reduction is measured on the golden corpus (`examples/koda`). The
|
|
29
|
+
smaller fixtures hold fewer than 100 facts, so the harness reports their
|
|
30
|
+
reduction but does not aggregate it.
|
|
31
|
+
|
|
32
|
+
## Fresh setup on public repositories: `node scripts/bench/run.mjs`
|
|
33
|
+
|
|
34
|
+
[`scripts/bench/run.mjs`](../scripts/bench/run.mjs) clones each repository in
|
|
35
|
+
[`repos.json`](../scripts/bench/repos.json) at a pinned commit, then does the
|
|
36
|
+
following:
|
|
37
|
+
|
|
38
|
+
1. Runs `agentdoc init` and `agentdoc scaffold --write`.
|
|
39
|
+
2. Fills in the one line AgentDoc refuses to decide: each component's placement.
|
|
40
|
+
3. Counts every other edit a human would need before the catalog validates. That
|
|
41
|
+
number is the "setup ok" column, and the target is zero.
|
|
42
|
+
4. Compiles three times, and checks that the graph is byte-identical.
|
|
43
|
+
5. For each component with a matching file, samples the first tracked source
|
|
44
|
+
file whose path does not contain `test` (benchmarks and examples may be
|
|
45
|
+
included). It measures the `agentdoc query` answer, at about 4 characters per
|
|
46
|
+
token, and the `agentdoc impact` result.
|
|
47
|
+
|
|
48
|
+
Measured with AgentDoc 1.2.0 on Node 24, on a 2019 Intel Core i9 laptop (load average about 4):
|
|
49
|
+
|
|
50
|
+
| repository | files | setup ok | components | dependency edges | checks | init + scaffold + median compile | median compile | deterministic | `query` answer, median / max |
|
|
51
|
+
|---|---|---|---|---|---|---|---|---|---|
|
|
52
|
+
| [tokio-rs/axum](https://github.com/tokio-rs/axum) @ 86aa615 (Rust) | 505 | yes | 4 | 11 | 9 | 1.0 s | 0.5 s | yes | ~151 / 153 tokens |
|
|
53
|
+
| [pydantic/pydantic-ai](https://github.com/pydantic/pydantic-ai) @ 5a4d576 (Python, TS) | 5,142 | yes | 8 | 9 | 5 | 4.6 s | 1.9 s | yes | ~112 / 144 tokens |
|
|
54
|
+
| [fastapi/full-stack-fastapi-template](https://github.com/fastapi/full-stack-fastapi-template) @ f4bcfab (Python, TS) | 252 | yes | 3 | 0 | 9 | 1.0 s | 0.4 s | yes | ~100 / 126 tokens |
|
|
55
|
+
| [t3-oss/create-t3-turbo](https://github.com/t3-oss/create-t3-turbo) @ 8f945b7 (TypeScript) | 141 | yes | 13 | 47 | 25 | 1.0 s | 0.4 s | yes | ~158 / 263 tokens |
|
|
56
|
+
|
|
57
|
+
Timings depend on the machine and its load, so run the script yourself. The
|
|
58
|
+
other columns are deterministic for a given AgentDoc version and commit.
|
|
59
|
+
|
|
60
|
+
### What these numbers do not say
|
|
61
|
+
|
|
62
|
+
- A `query` answer is a map of what to read, what the change reaches, and which
|
|
63
|
+
checks to run. It does not replace the code, so its size is not a "tokens
|
|
64
|
+
saved" figure.
|
|
65
|
+
- "Checks" counts the commands AgentDoc can prove from the repository. For
|
|
66
|
+
example, pydantic-ai's tests live outside the package roots, so AgentDoc
|
|
67
|
+
records none for those packages rather than guess one.
|
|
68
|
+
- Four repositories are a smoke test of the setup path, not a survey.
|
package/docs/CI.md
CHANGED
|
@@ -20,13 +20,15 @@ jobs:
|
|
|
20
20
|
with: { fetch-depth: 0 }
|
|
21
21
|
- uses: actions/setup-node@v4
|
|
22
22
|
with: { node-version: '24' }
|
|
23
|
-
# Pin a tag for reproducibility, e.g. github:lbframe/agent-doc-system#v1.
|
|
23
|
+
# Pin a tag for reproducibility, e.g. github:lbframe/agent-doc-system#v1.2.0 —
|
|
24
24
|
# a compiler upgrade intentionally invalidates every committed graph.
|
|
25
25
|
- run: npm install -g github:lbframe/agent-doc-system
|
|
26
26
|
- run: agentdoc validate
|
|
27
27
|
- run: agentdoc compile
|
|
28
28
|
- run: agentdoc check
|
|
29
29
|
- run: agentdoc check --require-clean
|
|
30
|
+
# Once MIGRATE is done: no unaccepted warning may remain.
|
|
31
|
+
- run: agentdoc check --strict
|
|
30
32
|
- run: agentdoc eval routing
|
|
31
33
|
```
|
|
32
34
|
|
package/docs/EVALS.md
CHANGED
|
@@ -30,11 +30,35 @@ is deterministic and cannot be moved by phrasing.
|
|
|
30
30
|
|---|---|
|
|
31
31
|
| recall | fraction of the scenario's ground-truth facts the catalog retrieved |
|
|
32
32
|
| critical recall | the same, restricted to critical context: constraints, conflicts, observations, resources, API boundaries, event subjects |
|
|
33
|
-
| verification recall | fraction of the
|
|
33
|
+
| verification recall | fraction of the scenario's verification expectations returned; 1 when there are no expectations, for both catalog and baseline |
|
|
34
|
+
| check selectivity | distinct recommended check IDs / distinct check IDs in the repository graph (`verification` + `gates`); reported only, not gated; lower means fewer checks recommended |
|
|
34
35
|
| precision | `1 - irrelevance` |
|
|
35
36
|
| irrelevance (noise) | fraction of retrieved facts outside the graph's one-hop closure of the touched entities |
|
|
36
37
|
| retrieval reduction | `1 - catalog facts / baseline-full facts` |
|
|
37
38
|
|
|
39
|
+
Scenario verification expectations accept `verify:<command>` and
|
|
40
|
+
`verify-id:<check-id>`. Use check IDs when multiple components have the same
|
|
41
|
+
command (for example `go test ./...`), so the library's own check cannot stand in
|
|
42
|
+
for a dependent's. Retrieved context includes the entity refs already returned
|
|
43
|
+
in query's neighbour summaries, even when those neighbours are dependencies and
|
|
44
|
+
therefore absent from impact's affected components.
|
|
45
|
+
|
|
46
|
+
Check selectivity counts the union of checks returned by queries for touched
|
|
47
|
+
and impact-affected entities (`verification.items` and `globalGates`), plus
|
|
48
|
+
impact's `recommendedVerification`. It measures the returned lists, respecting
|
|
49
|
+
their output caps. IDs deduplicate repeated recommendations while preserving
|
|
50
|
+
separate scoped checks that happen to share a command. With no checks in the
|
|
51
|
+
graph, selectivity is 1 (there is nothing to narrow). Corpus values are scenario
|
|
52
|
+
means; the aggregate is scenario-weighted across corpora. Both CLI reports
|
|
53
|
+
include per-scenario values in their `--json` output.
|
|
54
|
+
|
|
55
|
+
Baseline verification recall is 1 by construction: its verification strategy
|
|
56
|
+
runs every graph verification entry and repository gate, so it cannot miss a
|
|
57
|
+
registered expectation. Empty expectations also score 1 on both sides. Its
|
|
58
|
+
check selectivity is therefore 1. Selectivity is the meaningful comparison of
|
|
59
|
+
how much routing narrows the check set, read alongside catalog verification
|
|
60
|
+
recall so that omitting a required check is not mistaken for an improvement.
|
|
61
|
+
|
|
38
62
|
### Why noise is measured against reachability, not against the truth set
|
|
39
63
|
|
|
40
64
|
The first definition of noise was the complement of truth recall. It is
|
|
@@ -101,6 +125,8 @@ Two additional gates use the same numbers:
|
|
|
101
125
|
| `fixtures/a-node-ts-postgres` | 3 | single Node/TypeScript service, REST, Postgres, GitHub Actions |
|
|
102
126
|
| `fixtures/b-go-multi-service` | 4 | multi-service Go, protobuf contracts, shared library, resources |
|
|
103
127
|
| `fixtures/c-alt-monorepo` | 4 | a layout that is deliberately not `apps`+`packages`+`workers`, mixed runtimes, inconsistent pre-existing documentation |
|
|
128
|
+
| `fixtures/e-rust-workspace` | 4 | Cargo workspace, shared crate and its dependent, member manifest, local module, ambiguous crate names |
|
|
129
|
+
| `fixtures/f-python-workspace` | 6 | uv workspace, shared library and its dependent, member manifest, shadowed import, nested workspace, Alembic database, unittest |
|
|
104
130
|
|
|
105
131
|
Scenarios are repository-scoped: a scenario only runs against the corpus it was
|
|
106
132
|
written for, declared by a `repository` tag in a `.agentdoc-fixture.json` at the
|
|
@@ -117,7 +143,12 @@ cron; debug a production mismatch.
|
|
|
117
143
|
The synthetic fixtures add: change an API contract; change a write path; change
|
|
118
144
|
the only-writer rule; break an end-to-end journey; change an edge worker's flush
|
|
119
145
|
schedule; follow stale documentation while debugging; change a subject vocabulary
|
|
120
|
-
shared across runtimes; add an operation to a contract.
|
|
146
|
+
shared across runtimes; add an operation to a contract. The Rust workspace adds
|
|
147
|
+
a shared crate, the manifest that declares its dependents, a local module that
|
|
148
|
+
shares a name with another crate, and a hyphenated crate beside its underscored
|
|
149
|
+
twin. The Python workspace adds a shared library, a service manifest, an import
|
|
150
|
+
shadowed by a local module, a nested workspace member, an Alembic migration
|
|
151
|
+
bound to its database, and a job whose check is `python -m unittest discover`.
|
|
121
152
|
|
|
122
153
|
## Running it
|
|
123
154
|
|
package/docs/MIGRATION.md
CHANGED
|
@@ -41,6 +41,7 @@ independently:
|
|
|
41
41
|
"counts": { "CONFIRMED": 4, "DERIVED": 38 },
|
|
42
42
|
"contradictions": [ ... ],
|
|
43
43
|
"documentationContradictions": [ ... ],
|
|
44
|
+
"normative": { "sections": [ { "path", "section", "heading", "sha256", "coveredBy" } ], "uncovered": [ ... ], "requirements": [ ... ] },
|
|
44
45
|
"reviewedAmbiguity": [ ... ],
|
|
45
46
|
"documentation": { "orphanDocs", "undocumentedComponents", "unverifiedComponents" },
|
|
46
47
|
"contracts": { "inventory", "unclaimed" },
|
|
@@ -77,6 +78,64 @@ be checked at all.
|
|
|
77
78
|
The rule for extending this: only check vocabulary the graph owns. A check that
|
|
78
79
|
guesses is a check that cries wolf.
|
|
79
80
|
|
|
81
|
+
**These are the only automatic documentation checks.** The audit does not read
|
|
82
|
+
prose for meaning, so it does not find where an arbitrary sentence contradicts
|
|
83
|
+
the code. A specification saying "the verifier runtime is installed on the
|
|
84
|
+
production host" is invisible to it until someone turns that sentence into a
|
|
85
|
+
requirement — which is what the next section makes mandatory.
|
|
86
|
+
|
|
87
|
+
### Normative requirements
|
|
88
|
+
|
|
89
|
+
A specification that is linked to a component is *routed*; that says nothing
|
|
90
|
+
about whether anyone checked the implementation against it. List the documents
|
|
91
|
+
that state obligations in `docs.normative`:
|
|
92
|
+
|
|
93
|
+
```yaml
|
|
94
|
+
docs:
|
|
95
|
+
normative:
|
|
96
|
+
- specs/**
|
|
97
|
+
- verification_layer/*_PROFILE.md
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Every level-2 (`##`) section of those documents is then pinned by digest and
|
|
101
|
+
must be accounted for in one of two ways:
|
|
102
|
+
|
|
103
|
+
- **a requirement** on the component that must fulfil it, citing the section:
|
|
104
|
+
|
|
105
|
+
```yaml
|
|
106
|
+
# provisioning/agentdoc.yaml
|
|
107
|
+
spec:
|
|
108
|
+
requirements:
|
|
109
|
+
- id: verification-runtime-on-host
|
|
110
|
+
key: requirement.provides.verification-runtime
|
|
111
|
+
value: provided
|
|
112
|
+
source:
|
|
113
|
+
path: specs/EXECUTION_LAYER_SPEC.md
|
|
114
|
+
section: 13-host-configuration
|
|
115
|
+
sha256: <digest from `agentdoc audit` → normative.sections>
|
|
116
|
+
satisfiedBy: [ansible]
|
|
117
|
+
expects:
|
|
118
|
+
installs: /var/lib/agent-platform-runtime/verification-python-v1
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
- **an attestation** in `normativeCoverage` that the section carries no
|
|
122
|
+
implementation obligation (`disposition: no-implementation-obligation` or
|
|
123
|
+
`informative`), with a reason and a review condition.
|
|
124
|
+
|
|
125
|
+
A section that is neither raises `AGENTDOC_NORMATIVE_UNCOVERED`. A requirement
|
|
126
|
+
is an `AUTHORED` fact that can only be *corroborated*: until implementation
|
|
127
|
+
evidence on the same key agrees with it — a `DERIVED` fact from an adapter
|
|
128
|
+
named in `satisfiedBy` that finds what `expects` names (see `ADAPTERS.md`,
|
|
129
|
+
`ansible`), or a
|
|
130
|
+
`requirement-satisfaction` reviewed override citing the implementation — it is
|
|
131
|
+
`UNRESOLVED` and raises `AGENTDOC_REQUIREMENT_UNVERIFIED`, naming the adapter in
|
|
132
|
+
`satisfiedBy` that is missing. Implementation evidence that disagrees is a
|
|
133
|
+
conflict no authority rule may settle (see `AUTHORITY.md`). Editing a cited
|
|
134
|
+
section invalidates its requirement or attestation
|
|
135
|
+
(`AGENTDOC_NORMATIVE_SOURCE_STALE`): the review has to be redone.
|
|
136
|
+
|
|
137
|
+
A missing adapter lowers coverage; it never makes an obligation disappear.
|
|
138
|
+
|
|
80
139
|
### Reviewed ambiguity
|
|
81
140
|
|
|
82
141
|
The list a human must work through:
|
|
@@ -88,6 +147,8 @@ The list a human must work through:
|
|
|
88
147
|
| `UNCLAIMED_CONTRACT` | which API owns this contract, or is it dead? |
|
|
89
148
|
| `REVIEWED_OVERRIDE` | is this interpretation still true? |
|
|
90
149
|
| `NEGATED_COMPONENT`, `PORT_MISMATCH`, `UNLINKED_PORT_CLAIM` | which source is right? |
|
|
150
|
+
| `NORMATIVE_UNCOVERED` | what does this section oblige, and which component must do it? |
|
|
151
|
+
| `REQUIREMENT_UNVERIFIED` | where is the implementation — or is this a gap to fix before release? |
|
|
91
152
|
|
|
92
153
|
## CREATE
|
|
93
154
|
|
|
@@ -132,16 +193,21 @@ agentdoc audit > migration-report.json
|
|
|
132
193
|
|
|
133
194
|
Then, in order:
|
|
134
195
|
|
|
135
|
-
1. **Source-of-truth mapping.**
|
|
136
|
-
|
|
137
|
-
|
|
196
|
+
1. **Source-of-truth mapping.** Configure `docs.normative`, then work
|
|
197
|
+
`normative.uncovered`: every section of every normative document becomes a
|
|
198
|
+
component requirement or a reviewed attestation. Prove each requirement
|
|
199
|
+
with implementation evidence, or leave it `REQUIREMENT_UNVERIFIED` for a
|
|
200
|
+
human. For other major claims, record which of the four inventories
|
|
201
|
+
supports them; anything supported by none goes to `reviewedAmbiguity`.
|
|
138
202
|
2. **Contradiction detection.** Work `contradictions` and
|
|
139
203
|
`documentationContradictions`. Each one needs a human decision: fix the
|
|
140
204
|
documentation, fix the code, or record an authority rule saying which class
|
|
141
205
|
wins for that key.
|
|
142
206
|
3. **Orphan documentation.** `documentation.orphanDocs`. For each: link it to a
|
|
143
|
-
|
|
144
|
-
|
|
207
|
+
Component, Resource or System via `context.docs`, `context.constraints` or
|
|
208
|
+
`context.runbooks`, or delete it. Conventional component documents and
|
|
209
|
+
configured repository-wide roles also count as routed. An orphan is a
|
|
210
|
+
document nothing will ever route to.
|
|
145
211
|
4. **Missing documentation.** `documentation.undocumentedComponents` and
|
|
146
212
|
`documentation.unverifiedComponents`. These are the components an agent will
|
|
147
213
|
get wrong.
|
|
@@ -152,7 +218,11 @@ Then, in order:
|
|
|
152
218
|
from a human everywhere else.
|
|
153
219
|
7. **Catalog proposal.** `scaffold` lists what it would write.
|
|
154
220
|
8. **Migration.** `scaffold --write`, then review every generated file.
|
|
155
|
-
9. **Validation.** `validate` → `compile` → `check`.
|
|
221
|
+
9. **Validation.** `validate` → `compile` → `check --strict`. The strict gate
|
|
222
|
+
fails on every warning not accepted with pinned evidence, so a migration
|
|
223
|
+
cannot finish with an unreviewed normative section or an unproven
|
|
224
|
+
requirement. A known gap is accepted explicitly (`warningAcceptances`) and
|
|
225
|
+
stays `UNRESOLVED` in the audit.
|
|
156
226
|
|
|
157
227
|
### Do not trust the documentation
|
|
158
228
|
|
package/docs/QUERY.md
CHANGED
|
@@ -84,6 +84,17 @@ withheld.
|
|
|
84
84
|
endpoint is proved by running their suites, so `verification` for an API subject
|
|
85
85
|
is the union over the provider and its consumers.
|
|
86
86
|
|
|
87
|
+
**A component change carries its dependents' checks.** Verification follows the
|
|
88
|
+
reverse `buildDependsOn` / `testDependsOn` closure (including their inverse
|
|
89
|
+
`buildDependencyOf` / `testDependencyOf` spellings). Build dependents contribute
|
|
90
|
+
all tiers; a route containing a test dependency contributes only `unit` checks.
|
|
91
|
+
If an all-build route also reaches that dependent, all tiers apply. Cycles are
|
|
92
|
+
visited safely. The subject's own checks come first, then the dependents', with
|
|
93
|
+
each group sorted by check ID. A check shared by multiple components appears
|
|
94
|
+
once by ID; identical command text in different component checks remains scoped
|
|
95
|
+
by its ID and `configPaths`. The usual verification budget and truncation fields
|
|
96
|
+
apply to the combined list.
|
|
97
|
+
|
|
87
98
|
**Journey peers are named.** If a component appears in a journey, the other
|
|
88
99
|
components in that journey are in scope and are listed explicitly rather than
|
|
89
100
|
left for the agent to rediscover.
|
|
@@ -127,9 +138,25 @@ the slice is never mistaken for the whole.
|
|
|
127
138
|
| assertions | 25 |
|
|
128
139
|
| provenance | 20 |
|
|
129
140
|
| contracts | 10 |
|
|
141
|
+
| docs (markdown) | 12 |
|
|
142
|
+
| constraints (markdown) | uncapped |
|
|
143
|
+
| runbooks (markdown) | 12 |
|
|
130
144
|
|
|
131
145
|
## Markdown rendering
|
|
132
146
|
|
|
147
|
+
Component, Resource and System descriptors may carry `spec.context`. Their
|
|
148
|
+
documentation, constraints and runbooks appear under `docs`, `CONSTRAINTS` and
|
|
149
|
+
`runbooks`, respectively. Components also include conventional files discovered
|
|
150
|
+
in their source root. API and Domain schemas do not allow `context`.
|
|
151
|
+
|
|
152
|
+
Markdown docs and runbooks default to 12 paths each. Constraints are uncapped by
|
|
153
|
+
default so critical routing context is preserved. Set an explicit cap with, for
|
|
154
|
+
example, `--budget docs=1,constraints=5,runbooks=1`. A shortened line ends with
|
|
155
|
+
`[truncated: 1 of 2]`, reporting the number shown and the total. JSON retains the
|
|
156
|
+
complete arrays under `constraints.docs`, `constraints.constraints` and
|
|
157
|
+
`constraints.runbooks`; these markdown-only caps do not shorten the JSON arrays
|
|
158
|
+
or `entity.spec.context`.
|
|
159
|
+
|
|
133
160
|
`--md` (the default) produces a compact block suitable for a prompt or a human:
|
|
134
161
|
|
|
135
162
|
```
|
|
@@ -164,10 +191,32 @@ contracts, documentation, resources, verification and catalog sources; whether
|
|
|
164
191
|
the graph will be invalidated; the recommended verification commands; any open
|
|
165
192
|
conflicts on the affected subjects; and related journeys.
|
|
166
193
|
|
|
167
|
-
Reachability rules: a contract change reaches its provider and every consumer;
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
194
|
+
Reachability rules: a contract change reaches its provider and every consumer;
|
|
195
|
+
a Resource change reaches components bound to that exact Resource. A migration
|
|
196
|
+
change (including Alembic `alembic/versions`) reports its changed path and the
|
|
197
|
+
logical databases bound to its enclosing component through existing
|
|
198
|
+
`usesResource` / `resourceUsedBy` relations. Migration authority alone never
|
|
199
|
+
establishes ownership or invents a Resource binding.
|
|
200
|
+
|
|
201
|
+
A component change reaches its reverse build/test dependency closure, plus
|
|
202
|
+
direct runtime-call and schedule peers. Dependencies are not affected just
|
|
203
|
+
because the changed component uses them; they remain explicitly typed context
|
|
204
|
+
in query's `relations`. The dependent closure has no hop cutoff, so a long chain
|
|
205
|
+
cannot silently omit an affected consumer.
|
|
206
|
+
|
|
207
|
+
Changing a workflow file follows recorded verification `configPaths` to the
|
|
208
|
+
components its checks cover. Those components seed the reverse build/test
|
|
209
|
+
dependency closure just like directly changed components. Matching repository
|
|
210
|
+
gates appear in `affectedGates`; a workflow matched by any check or gate is
|
|
211
|
+
removed from `unmatchedFiles`.
|
|
212
|
+
|
|
213
|
+
Impact uses the same verification selection and ordering as query, including
|
|
214
|
+
the test-only tier restriction. Directly affected components' checks precede
|
|
215
|
+
their dependents' checks, followed by the matching repository gates. The
|
|
216
|
+
combined `recommendedVerification` array is capped at 25;
|
|
217
|
+
`recommendedVerificationTotal` gives the uncapped count including gates and
|
|
218
|
+
`recommendedVerificationTruncated` reports overflow. Query's default cap is 12
|
|
219
|
+
and can be adjusted with `--budget verification=...`.
|
|
171
220
|
|
|
172
221
|
## Using it in a prompt
|
|
173
222
|
|