Keel

Grounding report.

Every verification edge in aider, classified by who produces the signal and whether the actor being verified can write to that producer.

targetaider
revision5dc9490bb35f9729ef2c95d00a19ccd30c26339c
generated2026-07-25T02:36:32.279Z
1.00

anchored / (anchored + self_referential + unknown) = 7 / 7

anchored 7 self_referential 0 unknown 0 not_a_check 18 excluded from the denominator

Coverage (judged)

node kindjudged
ci_step23
review_gate1
test_target1

Nodes by kind, over the 25 node(s) carried in this report. Surfaces the gatherer cannot read are absent here rather than counted as unknown, which makes non-coverage Keel's own shoppable class — so it is stated, not implied.

ε-audit — not run

No verdict in this report carries a readable audit block, so nothing was re-decided and there is no agreement rate to report. This is not agreement, and it is not full agreement either: a rate over zero comparisons would state a measurement that was never taken. (“Readable” is load-bearing: a block can be present and state no comparison, and this state covers that too — see below if so.)

This run carries 14 probe-decided verdict(s), none of them contributing a readable comparison. (“Readable” rather than “audited”, because a block can arrive and state nothing — if any did, they are counted below.) Audit coverage is itself shoppable — audit none of the library and no disagreement can ever be found — so the absence is printed here rather than left to be inferred from a missing section.

This run judged 25 of 62 gathered edges. Every number on this page describes that sample, not the whole surface — 37 gathered edges are absent from all of it. A cap is disclosed rather than smoothed: an undisclosed sample is how a ratio gets shopped.

Scope. Keel measures the shape of verification, not its quality. A repo can be 100% anchored with terrible tests. Anchoring says the signal comes from outside; it does not say the signal is sufficient.

Node graph — 25 node(s), in gather order

anchored 7 not_a_check 18

No mark is ringed: no drawn verdict is anchored below confidence 0.6. Hover a mark for its node.

anchored — 7

The producer sits outside the write boundary of the actor being verified.

pytest config (pytest.ini)
anchored
pytest.ini · test_target

Both gating test workflows run a bare `pytest`, so this config is what actually decides which suite the merge-blocking job executes (tests/basic, tests/help, tests/browser, tests/scrape). Pass/fail is the interpreter's verdict on executing those modules against the installed package: an author cannot make a failing assertion, an exception or a collection error report green without changing the code or the tests, and `addopts = -p no:warnings` only silences warnings rather than swallowing failures. Documented limit: the EXECUTION is anchored, the ORACLE is not — implementation and assertions live in the same repo and are co-authored, so the suite proves the code does what these tests say, not that the tests say the right thing. Second limit: `testpaths`/`norecursedirs` mean anything outside those four directories (e.g. benchmark/) never runs at all.

producer the CPython/pytest process exit code, for the suite this file's `testpaths` selects when CI runs a bare `pytest` — actor can write to it: no

  • pytest.ini:4-9
  • pytest.ini:3
  • .github/workflows/ubuntu-tests.yml:52-56
  • .github/workflows/windows-tests.yml:47-51

decided by agent · confidence 0.85

pre-commit hooks (.pre-commit-config.yaml)
anchored
.pre-commit-config.yaml · review_gate

This config is not local-only advice: .github/workflows/pre-commit.yml runs `pre-commit run --show-diff-on-failure --color=always --all-files` under `set -o pipefail` on `pull_request`, so the hooks sit on the merge path. Each verdict is the exit status of a third-party tool at a pinned rev (isort 5.12.0, black 23.3.0, flake8 7.1.0, codespell v2.2.6) reading the committed bytes — black and isort fail the run when they had to rewrite a file, flake8 exits non-zero on a violation — and a contributor cannot make a violating file report clean without changing the file or the pinned config. Limit worth naming: what is asserted is import order, formatting, lint rules and spelling, never behaviour; and `SKIP: no-commit-to-branch` shows the hook set is selectively disabled in CI, so the config alone does not tell you every hook runs.

producer the exit statuses of isort, black, flake8 and codespell, each pinned to a rev and executed by pre-commit inside a CI job that runs on every pull request — actor can write to it: no

  • .pre-commit-config.yaml:1-24
  • .github/workflows/pre-commit.yml:22-28
  • .github/workflows/pre-commit.yml:3-6

decided by agent · confidence 0.8

Build and publish
anchored
.github/workflows/release.yml:28 · ci_step

`python -m build` executes the packaging backend against the committed pyproject/setup metadata in an isolated env — a broken packaging config, an unresolvable dependency spec or a missing module makes the process exit non-zero, and asserting otherwise changes nothing. `twine upload dist/*` then hands the artifact to PyPI, a third party nobody in this repo can write to, which rejects a duplicate version or malformed metadata on its own authority. Limits: this workflow fires only on a `v[0-9]+.[0-9]+.[0-9]+` tag push, so it gates the release and never a merge, and the property asserted is packageability and uploadability, not that the code behaves.

producer the setuptools/build backend exit code, and PyPI's index server accepting or rejecting the upload — actor can write to it: no

  • .github/workflows/release.yml:28-34
  • .github/workflows/release.yml:3-7

decided by agent · confidence 0.7

Run tests
anchored
.github/workflows/ubuntu-tests.yml:52 · ci_step

`run: pytest` executes the suite pytest.ini selects against the package the previous step installed, and the step's exit status IS the interpreter's verdict on those modules; the workflow triggers on `pull_request` to main, so that exit code is on the merge path. A failing assertion, an import error or a segfault cannot be talked into reporting green without changing the code or the tests, and the matrix runs it on Python 3.10-3.14 so a version-specific break surfaces too. Documented limit: execution is anchored, the oracle is not — the same authors write the implementation and the assertions, so the suite proves the code matches these tests rather than that the tests are the right specification. Second limit: `paths-ignore` skips the job entirely for changes confined to aider/website, README.md or HISTORY.md.

producer the pytest process exit code on ubuntu-latest, across a five-way Python version matrix — actor can write to it: no

  • .github/workflows/ubuntu-tests.yml:52-56
  • .github/workflows/ubuntu-tests.yml:13-21
  • .github/workflows/ubuntu-tests.yml:26-28
  • pytest.ini:4-9

decided by agent · confidence 0.9

Run tests
anchored
.github/workflows/windows-tests.yml:47 · ci_step

Same causal path as the Ubuntu job on a different OS: `run: pytest` executes the suite pytest.ini selects against the freshly `pip install .`-ed package, and the runner's exit status decides the job. It triggers on `pull_request` to main, so it blocks the merge, and running on windows-latest means path-separator and encoding breakage is caught by the platform actually executing the code rather than by anyone's claim about portability. Documented limit: the assertions are co-authored with the implementation, so this anchors execution, not the specification; and `paths-ignore` skips the job for website/README/HISTORY-only changes.

producer the pytest process exit code on windows-latest, across a five-way Python version matrix — actor can write to it: no

  • .github/workflows/windows-tests.yml:47-51
  • .github/workflows/windows-tests.yml:13-21
  • .github/workflows/windows-tests.yml:25-28

decided by agent · confidence 0.9

Build with Jekyll
anchored
.github/workflows/pages.yml:53 · ci_step

`bundle exec jekyll build` runs the bundled Ruby toolchain over the committed markdown, layouts and Liquid templates under aider/website; a Liquid syntax error, malformed YAML front matter or a missing include makes jekyll exit non-zero and reddens the job, and no claim in the repo can override that. The deploy job carries `needs: build`, so a failed render blocks publication. Limit: it asserts only that the site renders — nothing about whether the documented content is true, and nothing about the Python package this repo actually ships.

producer the Jekyll/Ruby process exit code from building the committed site sources — actor can write to it: no

  • .github/workflows/pages.yml:53-57
  • .github/workflows/pages.yml:64-69
  • .github/workflows/pages.yml:43-49

decided by agent · confidence 0.7

Run linkchecker
anchored
.github/workflows/pages.yml:85 · ci_step

