Skip to content

fix(ci): the Gate was failing on a missing pin file, not on 915 lint findings - #60

Merged
stranske merged 3 commits into
mainfrom
claude/gracious-murdock-2d1379
Aug 23, 2026
Merged

fix(ci): the Gate was failing on a missing pin file, not on 915 lint findings#60
stranske merged 3 commits into
mainfrom
claude/gracious-murdock-2d1379

Conversation

@stranske

@stranske stranske commented Aug 23, 2026

Copy link
Copy Markdown
Owner

Rebuilt on main after #42 and #59 merged. #42 carried its four chore(autofix) reformat commits into main, so the mechanical part of the drain is already there and this PR is now 35 files, +1,252/−154 instead of 135 files and +20k. The numbers below are re-measured on the new base.

The thing that was actually broken

Every Python PR failed six checks — lint-ruff, lint-format, typecheck-mypy, python 3.12, python 3.13, summary — and ruff check . reported 915 findings, 181 files needing reformatting. That reads as undrained lint debt no single PR can clear, which is the latched-gate shape.

It was not that. All five upstream jobs died at the same shared install step, before any tool ran:

Error: .../.github/workflows/autofix-versions.env is required;
       refusing to install unpinned tooling.

Identical in jobs 97151941071 / 97151941074 / 97151941041 / 97151952706 / 97151952767. Ruff, Black and mypy had never executed on this repository, not once — so every prior statement about its lint debt was inferred, not measured.

The cause is a contradiction between two lines of one upstream file:

Upstream Says
Workflows/.github/sync-manifest.yml:33 pr-00-gate.yml is synced to consumers (create_only)
Workflows/.github/sync-manifest.yml:967 autofix-versions.env is excluded"consumers copy or override per docs/ci/WORKFLOWS.md. Intentionally not synced"
Workflows/docs/ci/WORKFLOWS.md:83 The consumer procedure: copy that file

The sync delivered a Gate that hard-requires a file the sync deliberately never delivers, and this repo never performed the copy. This PR performs it.

Neither option in the brief would have worked on its own

  • (b) alone — setting lint/format_check/typecheck/run-mypy false — leaves python 3.12, python 3.13 and summary red, because require_exact_pin demands pytest and pytest-xdist pins unconditionally.
  • A second latch sat behind the first. With coverage on, the reusable appends --cov-config=pyproject.toml unconditionally (reusable-10-ci-python.yml:1975), so pytest dies at startup here: coverage.exceptions.ConfigError: Couldn't read 'pyproject.toml' as a config file. Adding a pyproject.toml to fix that makes the same workflow append -e '.[app,dev]' (:1683), which 129 flat root modules with no build backend cannot satisfy. Mutually exclusive upstream assumptions — which is why the config lands as ruff.toml + mypy.ini, and why coverage is off.

The real latch: two windows that could never agree

With no config file present, the two CI surfaces resolved "no config" differently:

