Keel

keel route

Independence cannot be manufactured, but it can be routed.

Every ungrounded verification edge in openai-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.

targetopenai-python
revisiond4c151d92ba713e56518a4483d3b7918dd1be838
source reportreports/openai-python.json
generated2026-07-25T05:17:57.179Z
statusproposed (all 3)
0.77

today — measured

·
0.85

projection if applied — 1 re-grounded · 0 constructed

anchored / (anchored + self_referential + unknown)

anchored 10 self_referential 2 unknown 1 not_a_check 12 excluded from the denominator

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 11 · self_referential 1 · unknown 1 · not_a_check 12. The delta is two different claims and is reported as two: 1 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 — 1 routable · 2 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/workflows/python-version-review.yml#125-validate-and-package-the-assessment
ci_step · Validate and package the assessment
today the signal comes from a markdown file written by the Codex LLM in the immediately preceding step (openai/codex-action, line 104); this step reads its first line and its byte count
self_referential
.github/workflows/python-version-review.yml#58-snapshot-official-lifecycle-and-public-usage-data
anchored
.github/workflows/python-version-review.yml:58

The measured argument records that the one consequential output of this step is `action_required`, the sole condition gating the open_issue job at line 174, and that it is currently produced by matching the first line of a file the model wrote against two marker strings — the model decides whether its own finding is actionable. Step 58, in this same job, has already written `$PYTHON_RELEASE_CYCLE` from https://peps.python.org/api/release-cycle.json under `curl --fail`, and has already proven with `jq --exit-status` that every entry carries `status` and `end_of_life`. Those two fields decide the same proposition the marker is standing in for — whether a Python version this repo still declares support for has passed the point the release managers published for it. The producer of that fact is the CPython release-cycle publication: the openai-python maintainers have no write path to peps.python.org, and no prompt, permission profile, or model output can move an end_of_life date. The signal stops originating inside the run and starts originating at the body that sets the dates. Named limit: this re-grounds the lifecycle-date half of the trigger only. The usage-share judgement the model also makes from pypistats — how much adoption is low enough to drop a version — is a policy call, and after this change it lives in the advisory prose where a human weighs it, not in the gate.

change: in the same job, replace the `head -n 1 $CODEX_OUTPUT_FILE` marker branch that sets `action_required` with a jq comparison of `$PYTHON_RELEASE_CYCLE` against the version floor declared in pyproject.toml (action_required=true when any version still in the declared support matrix has status "end-of-life"/"security" or an `end_of_life` date at or before `$REVIEW_DATE_FILE`), and leave the Codex prose as the issue body rather than the trigger

that producer: HTTP responses from peps.python.org and pypistats.org, surfaced as exit codes by `curl --fail` and then `jq --exit-status`

wiring
.github/CODEOWNERS#codeowners
review_gate · code owners (CODEOWNERS)
today the signal comes from GitHub's pull-request review machinery — but whether an approving review is REQUIRED is decided by branch-protection / ruleset configuration that lives in GitHub's settings, not in this repository
unknown
no route

The proposition this edge would assert is that a change cannot merge without approval from someone outside its author's write boundary. Every anchored node in this report is a machine reading committed text or bytes on the wire — ruff, mypy, pyright, pytest, and one HTTP fetch of Python lifecycle data. Not one of them observes a human reviewing, or observes a merge being blocked. There is no candidate here that asserts the proposition, so any route would be a substitution of a different claim, and the measured verdict's own reason for `unknown` — that the requirement, if it exists, lives in GitHub settings this clone cannot read — is not something a rewiring can reach.

why not: Two decisions are required first, both human. (1) Whether the merge requirement is pinned in an artifact anyone can read: today the CODEOWNERS file only routes reviewers, and whether approval is REQUIRED lives in unversioned branch-protection/ruleset configuration; committing rulesets as code would make the edge inspectable, and that is an adoption choice, not a wire. (2) Whether @openai/sdks-team approving Stainless-codegenned changes that the same team lands is independent of the author at all — settling that is a governance decision about who the reviewer must be. Until both are answered, `unknown` is the honest state and it correctly counts against the ratio.

.github/workflows/python-version-review.yml#104-ask-codex-to-assess-the-policy
ci_step · Ask Codex to assess the policy
today the signal comes from a large language model invoked by a CI step
self_referential
no route

This step's product is an assessment of whether the version-support policy is well judged. The only candidate whose subject matter is even adjacent, step 58, asserts something strictly narrower: that two third-party payloads were fetched and are well-shaped. Wiring the model invocation onto the fetch would say the assessment is grounded because its input arrived, which grounds nothing — the output is still a model's prose, produced by the same class of system that writes the code under review, and step 58's exit code is silent about its content. There is no rewiring that makes 'ask a language model for a recommendation' read from an exogenous producer; the producer IS the model. Note that the gate this step feeds IS routable and is proposed separately at line 125 — the trigger can be moved outside the boundary while the explanation stays a model's.

why not: The decision required is a policy one, not a wire: whether this monthly review's verdict should be an LLM's recommendation at all, or a deterministic lifecycle rule with the model demoted to writing the explanation beneath it. A human owns that choice about what the workflow is for. If the gate is re-grounded at line 125 as proposed, the honest follow-up question about this step is whether an advisory generator that no longer decides anything is a verification edge at all — and that reclassification is the scorer's call on a re-measured report, not this layer's.

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
.github/workflows/python-version-review.yml#125-validate-and-package-the-assessment