The step crawls the live https://aider.chat over the network, and its exit status is decided by responses that come back from servers: an internal page that does not exist answers 404 from the Pages CDN whatever the source tree claims, and an external target that has rotted answers 404/410 from a host nobody in this repo can write to. The signal is produced by executing requests against a deployed system rather than by reading an assertion in the tree. Two limits: it runs AFTER actions/deploy-pages in the same job, so it detects a broken site rather than preventing one; and it points at the live domain instead of the artefact just built, so if the deploy has not propagated it grades the previous deployment. The `--ignore-url` filter also removes media URLs from the crawl.

producer linkchecker's HTTP client, and the status codes returned by the Pages CDN and by the third-party hosts it crawls out to — actor can write to it: no

  • .github/workflows/pages.yml:85-87
  • .github/workflows/pages.yml:71-73
  • .github/workflows/pages.yml:80-83

decided by agent · confidence 0.7

not_a_check — 18

Asserts nothing about correctness, so it is excluded from the denominator. This is the one shoppable class: mis-filing a real check here shrinks the denominator and inflates the score, so each row carries the same burden of argument as any other verdict.

Checkout code
not_a_check
.github/workflows/release.yml:13 · ci_step

The step's whole effect is to put files or a toolchain on the runner so later steps have something to act on. It reads nothing about the repository's correctness and emits no pass/fail verdict about the artefact — a failure here means the runner could not fetch or install, not that the code is wrong. The check in such a job is whatever executes afterwards, so this edge must not enter the ratio in either direction.

producer a GitHub Actions provisioning action (repository checkout, toolchain setup, or dependency cache restore) — actor can write to it: not established

  • the step body is a bare `uses:` of a checkout/setup/cache action with no command of its own

decided by probe (ci-provisioning-action) · confidence 0.9

Set up Python
not_a_check
.github/workflows/release.yml:18 · ci_step

The step's whole effect is to put files or a toolchain on the runner so later steps have something to act on. It reads nothing about the repository's correctness and emits no pass/fail verdict about the artefact — a failure here means the runner could not fetch or install, not that the code is wrong. The check in such a job is whatever executes afterwards, so this edge must not enter the ratio in either direction.

producer a GitHub Actions provisioning action (repository checkout, toolchain setup, or dependency cache restore) — actor can write to it: not established

  • the step body is a bare `uses:` of a checkout/setup/cache action with no command of its own

decided by probe (ci-provisioning-action) · confidence 0.9

Install dependencies
not_a_check
.github/workflows/release.yml:23 · ci_step

The command installs declared dependencies so that later steps can run. Without a lockfile-freezing flag the resolver will refresh a stale lock rather than error, so the step cannot report a discrepancy between the manifest and the lock; its non-zero exits mean the network or the index failed, not that the repository is wrong. The assertion in such a job lives in whatever executes against the installed environment afterwards.

producer a package manager's dependency resolver populating an environment — actor can write to it: not established

  • the run command is a bare dependency install with no --locked/--frozen equivalent

decided by probe (unfrozen-dependency-install) · confidence 0.8

Check out repository
not_a_check
.github/workflows/ubuntu-tests.yml:31 · ci_step

The step's whole effect is to put files or a toolchain on the runner so later steps have something to act on. It reads nothing about the repository's correctness and emits no pass/fail verdict about the artefact — a failure here means the runner could not fetch or install, not that the code is wrong. The check in such a job is whatever executes afterwards, so this edge must not enter the ratio in either direction.

producer a GitHub Actions provisioning action (repository checkout, toolchain setup, or dependency cache restore) — actor can write to it: not established

  • the step body is a bare `uses:` of a checkout/setup/cache action with no command of its own

decided by probe (ci-provisioning-action) · confidence 0.9

Set up Python ${{ matrix.python-version }}
not_a_check
.github/workflows/ubuntu-tests.yml:36 · ci_step

The step's whole effect is to put files or a toolchain on the runner so later steps have something to act on. It reads nothing about the repository's correctness and emits no pass/fail verdict about the artefact — a failure here means the runner could not fetch or install, not that the code is wrong. The check in such a job is whatever executes afterwards, so this edge must not enter the ratio in either direction.

producer a GitHub Actions provisioning action (repository checkout, toolchain setup, or dependency cache restore) — actor can write to it: not established

  • the step body is a bare `uses:` of a checkout/setup/cache action with no command of its own

decided by probe (ci-provisioning-action) · confidence 0.9

Install system dependencies
not_a_check
.github/workflows/ubuntu-tests.yml:41 · ci_step

`sudo apt-get update && sudo apt-get install -y libportaudio2` puts a shared library on the runner so the later `pip install .` and `pytest` steps have something to link against. Nothing in the repository is read or evaluated: a non-zero exit here means the mirror was unreachable or the package moved upstream, never that the code is wrong. The assertion in this job is the `pytest` step that runs afterwards, so this edge must not enter the ratio in either direction.

producer apt-get fetching an OS package from the Ubuntu mirrors onto the runner — actor can write to it: not established

  • .github/workflows/ubuntu-tests.yml:41-44

decided by agent · confidence 0.9

Install dependencies
not_a_check
.github/workflows/ubuntu-tests.yml:46 · ci_step

The command installs declared dependencies so that later steps can run. Without a lockfile-freezing flag the resolver will refresh a stale lock rather than error, so the step cannot report a discrepancy between the manifest and the lock; its non-zero exits mean the network or the index failed, not that the repository is wrong. The assertion in such a job lives in whatever executes against the installed environment afterwards.

producer a package manager's dependency resolver populating an environment — actor can write to it: not established

  • the run command is a bare dependency install with no --locked/--frozen equivalent

decided by probe (unfrozen-dependency-install) · confidence 0.8

Check out repository
not_a_check
.github/workflows/windows-tests.yml:31 · ci_step

The step's whole effect is to put files or a toolchain on the runner so later steps have something to act on. It reads nothing about the repository's correctness and emits no pass/fail verdict about the artefact — a failure here means the runner could not fetch or install, not that the code is wrong. The check in such a job is whatever executes afterwards, so this edge must not enter the ratio in either direction.

producer a GitHub Actions provisioning action (repository checkout, toolchain setup, or dependency cache restore) — actor can write to it: not established

  • the step body is a bare `uses:` of a checkout/setup/cache action with no command of its own

decided by probe (ci-provisioning-action) · confidence 0.9

Set up Python ${{ matrix.python-version }}
not_a_check
.github/workflows/windows-tests.yml:36 · ci_step

The step's whole effect is to put files or a toolchain on the runner so later steps have something to act on. It reads nothing about the repository's correctness and emits no pass/fail verdict about the artefact — a failure here means the runner could not fetch or install, not that the code is wrong. The check in such a job is whatever executes afterwards, so this edge must not enter the ratio in either direction.

producer a GitHub Actions provisioning action (repository checkout, toolchain setup, or dependency cache restore) — actor can write to it: not established

  • the step body is a bare `uses:` of a checkout/setup/cache action with no command of its own

decided by probe (ci-provisioning-action) · confidence 0.9

Install dependencies
not_a_check
.github/workflows/windows-tests.yml:41 · ci_step

The command installs declared dependencies so that later steps can run. Without a lockfile-freezing flag the resolver will refresh a stale lock rather than error, so the step cannot report a discrepancy between the manifest and the lock; its non-zero exits mean the network or the index failed, not that the repository is wrong. The assertion in such a job lives in whatever executes against the installed environment afterwards.

producer a package manager's dependency resolver populating an environment — actor can write to it: not established

  • the run command is a bare dependency install with no --locked/--frozen equivalent

decided by probe (unfrozen-dependency-install) · confidence 0.8

Checkout
not_a_check
.github/workflows/pages.yml:39 · ci_step

The step's whole effect is to put files or a toolchain on the runner so later steps have something to act on. It reads nothing about the repository's correctness and emits no pass/fail verdict about the artefact — a failure here means the runner could not fetch or install, not that the code is wrong. The check in such a job is whatever executes afterwards, so this edge must not enter the ratio in either direction.