surface rule set on today's main
Gate (reusable-10-ci-python.yml:1155) ruff check --select E4,E7,E9,F — pre-0.16 default, pinned on purpose 37
Autofix (reusable-18-autofix.yml:523-527) --select I --fix, then bare ruff check --fix (Ruff 0.16's own, wider default), then black -l 100 733

Before #42's Autofix commits landed those read 79 and 915 — which is where the "915, undrainable" reading came from. The gap is the defect, not its size on any given day. Autofix rewrote the tree to satisfy rules the Gate never checked, on every Gate failure, and the Gate stayed red regardless because it was dying at the install step: four chore(autofix) commits on #42, one on #51, ~143 files and +20,562/−11,089 each. Reverting one got it re-pushed.

ruff.toml collapses them into one window — Ruff reads it from either surface, so what Autofix fixes is exactly what the Gate checks — and this PR brings the tree to that canon, which is what kills the loop structurally rather than leaving it dormant. Verified by replaying Autofix's three commands verbatim:

ruff check --select I --fix --exit-zero .   ->  All checks passed!
ruff check --fix --exit-zero .             ->  All checks passed!
black --line-length 100 .                  ->  196 files left unchanged

Deferring the format check instead would have left the loop armed for the next Gate failure of any kind. .autofix-exclude, the only repo-owned lever, cannot express "do not format this repo" (its patterns filter directories, and the repo root is always a target), and autofix.yml carries no sync_mode, so an edit there would be overwritten by the next template sync.

Measured, blocking / drainable

2026-08-23, at the pinned versions, on the rebuilt base:

check blocking drainable state
lint-ruff 39 → 0 findings 39 ON, green
lint-format 2 → 0 files 2 ON, green
python 3.12 / 3.13 0 failures ON, green
typecheck-mypy 601 errors in 89 of 189 files 0 per PR (no mypy --fix exists) OFF, annotated
coverage 1 startup error 0 from inside this repo OFF, annotated

Both OFF toggles state blocking and drainable and drains by: at the single place the toggles are computed, and test_ci_gate_config.py fails if any of those three fields goes missing — the repo's runtime rule enforced rather than written down. One literal per toggle: the with: block and the summary job's coverage branch both read needs.detect.outputs.*, and a test rejects a second hardcoded value.

mypy.ini is committed although the check is off, for one reason: without it mypy . aborts on Source file found twice under different module names and the 601 would be unverifiable prose. It silences no error code, by test — fifteen disable_error_code entries would cover 597 of the 601 and make the job green while checking essentially nothing.

Deliberately not selected, each with its count and its drain: E501 — 1068 lines still exceed 100 columns after black -l 100, all long strings, URLs and comment prose, so selecting it would be selecting a rule with no drain. The rest of Ruff 0.16's default set — 742 findings, each a real code change. RUF100 — 72 # noqa comments name rules the narrow set does not check; deleting them would have to be undone the moment the selection widens. Three E402 findings are exempted per site with a reason (each import follows the sys.path.insert that makes it resolvable), not by an ignore in ruff.toml.

Line length is 100, not Black's default 88 — the value both the Gate's format job and Autofix hardcode. At 88 Black rewrites 184 of 196 files here; at 100 it rewrites 2. A test asserts ruff.toml, the baseline script and that 100 still agree.

Files

  • .github/workflows/autofix-versions.envthe actual unblock. The documented copy of the fleet pins.
  • ruff.toml, mypy.ini — one rule set for both surfaces; module resolution so mypy's count is reproducible.
  • .github/workflows/pr-00-gate.ymltypecheck/coverage off at the single toggle source, each annotated with both quantities and its drain.
  • docs/CI_LINT_BASELINE.md, scripts/ci_lint_baseline.py — the recorded baseline and the tool that regenerates it. The script refuses to print numbers measured with unpinned tools; a measured-with line in the doc is asserted against the pin file, so bumping a version without re-measuring goes red.
  • test_ci_gate_config.py (11 tests) + env_prereq.repo_files_absent — the enforcement. The skip gate is the presence of the repository directories, never of the pin file itself: gating on the file would have made the test that checks for it unable to fail, which is this very defect reproduced inside its own test.
  • 39 Ruff findings and 2 files drained — E741 renames, E731 lambda→def (via AST, not regex), F841 unused locals, one F601 duplicate dict key (a real bug: "route_weights" appeared twice in a test fixture, so one value was silently discarded), one stray mid-file import math hoisted.

Verification

python3 verify.py on the owner's machine: 402 passed, 0 failed, 0 skipped, 84/84 selftests, 43/43 CAN FIRE, 5/5 gates. Fresh-machine simulation with empty ORCH_STATE_DIR and ORCH_LOCAL_RUNTIME: 394 passed, 8 skipped, 402 collected. CI-equivalent parallel run (pytest -n auto --dist=loadgroup): 393 passed, 9 skipped. Also re-run from a mirror-shaped copy (root-level *.py only, as orch-sync-mirror.sh produces) to confirm the new tests skip there with a named reason rather than failing. The live exec mirror was deliberately not synced: it currently carries another session's branch, and syncing it is the manual circuit breaker between a change and the dispatcher — a post-merge step, not part of this PR. Floor 391 → 402 for the 11 new tests; no ceiling moved.

One click is needed to see the Gate itself run

Gate on this PR is action_required with zero jobsrun 32644152974. That is GitHub's suspicious-workflow protection, armed because this PR edits .github/workflows/pr-00-gate.yml; the scan attaches to the file version, so any change to that file re-arms it. The signature is exact: status=completed, conclusion=action_required, created_at == updated_at, 0 jobs, and POST /actions/runs/{id}/approve returns 403 "This run is not from a fork pull request or queued by the Actions bot". A workflow_dispatch run on the same ref (32644278296) is held identically, so no event can route around it.

It needs one click of "Approve and run" on that run page. There is no API path. Until then the Gate's own python-ci legs cannot be observed on this branch — which is why every number in this PR was measured by running the Gate's exact commands locally, at the exact pinned tool versions, and why scripts/ci_lint_baseline.py exists to re-run them rather than being taken on trust.

What did run on a clean GitHub runner is this repo's own CI workflow — python3 verify.py, green: 376 passed, 0 failed, 402 collected against floor 402, at exactly the agreed 26/7/2 skip ceilings with every skip naming its missing prerequisite.

Out of scope, filed separately

A seventh red check on these PRs, same class, different workflow: backplane-conformance.yml:35 runs pip install -e . unconditionally, so it fails on any non-package consumer despite its own header promising it "skips harmlessly". Both that and the --cov-config fix belong upstream in Workflows (both files are overwrite-synced, so a local fix would be reverted). When the --cov-config fix lands, coverage can come back on here — the annotation in pr-00-gate.yml already names it as the drain.

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Aug 23, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your current included review allowance is based on your included PR review attempts over the past 7 days.

Next review available in: 55 minutes

Limit details: You’ve used the included review currently available. Your 75 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8bc6576f-803f-42ff-9df4-aa26593bcdf3

📥 Commits

Reviewing files that changed from the base of the PR and between 2118f57 and d07f734.

📒 Files selected for processing (33)
  • .github/workflows/autofix-versions.env
  • .github/workflows/pr-00-gate.yml
  • .verify-floor.json
  • README.md
  • backlog.py
  • capability_activation_audit.py
  • capability_admission.py
  • capability_matcher_proposals.py
  • capability_outcome_bridge.py
  • capability_recurrence_check.py
  • capacity.py
  • dispatcher.py
  • docs/CI_LINT_BASELINE.md
  • env_prereq.py
  • exp_abcd.py
  • feedback.py
  • gh_capacity.py
  • issue_readiness.py
  • keepalive_evidence.py
  • keepalive_outcomes.py
  • keepalive_shadow.py
  • mcp_server.py
  • merge_guard.py
  • mypy.ini
  • ruff.toml
  • scripts/ci_lint_baseline.py
  • scripts/docs_drift_fix_agent.py
  • scripts/sync_test_dependencies.py
  • test_ci_gate_config.py
  • test_observability_activation.py
  • tick.py
  • tools/check_model_registry_freshness.py
  • verify.py

Comment @coderabbitai help to get the list of available commands.

… lint debt

Every Python PR failed six checks — lint-ruff, lint-format, typecheck-mypy,
python 3.12, python 3.13, summary — and `ruff check .` on main reported 915
findings with 181 files needing reformatting. That reads as debt no single PR can
clear. It was not. All five upstream jobs died at the SAME shared install step,
before any tool ran:

  Error: .../.github/workflows/autofix-versions.env is required;
         refusing to install unpinned tooling.

identical in jobs 97151941071 / 97151941074 / 97151941041 / 97151952706 /
97151952767. Ruff, Black and mypy had never executed on this repository, not
once, so every prior statement about its lint debt was inferred.

The cause is a contradiction between two lines of one upstream file.
`Workflows/.github/sync-manifest.yml:33` syncs `pr-00-gate.yml` to consumers;
line 967 of the same file lists `autofix-versions.env` under EXCLUDED —
"consumers copy or override per docs/ci/WORKFLOWS.md. Intentionally not synced".
So the sync delivered a Gate that hard-requires a file the sync deliberately
never delivers, and this repo never did the documented copy
(`Workflows/docs/ci/WORKFLOWS.md:83`). This commit does it.

Neither option in the brief would have worked alone. Setting lint/format_check/
typecheck/run-mypy to false leaves python 3.12, python 3.13 and summary red,
because `require_exact_pin` demands pytest and pytest-xdist pins
unconditionally. And a second latch sat behind the first: with coverage on, the
reusable appends `--cov-config=pyproject.toml` unconditionally, so pytest dies
at startup here (`ConfigError: Couldn't read 'pyproject.toml'`) — while adding a
pyproject.toml makes the same workflow append `-e '.[app,dev]'`, which 129 flat
root modules with no build backend cannot satisfy. That is why the Ruff and mypy
config land as ruff.toml + mypy.ini, and why coverage is off.

THE REAL LATCH: two windows that could never agree. With no config present the
two CI surfaces resolved "no config" differently — the Gate pinned the pre-0.16
family (`--select E4,E7,E9,F`) while Autofix took Ruff 0.16's own much wider
default plus `--select I`. On today's main that is 37 findings versus 733; before
#42's Autofix commits landed it was 79 versus 915, which is where the "915, no PR
can drain it" reading came from. The gap is the defect, not its size on any given
day. Autofix rewrote the tree to satisfy rules the Gate never checked, on every
Gate failure, and the Gate stayed red anyway: four `chore(autofix)` commits on
#42 and one on #51, ~143 files and +20,562/-11,089 each. Reverting one got it
re-pushed.

ruff.toml collapses them into one window — Ruff reads it from either surface, so
what Autofix fixes is exactly what the Gate checks — and this commit brings the
tree TO that canon, which makes the loop structurally dead rather than dormant.
Verified by replaying Autofix's three commands verbatim: `ruff check --select I
--fix`, `ruff check --fix`, `black -l 100 .` → zero changes, 196 files
unchanged. Deferring format instead would have left the loop armed;
`.autofix-exclude`, the only repo-owned lever, cannot express "do not format
this repo", and `autofix.yml` carries no `sync_mode`, so an edit there would be
overwritten by the next template sync.

Measured 2026-08-23 at the pinned versions, blocking / drainable:

  lint-ruff        39 -> 0 findings       drainable 39   ON, green
  lint-format      2 -> 0 files           drainable 2    ON, green
  python 3.12/3.13 0 failures                            ON, green
  typecheck-mypy   601 errors in 89/189   drainable 0    OFF, annotated
  coverage         1 startup error        drainable 0    OFF, annotated

Because #42's Autofix commits reached main first, the drain here is 39 findings
and 2 files rather than the 141 and 126 it would have been a day earlier.

Both OFF toggles state blocking AND drainable AND "drains by" at the single
place the toggles are computed, and a test fails if any of the three fields goes
missing — the runtime rule enforced rather than written down. One literal per
toggle: the `with:` block and the `summary` job's coverage branch both read
`needs.detect.outputs.*`, and a test rejects a second hardcoded value. mypy.ini
is committed although the check is off, because without it `mypy .` aborts on a
duplicate-module setup error and the 601 would be unverifiable prose; it
silences no error code, by test — fifteen `disable_error_code` entries would
cover 597 of the 601 and make the job green while checking nothing.
docs/CI_LINT_BASELINE.md records the baseline and
`scripts/ci_lint_baseline.py` regenerates it, refusing to print numbers measured
with unpinned tools. A `measured-with` line is asserted against the pin file, so
bumping a tool version without re-measuring goes red — the drain and the
measurement are wired to move together.

E501 is deliberately not selected: 1068 lines still exceed 100 columns after
`black -l 100`, all long strings, URLs and comment prose. Selecting it would be
selecting a rule with no drain. Three E402 findings are exempted per site with a
reason, because each import follows the `sys.path.insert` that makes it
resolvable; the rule stays on everywhere else. RUF100 is not selected, because
72 `# noqa` comments name rules the narrow set does not check and deleting them
would have to be undone the moment the selection widens.

Verified: `python3 verify.py` on the owner's machine — 402 passed, 0 failed, 0
skipped, 84/84 selftests, 43/43 CAN FIRE, 5/5 gates. Fresh-machine simulation
with empty ORCH_STATE_DIR and ORCH_LOCAL_RUNTIME: 394 passed, 8 skipped, 402
collected. CI-equivalent parallel run (`pytest -n auto --dist=loadgroup`): 393
passed, 9 skipped. Floor 391 -> 402 for the 11 new tests; no ceiling moved.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@stranske
stranske force-pushed the claude/gracious-murdock-2d1379 branch from 6387624 to 4298f92 Compare August 23, 2026 14:01
@agents-workflows-bot

Copy link
Copy Markdown
Contributor

Workflow source needed

PR #60 needs either a linked GitHub issue or one valid non-issue Workflow Source before PR metadata automation can manage it safely.

Please do one of:

  • Add <!-- meta:issue:123 --> or a normal Closes #123 / Related to #123 line.
  • Check one Workflow Source option in the PR body.
  • Add a hidden marker such as <!-- workflow-source:local_request -->, <!-- workflow-source:manual_remote -->, <!-- workflow-source:review_followup -->, <!-- workflow-source:sync_campaign -->, or <!-- workflow-source:dependabot -->.
  • Add a workflow source label such as workflow:source-direct-pr, workflow:source-local-request, workflow:source-review-followup, workflow:source-sync, or workflow:no-automation.

Once a valid source is present, this warning will not be reposted.

@github-actions

github-actions Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Workflow state fingerprint for Agents Gate Followups. Do not edit.

@agents-workflows-bot

agents-workflows-bot Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Automated Status Summary

Head SHA: a41aa3d
Latest Runs: ⏳ pending — Gate
Required: core tests (3.12): ⏳ pending, core tests (3.13): ⏳ pending, docker smoke: ⏳ pending, gate: ⏳ pending

Workflow / Job Result Logs
(no jobs reported) ⏳ pending

Updated automatically; will refresh on subsequent CI/Docker completions.


Keepalive checklist

Scope

No scope information available

Tasks

  • No tasks defined

Acceptance criteria

  • No acceptance criteria defined

Tim Stranske and others added 2 commits August 23, 2026 09:14
…in's floor at 391

#61 merged while this branch was in review. Merged it in and re-ran the count rather than assuming:
393 passed + 9 skipped = 402 collected, identical to the pre-#61 measurement, so #61 added no
collected tests and this floor is not sitting below reality. main's own floor is still 391, which is
exactly main-without-these-11 — no inherited drift to correct.

The merge is clean and #61's new code needs nothing: `ruff check` under this branch's ruff.toml
reports 0 findings and `black --check -l 100` leaves all 196 files unchanged, so the Gate stays green
across the merge rather than only on the branch.

verify.py on the merge result: 402 passed, 0 failed, 0 skipped, 84/84 selftests, 43/43 CAN FIRE,
5/5 gates.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@stranske
stranske temporarily deployed to agent-high-privilege August 23, 2026 14:22 — with GitHub Actions Inactive
@stranske
stranske merged commit bd6da2e into main Aug 23, 2026
54 of 55 checks passed
@stranske

Copy link
Copy Markdown
Owner Author

Independent verification of this PR from a separate session — I re-derived the root cause before finding this PR, and it matches. Two findings, one of them actionable here.

1. Dangling citation in the pin file (actionable)

.github/workflows/autofix-versions.env:24 says:

# so docs/ci/LINT_BASELINE.md records the numbers measured against exactly these versions and

The file this PR actually adds is docs/CI_LINT_BASELINE.md (repo root docs/, not docs/ci/ — that subdirectory doesn't exist here; docs/ holds CI_LINT_BASELINE.md alongside contracts/). pr-00-gate.yml and ruff.toml both cite the correct path, so this is the one outlier of three. Worth fixing because that comment is the sole pointer telling the next person where to re-measure before bumping a pin — which is precisely the coupling the surrounding paragraph exists to enforce.

2. emit-reference-run is not this PR's fault, and the upstream fix already exists

The one non-green check here is pre-existing, not a regression. backplane-conformance.yml has failed on all 9 runs, across four unrelated branches (sync/workflows-delivery, claude/entrypoint-diagnosis-tests, claude/profile-per-agent, and this one). This PR only triggered it by adding scripts/ci_lint_baseline.py, which matches the job's scripts/** path filter.

It dies on the same no-pyproject.toml cause as the coverage toggle documented in pr-00-gate.yml:

ERROR: file:///home/runner/work/Orchestrator/Orchestrator does not appear to be a Python project:
       neither 'setup.py' nor 'pyproject.toml' found.

stranske/Workflows has already fixed this in the consumer template, on main today — templates/consumer-repo/.github/workflows/backplane-conformance.yml now guards the install, and its comment names this exact failure mode:

      # Guarded: a consumer need not be an installable package (the template ships
      # no pyproject.toml). An unconditional editable install exits 1 on such a repo
      # and fails this job, which fails `conformance` via `needs` - turning the
      # documented opt-in skip above into a hard gate failure.
      - run: |
          if [ -f pyproject.toml ] || [ -f setup.py ] || [ -f setup.cfg ]; then
            pip install -e .
          else
            echo "No packaging metadata; skipping editable install (opt-in stub not yet tuned)."
          fi

This repo still carries the unguarded one-liner - run: pip install -e .. So no upstream issue is warranted — the only gap is that this repo hasn't received the refreshed file. The sync PR that would deliver it, #54, is CONFLICTING/DIRTY and hasn't moved since 07:55, so it will not arrive on its own. Refreshing that one file from the template would clear the last red here; whether it belongs in this PR or its own is your call.

3. Two claims verified independently

This PR needs a rebase, not another rebuild. #61, #64 and #65 all merged past the red gate after this PR's last push. Using the exact pinned versions (ruff 0.16.4, black 26.5.1) against this PR's ruff.toml, the four Python files those three merges touched — capability_propensity.py, improvement_log.py, research_subjects.py, test_improvement_log.py at current main — come back clean:

ruff check .                      → All checks passed!
black --line-length 100 --check . → 4 files would be left unchanged

So no new lint debt arrived behind you; the merge you already did at d3ed376 was sufficient.

The pyproject.toml correlation is causal, and it explains why this went unnoticed. Checking all 13 lane repos: the 12 others have both the pin file (620 bytes) and a pyproject.toml; Orchestrator has neither. maint-52-sync-dev-versions.yml copies the pin file only inside two steps, both gated on the consumer having a pyproject.toml (has_dev_deps == 'true', or has_pyproject == 'true' && has_dev_deps != 'true'). Every repo with a pyproject.toml received the file as a side effect of dev-version sync. The documented manual copy in docs/ci/WORKFLOWS.md:83 was load-bearing for exactly one repo — the only one without a pyproject.toml — which is why nobody noticed the step existed. Worth adding to the "HOW IT STAYS CORRECT" paragraph: the reason this repo is the sole instance is structural, not an oversight.

stranske pushed a commit that referenced this pull request Aug 23, 2026
CodeRabbit thread 3838730241 on #63, verified: the break keyed on an exact
substring including the trailing space, so a reformatted query would make
`str.replace` a silent no-op. The filter would keep protecting the row, the
corruption assertion would fail, and its message would blame the fix rather than
the stale fixture. It fails RED either way -- no false green -- but it misdiagnoses,
and in this repo a check has to name its own cause.

Two guards, because there are two ways to go stale, and only one was proposed:

1. The clause MOVES within a still-recognisable query -- asserted per statement,
   naming the clause it expected and printing the actual SQL.
2. The query itself becomes UNRECOGNISABLE, so nothing is ever stripped -- caught
   after the run by `stripped`. The review's guarded snippet asserts only WHEN the
   FROM/JOIN + ORDER BY signature matches, so a rewrite that changes the signature
   leaves the break silently inert and its assert never runs. That is the same hole
   one level up.

Not the review's first proposal, which is tautological: `broken != sql or clause
not in sql` cannot fail, since `clause in sql` makes `broken != sql` necessarily
true and the other branch covers the rest. Its second snippet is the right shape
and is what guard 1 implements.

The candidate query is identified by its FROM/JOIN plus ORDER BY fragments; the
not-terminal count query shares the FROM/JOIN but ends in GROUP BY, so it is not
mistaken for the candidate and other SQL passes through untouched.

Both guards demonstrated then reverted:
  clause "unresolved" -> " = 'unresolved' "  =>  "deliberate break is STALE: the
    candidate query no longer contains ... Update this fixture" + the real SQL
  ORDER BY r.ts DESC -> ASC (valid rewrite)  =>  "deliberate break never fired:
    nothing matched the candidate query's ... the assertions below prove nothing"

No new test, so the floor stays 392 (re-measured: 392 collected). verify.py: 392
passed, 0 failed, 0 skipped, 84/84 selftests, 5/5 gates. Clean under #60's
incoming ruff config and black -l 100.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
stranske pushed a commit that referenced this pull request Aug 23, 2026
Brings in #60 (`autofix-versions.env`, `ruff.toml`, `mypy.ini`, the tree drain), which is what every
red check on this PR was actually waiting for — all five python-ci jobs were dying at the shared
install step before any tool ran.

`capability_admission.py` auto-merged: #60 deletes the bare `cited` binding, this branch deletes it
and adds `_probe_live_root` in its place, so the two agree on the deletion and differ only in what
replaces it. Verified afterwards that the only remaining `cited = {d["record"]...}` in the file is
the docstring quoting it as the thing that was dropped.

ONE conflict, `langsmith-fleet-worker-attempt.json` (add/add): a generated worker-attempt telemetry
snapshot that each CI run rewrites. Resolved to main's copy verbatim, so this PR's diff against main
stays exactly one file. It is a single-object "last attempt" snapshot rather than a log, so taking
either side discards the other by design — not something to repair in a merge.

Net change vs main after the merge: capability_admission.py only, +84/-4.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
stranske pushed a commit that referenced this pull request Aug 23, 2026
…e-measured

#60 landed the `.github/workflows/autofix-versions.env` pin file that every
Python check on this PR was dying on, at the shared `Install dependencies` step
before any tool ran. It also brings this repo's first `ruff.toml` and `mypy.ini`,
so this change is linted for real for the first time rather than under Ruff's
88-column defaults.

Checked against the config that actually landed, not the branch preview:
  ruff check ledger_reconcile.py test_feedback_model_provenance.py  -> passed
  ruff check .                        (the Gate's own command)      -> passed
  black --line-length 100 --check     on both files                 -> unchanged

`.verify-floor.json` conflicted, as it has every round. Resolved as the UNION:
main's note is kept whole (it carries #60's +11 tests and the #64/#65 rationale)
with this branch's entry appended, and the count RE-MEASURED on the merge result
rather than either side's number -- `pytest --collect-only` reports 403, which is
main's 402 plus this branch's one test. No ceiling moved; nothing new is skipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
stranske added a commit that referenced this pull request Aug 23, 2026
Two follow-ups to #60, found while independently verifying it.

1. The pin file #60 added cited docs/ci/LINT_BASELINE.md; the file it added
   is docs/CI_LINT_BASELINE.md. docs/ci/ is the Workflows repo layout and
   does not exist here. That paragraph is the only pointer telling a reader
   to re-measure the baseline before bumping a pin, so it pointed nowhere.

2. test_ci_gate_config.py read the pin file CONTENTS thoroughly and its
   PROSE not at all, which is where (1) lived.
   test_every_cited_repo_path_resolves requires every repo-relative docs/,
   scripts/ or tools/ path cited in the two config files this repo OWNS to
   resolve. Scoped to those two: pr-00-gate.yml adds six findings that are
   all correct as written (check_issue_consistency.py behind hashFiles(...)
   != %s with a named skip, ledger_validate.py behind a .agents check,
   docs/ci/WORKFLOWS.md upstream), and a test that cries wolf gets waived.
   The upstream marker is scoped per PARAGRAPH, not per line, because the
   prose wraps and docs/ci/WORKFLOWS.md is quoted three lines below the
   sentence naming whose doc it is.

A third fix was DROPPED as redundant: this branch also carried the
backplane-conformance.yml editable-install guard, and #73 landed
byte-identical text from the same upstream template while this was open.

Deliberate break -> revert: restoring the original citation failed with
"autofix-versions.env paragraph at line 23 cites docs/ci/LINT_BASELINE.md";
reverting gave a cmp-clean file and 12 passed.

Floor re-measured five times as the base moved under this one-line change
(bd6da2e 402 -> ddb0928 402 -> fc1fd42 407 -> 0d661e3 407 -> 0593eeb 411,
each +1), never carried forward. verify.py green on the 0d661e3 rebase:
408 passed, 0 failed, 0 skipped, 84/84 selftests, 5/5 gates; re-based onto
0593eeb with the fast checks re-run (12 passed, 412 collected, ruff and
black clean) and the full suite left to CI.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
stranske added a commit that referenced this pull request Aug 23, 2026
…70)

* test(diagnostics): salvage PR #43's pytest coverage and fetch-first pointer

Rebuilt on current main (PR #43's branch was CONFLICTING and #46/#60 have since reshaped both
files). #43 and #46 built the entrypoint-absence diagnostic independently and in parallel; #46
merged first, so this lifts the three things #43 had that #46 lacked rather than losing them with
the closed PR.

1. `test_an_absent_entrypoint_diagnoses_itself_differently_from_a_real_defect` — #46 put the
   equivalent checks in `capability_activation_audit --selftest`, and a selftest is NOT guarded by
   `.verify-floor.json`. Only a COLLECTED test is, so this is the half that makes the behaviour
   hold.

2. `test_the_capability_gates_all_consult_the_entrypoint_diagnosis` — the sharper idea, with no
   equivalent in #46 at all: nothing else notices if one of the three gates quietly stops calling
   the helper and reverts to a bare capability id. It matches the CALL, not the bare name, because
   all three files also MENTION the helper in a comment — a name-only grep would keep passing after
   someone deleted the call and left the comment behind.

3. The `git fetch --all && git log --all --oneline -- <module>` pointer, WITH its caveat. `git log
   --all` is the natural next probe and on 2026-08-22 it came back empty for a module that existed,
   because the branch holding it had never been fetched into that checkout. An empty result there
   means "not fetched", never "does not exist", so the command and its precondition travel together
   or the pointer reproduces the misreading it exists to prevent.

Also adds `absent_entrypoint_report(..., ledger=)` / `absent_entrypoint_note(..., ledger=)` so both
tests inject their rows instead of reading the running instance's ledger. That is why neither test
skips anywhere: the interesting case is one row present and one absent, and no real ledger is
reliably both. A machine-independent test is the preferred way to grow this suite — see the
24 -> 26 -> 24 ceiling episode in `.verify-floor.json`.

FLOOR 402 -> 404, measured on the merge result, and it must be exact now that #56 made `collected`
an EQUALITY. No ceiling moved and nothing new is skipped.

Deliberate break -> revert, each caught then reverted byte-identically:
  * stripped one gate's call to the helper while leaving the comment behind — the drift guard fired
    and named the file;
  * dropped the fetch-first caveat from the pointer — the pointer assertion fired.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(diagnostics): two CodeRabbit findings — a short-circuit and a vacuous guard

Both from the review on PR #51, both real, and the second is embarrassing in a useful way.

1. THE FETCH COMMAND OMITTED THE MODULES THAT MATTERED MOST. The module list behind
   `git log --all` was `{sibling hits} or {missing candidates}`. `or` short-circuits, so as soon as
   ONE absent row was found in a sibling checkout, the candidates of every row found NOWHERE were
   dropped — and those are precisely the rows the pointer exists for, because a module in no sibling
   checkout is the one most likely to sit on an unfetched remote branch. The command said "to check
   every branch" while silently omitting the hardest cases. Now a union, with the truncation counted
   rather than silent (`+N more module(s) not shown`), because a cap that hides modules would put
   the same lie back in a smaller place.

2. THE DRIFT GUARD WAS VACUOUS FOR ITS OWN FILE. It searched each whole FILE for the substring
   `audit.absent_entrypoint_note(` — which appears SIX times in `test_capability_set_coverage.py`
   alone: in the docstring, in sibling tests, and inside the assertion itself. So deleting the real
   call from the recurrence-fixture gate left the guard passing. A guard written specifically to
   catch a check that cannot fail, that itself could not fail. That is this repo's founding defect
   wearing the uniform of its own countermeasure.

   It now walks the AST of ONE NAMED FUNCTION per file, from an explicit `GATE_CALL_SITES` mapping.
   A string literal or a comment cannot satisfy an AST call match at all, and a RENAMED gate asserts
   rather than passing quietly — "some call somewhere in the file" was the whole weakness.

Deliberate break -> revert, each caught then reverted byte-identically:
  * union -> `or`: the new regression test failed naming the exact omission (`b_lane.py` absent from
    the command while `a_lane.py` was present);
  * deleted the real call from this file's gate, leaving all six literals in place: the AST guard
    failed where the substring version had passed — the specific hole CodeRabbit found;
  * renamed a gate function: caught, with a message saying to update `GATE_CALL_SITES` deliberately.

FLOOR 404 -> 405: one new test,
`test_the_fetch_command_names_every_absent_module_not_just_the_found_ones`. It needs BOTH kinds of
absent row present at once, which is why it is its own test rather than more assertions on an
existing one — with only one kind, `or` and `|` are indistinguishable. It injects its ledger rows,
so it skips nowhere. No ceiling moved.

Verified with `python3 verify.py`: 405 passed, 0 failed, 0 skipped, 84/84 selftests, 43/43 can-fire,
5/5 gates. `ruff check .` and `black --check --line-length 100` both clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test(diagnostics): address PR #70 CodeRabbit threads

Add truncation regression for seven-plus absent modules and tighten the
AST gate predicate to require audit.absent_entrypoint_note in the named
function body only, ignoring nested defs and non-audit receivers.

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore(autofix): formatting/lint

* chore(verify): raise floor to 415 on PR #70 merge result

CI measured 415 collected (389 passed + 26 skipped) after merging
main into the diagnostics salvage branch.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Tim Stranske <tim@stranskemo.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
stranske added a commit that referenced this pull request Aug 23, 2026
The pin file #60 added cited docs/ci/LINT_BASELINE.md; the file it added is
docs/CI_LINT_BASELINE.md. docs/ci/ is the Workflows repo layout and does not
exist here, so the only pointer telling a reader to re-measure the baseline
before bumping a pin led nowhere.

test_ci_gate_config.py read that file CONTENTS thoroughly and its PROSE not
at all, which is where the defect lived. test_every_cited_repo_path_resolves
requires every repo-relative docs/, scripts/ or tools/ path cited in the two
config files this repo OWNS to resolve. Scoped to those two: pr-00-gate.yml
yields six findings that are all correct as written, and a test that cries
wolf gets waived. The upstream marker is per PARAGRAPH, not per line, because
the prose wraps.

Deliberate break -> revert: restoring the original citation failed with
"autofix-versions.env paragraph at line 23 cites docs/ci/LINT_BASELINE.md";
reverting gave a cmp-clean file and 12 passed.

A third fix was dropped as redundant: #73 landed byte-identical
backplane-conformance.yml text from the same upstream template while this
was open.

Floor re-measured six times as the base moved under this one-line change
(402 -> 402 -> 407 -> 407 -> 411 -> 415, each +1). verify.py green on the
0d661e3 rebase: 408 passed, 0 failed, 0 skipped, 84/84 selftests, 5/5 gates;
fast checks re-run on each later base (12 passed, 416 collected, ruff and
black clean) with the full suite left to CI.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
stranske added a commit that referenced this pull request Aug 23, 2026
The pin file #60 added cited docs/ci/LINT_BASELINE.md; the file it added is
docs/CI_LINT_BASELINE.md. docs/ci/ is the Workflows repo layout and does not
exist here, so the only pointer telling a reader to re-measure the baseline
before bumping a pin led nowhere.

test_ci_gate_config.py read that file CONTENTS thoroughly and its PROSE not
at all, which is where the defect lived. test_every_cited_repo_path_resolves
requires every repo-relative docs/, scripts/ or tools/ path cited in the two
config files this repo OWNS to resolve. Scoped to those two: pr-00-gate.yml
yields six findings that are all correct as written, and a test that cries
wolf gets waived. The upstream marker is per PARAGRAPH, not per line, because
the prose wraps.

Deliberate break -> revert: restoring the original citation failed with
"autofix-versions.env paragraph at line 23 cites docs/ci/LINT_BASELINE.md";
reverting gave a cmp-clean file and 12 passed.

A third fix was dropped as redundant: #73 landed byte-identical
backplane-conformance.yml text from the same upstream template while this
was open.

Floor re-measured six times as the base moved under this one-line change
(402 -> 402 -> 407 -> 407 -> 411 -> 415, each +1). verify.py green on the
0d661e3 rebase: 408 passed, 0 failed, 0 skipped, 84/84 selftests, 5/5 gates;
fast checks re-run on each later base (12 passed, 416 collected, ruff and
black clean) with the full suite left to CI.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
@stranske
stranske deleted the claude/gracious-murdock-2d1379 branch August 23, 2026 22:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant