Keel
keel route
Independence cannot be manufactured, but it can be routed.
Every ungrounded verification edge in anthropic-sdk-python, paired — where a pairing exists — with an anchored producer already present in the same measurement. Nothing here invents an anchor, and nothing here has been applied.
| target | anthropic-sdk-python |
|---|---|
| revision | 60c64fba5c2bf340567f627328e57cf0196b868f |
| source report | reports/anthropic-sdk-python.json |
| generated | 2026-07-25T05:15:24.487Z |
| status | proposed (all 4) |
anchored / (anchored + self_referential + unknown)
The second number is a projection: the ratio this target would carry if a human applied every route below and the applied routes measured as anchored on re-measurement. It is arithmetic on a hypothetical. It is not written to any report, it is not fed back into the grounding ratio, and no proposal on this page has been applied. Projected counts, for the same conditional: anchored 8 · self_referential 2 · unknown 2 · not_a_check 13. The delta is two different claims and is reported as two: 0 re-grounded — an existing check whose signal moves outside the write boundary, the proposition it asserts unchanged — and 0 constructed — a not_a_check node that becomes a check, entering the denominator as well as the numerator. Only the first repairs something that was already being claimed.
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.
Routes — 0 routable · 4 unroutable
Existing checks whose signal could come from somewhere they cannot write. Cheapest effort on top. no route is a first-class answer: it means the fix needs a policy decision rather than a rewiring, and it is reported here rather than dropped.
| what's ungrounded | route to | why that's anchored | effort |
|---|---|---|---|
.github/CODEOWNERS#codeowners
unknown |
no route | The proposition here is 'a change reaching main was approved by a party responsible for the code'. It is unknown because the producer of that signal — GitHub's branch-protection engine — is configured outside the clone, so the edge cannot be traced to a fork point at all. Routing requires an anchored node that asserts THAT proposition, and this report contains none: every anchored candidate produces a machine verdict over the committed tree (ruff, pyright, mypy, the interpreter's import, the uv build backend, PyPI's upload response). A machine's verdict on the source is not an approval by a responsible party — substituting one for the other would silently redefine the claim rather than ground it. There is also no node in this report whose producer is a human decision of any kind. |
— |
.github/workflows/claude.yml#38-run-claude-code
self_referential |
no route | There is nothing here to re-ground, and that is the first reason. The workflow `if:` at claude.yml:15-19 makes this step mention-triggered, so it is not on the merge path; moving its signal to an anchored producer would change no admission decision. The second reason is that the propositions do not match. Whatever this step asserts is a broad judgement — 'this change or this answer is sound' — while every anchored candidate in the report asserts something strictly narrower and different in kind: ci.yml#34-run-lints and the pyproject linter tables say the tree type-checks, lints and imports; create-releases.yml#34-publish-to-pypi says the tree packages and PyPI took it; pyproject.toml#tool-pytest-ini-options says the collected tests executed to a clean exit. Declaring 'the lints are green' to be the grounded form of 'the model reviewed it' would rename the claim rather than anchor it. Those producers already run on push against anything this job commits, so the honest statement is that they cover what they cover and the model's judgement remains unverified — not that the judgement has been routed. |
— |
.github/workflows/create-releases.yml#22-stainless-api-trigger-release-please-bb6677c5a04578eec1ccfd9e1913b5b78ed64c61-v1-4-0
unknown |
no route | The proposition this step asserts is 'a release is warranted now, at this version, with this changelog and tag state'. The only anchored candidate anywhere near it is create-releases.yml#34-publish-to-pypi, and it fails on both counts. Direction: #34 runs BECAUSE of this step's `releases_created` output, so it is downstream and cannot be a producer this step reads — a check cannot be grounded by its own consequence. Proposition: PyPI's upload response asserts that an artefact was built and accepted; it rejects a duplicate version but says nothing about whether a release was warranted, whether the changelog is honest, or whether the version bump matches the diff. A wrongly-triggered release carrying a fresh version number passes #34 cleanly, so wiring these together would raise the number while leaving the actual claim ungrounded. The opacity itself is untouched either way: the action's body is pinned by SHA but not vendored, so nothing in this repo can be read to learn what it validates. |
— |
tests/conftest.py#conftest-py
self_referential |
no route | The proposition this conftest is trying to assert is behavioural: that the client's requests and its handling of responses match the API it will actually talk to. Its producer is a Steady mock booted from the `openapi_spec_url` in .stats.yml plus inline_snapshot recordings of the client's own traffic — both derived from artefacts inside the write boundary, which is exactly why it is self_referential. Every anchored producer in this report sits on a different axis: ruff/pyright/mypy/`import anthropic` (.github/workflows/ci.yml#34-run-lints and the four pyproject linter tables) assert that the committed tree analyses and imports cleanly, and create-releases.yml#34-publish-to-pypi asserts that the tree packages and that PyPI accepted the upload. None of them observes the behaviour of the Anthropic API, so none of them can supply the oracle this suite is missing. pyproject.toml#tool-pytest-ini-options is the trap: it is anchored, but only on the EXECUTION axis, and its own measured argument names the identical spec-derived-oracle limit. Routing the oracle onto the config of the very suite whose oracle is in question is a circle, and would move the count without grounding the claim. |
— |
Construct — not yet.
A route makes a check read a signal from outside itself. It does not pair that check with a counter-metric, name who arbitrates when the pair disagrees, or set a cadence at which the route is re-audited. Those three fields are declared in schemas/route.ts and are filled by keel construct, which is not built. The columns are empty by construction, not by omission.
| route | pairedWith | arbitratedBy | auditEvery |
|---|---|---|---|
| no routes on this run | |||