producer a GitHub Actions provisioning action (repository checkout, toolchain setup, or dependency cache restore) — actor can write to it: not established

  • the step body is a bare `uses:` of a checkout/setup/cache action with no command of its own

decided by probe (ci-provisioning-action) · confidence 0.9

Setup Ruby
not_a_check
.github/workflows/pages.yml:43 · ci_step

The step's whole effect is to put files or a toolchain on the runner so later steps have something to act on. It reads nothing about the repository's correctness and emits no pass/fail verdict about the artefact — a failure here means the runner could not fetch or install, not that the code is wrong. The check in such a job is whatever executes afterwards, so this edge must not enter the ratio in either direction.

producer a GitHub Actions provisioning action (repository checkout, toolchain setup, or dependency cache restore) — actor can write to it: not established

  • the step body is a bare `uses:` of a checkout/setup/cache action with no command of its own

decided by probe (ci-provisioning-action) · confidence 0.9

Setup Pages
not_a_check
.github/workflows/pages.yml:50 · ci_step

The step's whole effect is to ask the Pages API for the site's base path and export it as an output the next step interpolates into `jekyll build --baseurl`. It evaluates nothing about the repository — a failure means the Pages API was unreachable or the repo has Pages disabled, which is a fact about the hosting configuration, not about the artefact. The assertion in this job is the jekyll build that consumes its output.

producer actions/configure-pages resolving the Pages site URL and exporting `steps.pages.outputs.base_path` — actor can write to it: not established

  • .github/workflows/pages.yml:50-52
  • .github/workflows/pages.yml:55

decided by agent · confidence 0.85

Upload artifact
not_a_check
.github/workflows/pages.yml:58 · ci_step

The step packages the directory the jekyll build in the same job just produced and hands it to the Pages artifact store so the deploy job can fetch it. Nothing about the repository is evaluated — the worst it can report is that a path the pipeline itself was responsible for creating is absent, a fact about the plumbing. The assertion in this job is the build step before it, so this edge must not enter the ratio in either direction.

producer actions/upload-pages-artifact tarring the _site tree the immediately preceding step wrote — actor can write to it: not established

  • .github/workflows/pages.yml:58-61
  • .github/workflows/pages.yml:53-55

decided by agent · confidence 0.85

Deploy to GitHub Pages
not_a_check
.github/workflows/pages.yml:71 · ci_step

The step fetches the tarball the build job uploaded and asks the Pages service to serve it. Success means GitHub accepted and published a bundle the same actor authored — a statement about the delivery channel, not a verdict on the artefact — and there is no condition between build and deploy other than the build's own exit code, so nothing is gated here. Naming the shoppability risk explicitly: I am not filing this here because it is hard, but because a successful publish is compatible with every possible content defect, so it asserts nothing about correctness in either direction. The post-deploy linkchecker step in the same job is where an assertion about the deployed site is actually made.

producer actions/deploy-pages publishing the artifact an earlier job in the same run uploaded — actor can write to it: not established

  • .github/workflows/pages.yml:71-73
  • .github/workflows/pages.yml:63-69

decided by agent · confidence 0.7

Set up Python 3.12
not_a_check
.github/workflows/pages.yml:75 · ci_step

The step's whole effect is to put files or a toolchain on the runner so later steps have something to act on. It reads nothing about the repository's correctness and emits no pass/fail verdict about the artefact — a failure here means the runner could not fetch or install, not that the code is wrong. The check in such a job is whatever executes afterwards, so this edge must not enter the ratio in either direction.

producer a GitHub Actions provisioning action (repository checkout, toolchain setup, or dependency cache restore) — actor can write to it: not established

  • the step body is a bare `uses:` of a checkout/setup/cache action with no command of its own

decided by probe (ci-provisioning-action) · confidence 0.9

Install linkchecker
not_a_check
.github/workflows/pages.yml:80 · ci_step

The command installs declared dependencies so that later steps can run. Without a lockfile-freezing flag the resolver will refresh a stale lock rather than error, so the step cannot report a discrepancy between the manifest and the lock; its non-zero exits mean the network or the index failed, not that the repository is wrong. The assertion in such a job lives in whatever executes against the installed environment afterwards.

producer a package manager's dependency resolver populating an environment — actor can write to it: not established

  • the run command is a bare dependency install with no --locked/--frozen equivalent

decided by probe (unfrozen-dependency-install) · confidence 0.8

Checkout code
not_a_check
.github/workflows/docker-release.yml:13 · ci_step

The step's whole effect is to put files or a toolchain on the runner so later steps have something to act on. It reads nothing about the repository's correctness and emits no pass/fail verdict about the artefact — a failure here means the runner could not fetch or install, not that the code is wrong. The check in such a job is whatever executes afterwards, so this edge must not enter the ratio in either direction.

producer a GitHub Actions provisioning action (repository checkout, toolchain setup, or dependency cache restore) — actor can write to it: not established

  • the step body is a bare `uses:` of a checkout/setup/cache action with no command of its own

decided by probe (ci-provisioning-action) · confidence 0.9

Crystallization curve

Keel crystallization curve Crystallization curve over 15 runs from <repo>/reports. falls — total fitted change -66.5% of the mean across 15 runs (R^2 0.28, so the line explains less than half the variance — read the raw squares) CRYSTALLIZATION CURVE 15 sequential runs · 345 nodes judged of 1838 gathered · 124 anchored Keel corpus — 15 repositories, 2026-07-24 — measured corpus (declared on the command line) estimated tokens per node estimated tokens / judged node 0 300 600 run 0 · keel · estimated tokens per node = 498 · judged 25 of 32 gathered run 1 · anthropic-sdk-python · estimated tokens per node = 369 · judged 25 of 41 gathered run 2 · openai-python · estimated tokens per node = 398 · judged 25 of 95 gathered run 3 · vercel-ai · estimated tokens per node = 410 · judged 25 of 1014 gathered run 4 · aider · estimated tokens per node = 204 · judged 25 of 62 gathered run 5 · browser-use · estimated tokens per node = 378 · judged 25 of 104 gathered run 6 · mcp-python-sdk · estimated tokens per node = 592 · judged 25 of 121 gathered run 7 · simonw-llm · estimated tokens per node = 189 · judged 25 of 38 gathered run 8 · tiktoken · estimated tokens per node = 240 run 9 · requests · estimated tokens per node = 290 · judged 25 of 106 gathered run 10 · flask · estimated tokens per node = 408 · judged 25 of 59 gathered run 11 · sinatra · estimated tokens per node = 265 · judged 25 of 59 gathered run 12 · commander-js · estimated tokens per node = 316 run 13 · anthropic-quickstarts · estimated tokens per node = 310 · judged 25 of 62 gathered run 14 · tiktoken · estimated tokens per node = 53 0* 1* 2* 3* 4* 5* 6* 7* 8 9* 10* 11* 12 13* 14 seconds per node measured s / judged node 0.0 60.0 120.0 run 0 · keel · seconds per node = 0.1 · judged 25 of 32 gathered run 1 · anthropic-sdk-python · seconds per node = 15.8 · judged 25 of 41 gathered run 2 · openai-python · seconds per node = 15.4 · judged 25 of 95 gathered run 3 · vercel-ai · seconds per node = 105.9 · judged 25 of 1014 gathered run 4 · aider · seconds per node = 21.3 · judged 25 of 62 gathered run 5 · browser-use · seconds per node = 21.7 · judged 25 of 104 gathered run 6 · mcp-python-sdk · seconds per node = 20.1 · judged 25 of 121 gathered run 7 · simonw-llm · seconds per node = 11.8 · judged 25 of 38 gathered run 8 · tiktoken · seconds per node = 23.7 run 9 · requests · seconds per node = 16.8 · judged 25 of 106 gathered run 10 · flask · seconds per node = 20.5 · judged 25 of 59 gathered run 11 · sinatra · seconds per node = 16.9 · judged 25 of 59 gathered run 12 · commander-js · seconds per node = 18.7 run 13 · anthropic-quickstarts · seconds per node = 20.4 · judged 25 of 62 gathered run 14 · tiktoken · seconds per node = 0.1 0* 1* 2* 3* 4* 5* 6* 7* 8 9* 10* 11* 12 13* 14 probe-decided share measured share of decided nodes 0.00 0.50 1.00 run 0 · keel · probe-decided share = 0.00 · judged 25 of 32 gathered run 1 · anthropic-sdk-python · probe-decided share = 0.00 · judged 25 of 41 gathered run 2 · openai-python · probe-decided share = 0.16 · judged 25 of 95 gathered run 3 · vercel-ai · probe-decided share = 0.08 · judged 25 of 1014 gathered run 4 · aider · probe-decided share = 0.56 · judged 25 of 62 gathered run 5 · browser-use · probe-decided share = 0.32 · judged 25 of 104 gathered run 6 · mcp-python-sdk · probe-decided share = 0.00 · judged 25 of 121 gathered run 7 · simonw-llm · probe-decided share = 0.56 · judged 25 of 38 gathered run 8 · tiktoken · probe-decided share = 0.58 run 9 · requests · probe-decided share = 0.28 · judged 25 of 106 gathered run 10 · flask · probe-decided share = 0.00 · judged 25 of 59 gathered run 11 · sinatra · probe-decided share = 0.28 · judged 25 of 59 gathered run 12 · commander-js · probe-decided share = 0.19 run 13 · anthropic-quickstarts · probe-decided share = 0.24 · judged 25 of 62 gathered run 14 · tiktoken · probe-decided share = 1.00 0* 1* 2* 3* 4* 5* 6* 7* 8 9* 10* 11* 12 13* 14 probe library size measured probes in library 0 15 30 run 0 · keel · probe library size = 0 · judged 25 of 32 gathered run 1 · anthropic-sdk-python · probe library size = 3 · judged 25 of 41 gathered run 2 · openai-python · probe library size = 5 · judged 25 of 95 gathered run 3 · vercel-ai · probe library size = 8 · judged 25 of 1014 gathered run 4 · aider · probe library size = 10 · judged 25 of 62 gathered run 5 · browser-use · probe library size = 12 · judged 25 of 104 gathered run 6 · mcp-python-sdk · probe library size = 13 · judged 25 of 121 gathered run 7 · simonw-llm · probe library size = 15 · judged 25 of 38 gathered run 8 · tiktoken · probe library size = 17 run 9 · requests · probe library size = 19 · judged 25 of 106 gathered run 10 · flask · probe library size = 22 · judged 25 of 59 gathered run 11 · sinatra · probe library size = 23 · judged 25 of 59 gathered run 12 · commander-js · probe library size = 26 run 13 · anthropic-quickstarts · probe library size = 29 · judged 25 of 62 gathered run 14 · tiktoken · probe library size = 29 0* 1* 2* 3* 4* 5* 6* 7* 8 9* 10* 11* 12 13* 14 x axis: run index in the recorded corpus order (listed below). Squares are the raw per-run values; the dashed line is an ordinary-least-squares fit and is never shown without them. The fit is clipped to the panel, and withheld entirely (with the panel saying so) where a straight line would predict values the points cannot take — R^2 for every fit is in the trend notes below. * on run 0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 13 = judged fewer nodes than gathered; per-node values are per JUDGED node. Coverage (judged) ci_step 224 · script 64 · test_target 46 · review_gate 10 · deploy_gate 1 Trend estimated tokens per node: falls — total fitted change -66.5% of the mean across 15 runs (R^2 0.28, so the line explains less than half the variance — read the raw squares). raw first 498 -> last 53. seconds per node: falls — total fitted change -72.9% of the mean across 15 runs (R^2 0.04, so the line explains less than half the variance — read the raw squares). raw first 0.1 -> last 0.1. probe-decided share: rises — total fitted change 144.9% of the mean across 15 runs (R^2 0.21, so the line explains less than half the variance — read the raw squares). raw first 0.00 -> last 1.00. probe library size: rises — total fitted change 187.7% of the mean across 15 runs (R^2 0.99). raw first 0 -> last 29. Run order run order derived from Report.generatedAt (ascending, filename as tiebreak) — no order.json manifest present 0 keel -> 1 anthropic-sdk-python -> 2 openai-python -> 3 vercel-ai -> 4 aider -> 5 browser-use -> 6 mcp-python-sdk -> 7 simonw-llm -> 8 tiktoken -> 9 requests -> 10 flask -> 11 sinatra -> 12 commander-js -> 13 anthropic-quickstarts -> 14 tiktoken Shuffle check shuffle check INCOMPLETE — the curve direction ran, the ratio direction did not Permutation (400 draws, seed 20260724): median |delta normalized slope| 0.633, 92% of draws move it by >= 0.15. A permutation reorders ALREADY-RECORDED runs; it cannot reproduce what a genuine re-run in a different order would have cost, because the probe library would have accumulated differently. It is a sanity signal on order-dependence, never a substitute for the empirical re-run. Ratio stability under shuffle was NOT checked: no re-run supplied (--shuffled) and none declared in corpus.meta.json. Permuting recorded runs cannot move a per-target ratio, so the permutation result below says nothing about it. Supply a re-run with --shuffled <dir>. Disclosures - Skipped 3 file(s) that are not usable run reports: corpus-summary.json (no string "target"); curve.json (no string "target"); keel.bindings.json (no "nodes" array). - Run 0 (keel) judged 25 of 32 gathered nodes — a cap. Per-node cost below is per JUDGED node. - Run 1 (anthropic-sdk-python) judged 25 of 41 gathered nodes — a cap. Per-node cost below is per JUDGED node. - Run 2 (openai-python) judged 25 of 95 gathered nodes — a cap. Per-node cost below is per JUDGED node. - Run 3 (vercel-ai) judged 25 of 1014 gathered nodes — a cap. Per-node cost below is per JUDGED node. - Run 4 (aider) judged 25 of 62 gathered nodes — a cap. Per-node cost below is per JUDGED node. - Run 5 (browser-use) judged 25 of 104 gathered nodes — a cap. Per-node cost below is per JUDGED node. - Run 6 (mcp-python-sdk) judged 25 of 121 gathered nodes — a cap. Per-node cost below is per JUDGED node. - Run 7 (simonw-llm) judged 25 of 38 gathered nodes — a cap. Per-node cost below is per JUDGED node. - Run 9 (requests) judged 25 of 106 gathered nodes — a cap. Per-node cost below is per JUDGED node. - Run 10 (flask) judged 25 of 59 gathered nodes — a cap. Per-node cost below is per JUDGED node. - Run 11 (sinatra) judged 25 of 59 gathered nodes — a cap. Per-node cost below is per JUDGED node. - Run 13 (anthropic-quickstarts) judged 25 of 62 gathered nodes — a cap. Per-node cost below is per JUDGED node. - Run 14 (tiktoken): decidedByProbe + decidedByAgent = 10 but nodesSampled = 12. Probe-decided share uses the decided total (10). - Provenance "measured" was declared on the COMMAND LINE (--provenance), not in <repo>/reports/corpus.meta.json. The declaration therefore lives in the invocation and is only as trustworthy as the run sheet that records it. - Token counts are ESTIMATES in 15 of 15 run(s) (RunEconomics.tokensEstimated). No API exposes session token usage to a skill, so the token axis reads "estimated tokens" and nothing here claims a measured token count. Scope. Keel measures the shape of verification, not its quality. A repo can be 100% anchored with terrible tests. Anchoring says the signal comes from outside; it does not say the signal is sufficient.

Run economics

14 decided by probe
11 decided by agent
56% probe-decided share
25 / 62 nodes judged / gathered
1,459 estimated tokens in
3,641 estimated tokens out
8m 52s wall clock
2 probes minted
10 probe library size

Token counts are estimated, and labelled so: a skill running inside an agent session has no API for its own usage, so the figure is ceil(chars/4) over the judgment payloads and responses. Wall clock and probe-decided share are measured directly. 25 of 62 gathered edges were judged — the cap is printed here and beside the ratio, never applied silently.