style+fix: conform to the fleet's black and ruff gates (B and C) - #58
style+fix: conform to the fleet's black and ruff gates (B and C)#58stranske wants to merge 2 commits into
Conversation
…no logic change)
`pr-00-gate.yml` calls `stranske/Workflows/.github/workflows/reusable-10-ci-python.yml@main`,
whose format job runs exactly:
black --check --line-length 100 --exclude '(\.venv|\.workflows-lib|node_modules)' .
That gate started firing on this repo and failed, because the tree had never been black-formatted.
This runs the formatter with those exact arguments, so the check and the tree agree by construction
rather than by coincidence.
WHOLLY MECHANICAL. `black` verifies AST equivalence on every file it rewrites, and `verify.py` is
green on the result: 368 passed, 0 failed, 0 skipped, 83/83 selftests, 43/43 can-fire, 5/5 gates.
No floor or ceiling moves — nothing was added, removed or renamed. Review the next commit instead;
this one is the formatter's output.
WHAT IT ACTUALLY CHANGES, measured rather than assumed. Code only: tuple/list literals exploded one
per line, implicitly-concatenated strings re-indented, `a; b` split onto two lines. It also collapses
the column-aligned padding before a trailing `#` comment to two spaces, which this tree used
extensively — 244 comment-bearing lines are byte-identical after whitespace normalisation. No comment
or docstring PROSE is reworded or reflowed anywhere; black does not touch either.
A note on measurement, because the first attempt at this was wrong. Running bare `black --check .`
reports 180 files, and bare `ruff check .` reports 914 errors — both artefacts of this repo having
no `pyproject.toml`, so the tools fall back to their own defaults (line length 88; the full ruff
rule set) rather than to what CI runs. At CI's real settings the numbers are 126 files and 79 lint
findings. Always take the command line from `reusable-10-ci-python.yml`, not from the tool default.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`reusable-10-ci-python.yml:1155` runs `ruff check --select E4,E7,E9,F` when a repo declares no
explicit rule selection — pyflakes plus the serious pycodestyle errors, i.e. real defects rather
than style. This clears all of them. `ruff check --select E4,E7,E9,F --extend-exclude
.workflows-lib .` now passes.
The previous commit (black) already removed all 18 `E702` semicolon statements, leaving 61.
MECHANICAL (54):
* F401 x25 unused imports, F541 x2 empty f-strings — `ruff --fix`. Each of the five that could
plausibly have been a re-export (`ux_review.MIN_EVALUATORS`, `EVALUATOR_TOPUP_ORDER`,
`periodic_report.execution_profiles`, `capability_targets.repo_knowledge`,
`capability_propensity.env_prereq`) was grepped for use elsewhere first; none had any.
* E741 x19 ambiguous `l` — every instance is a comprehension variable whose scope is its own
line, renamed to what it holds (`lb` for labels, `link`, `lab`, `ln` for a JSON line).
* E731 x7 lambda assignments -> `def`. In `exp_abcd.py` the default-arg capture
(`repo=meta["repo"], exp_id=edir.name`) is LOAD-BEARING — it binds this iteration's values so a
later loop turn cannot rebind them — and is preserved verbatim in the def signature.
* E402 x1: a stray mid-file `import math` in `feedback.py`, moved to the import block. Not a
cycle-avoidance lazy import; those live inside functions and stay there.
REAL DEFECTS the gate found (3):
* `test_observability_activation.py` set `"route_weights"` TWICE in one dict literal (lines 52 and
90). Same value, so no behaviour changed, but one silently overrode the other.
* `verify.py` unpacked `fc, fp` in `verify()` while only `fc` is used — a leftover from the
refactor that moved the passed-floor comparison into `_floor_problems`. Removed there and kept
in `_floor_problems`, which genuinely uses both.
* `capability_admission.py` computed `cited = {d["record"] for d in com["dangling_citations"]}`
and asserted nothing on it. That is this repo's founding defect in miniature — a value computed
for a check that no longer checks. The dead binding is removed; the MISSING assertion is not
invented here.
DELIBERATELY NOT REPAIRED, flagged instead: `keepalive_evidence.py` built
`haystack = f"#{issue_number} {issue_title}"` and then searched `issue_title` alone, so a bare `#N`
reference in a title is never matched. Wiring `haystack` in would change what the keepalive
evidence path MATCHES, and that is Brain input (CLAUDE.md 2) — a behaviour change has no business
riding along in a lint pass. Only the unused binding is removed, which changes nothing.
A note on method: the first edit here replaced the wrong `fc, fp = ...` occurrence and broke
`_floor_problems`. `ruff --select F821` named it immediately ("Undefined name `fp`", three sites) —
which is the argument for this gate existing rather than being configured away.
Verified with `python3 verify.py`: 368 passed, 0 failed, 0 skipped, 83/83 selftests, 43/43
can-fire, 5/5 gates. Floor and ceilings untouched — nothing added, removed or renamed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 5 minutes Limit details: You’ve used the included review currently available. Your 74 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 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 configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: 📒 Files selected for processing (126)
Comment |
|
Closing — superseded by #60, which has the root cause this PR does not. I built this from a local measurement without checking open PRs or the improvement log first. #60 got there properly, and its diagnosis invalidates the premise of this PR: all five upstream jobs were dying at a shared install step — Ruff, Black and mypy had never executed on this repo, not once. Every statement about its lint debt, mine included, was inferred. #60 adds the missing pin file, plus It also explains why my 126-file black pass was largely wasted: the repo self-heals formatting via its own autofix workflow ( One thing from here worth carrying over if it is not already in #60, since these were verified against live code:
And a correction to my own earlier claim on #58: the 🤖 Addressed by Claude Code |
…y it stays dead
`_dedupe_candidate` built `haystack = f"#{issue_number} {issue_title}"` and then searched
`issue_title` and `candidate["seed"]` only. ruff F841 flagged the unused local; PR #58 removed
the binding as lint. This decides the question that removal left open — was the combined form
the intent? No, and it is inert rather than merely unused:
* Substituting `haystack` for `issue_title` in the first `_contains_pr_ref` adds EXACTLY one
condition, `issue_number == pr_number`. It does not widen the text searched. Checked by brute
force over 200k random (issue_number, pr_number, title) triples: 0 mismatches against
`ref(title, pr) or issue_number == pr`.
* That condition cannot occur: GitHub draws issue and PR numbers from one per-repo sequence.
Over recorded history — 202 dedupe-eligible candidates (reverted/abandoned keepalive rows
carrying a PR number, 2026-01-08..2026-08-22, 11 repos) against 4,031 issues in those same
repos — 0 number collisions.
* And it is already covered even if it could: every seed `evidence_for_repo` builds opens with
"PR #{pr_number}", so the adjacent `_contains_pr_ref(candidate["seed"], issue_number)`
disjunct is already true in exactly that case. Differential run of the real
`_dedupe_candidate` against a haystack-wired copy over 120k real-shaped candidates, with
`issue_number == pr_number` forced in ~40% of search hits: 0 behaviour differences.
So the effect on matching is +0 candidates, not merely over history but under any input. The one
way it could ever fire is as a false positive claiming duplication from a numeric coincidence.
Also corrects the premise behind the question: `_contains_pr_ref` ALREADY matches a bare "#N" in
an issue title — the "#" in `#?{n}` is optional and `(?<!\d)` excludes only a preceding digit.
Nothing here changes what the path matches, so CLAUDE.md §2 is satisfied by the change being a
true no-op rather than by deferring it. The genuine widening, if ever wanted, is the sibling
pattern in durability_sweep.py — title -> title+body, which widens the TEXT.
The explanation sits ABOVE the matching loop rather than in the deleted line's slot, so an
identical deletion on both sides merges cleanly with PR #58 instead of conflicting.
Selftest pins the decision with two assertions and a deliberate-break -> revert demonstration:
wiring the haystack in fails assertion 1 (exit 1); removing "PR #<pr>" from the reversal seed
fails assertion 2 (exit 1); revert restores byte-for-byte and both pass (exit 0).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…is redundant PR #58's entire change to keepalive_evidence.py is two deletions: the dead `haystack` binding (decided in the previous commit) and this unused `repo = target.split("#", 1)[0]` in the selftest loop — `record_run` is passed `target`, never `repo`. Taking both makes this branch's copy of the file a superset of #58's, and since both are now identical deletions on both sides, the file merges with zero conflicts in either order — verified with a 3-way merge against origin/claude/ci-conform-format-lint. `ruff check --select E4,E7,E9,F` is clean for this file and `black --line-length 100 --check` leaves it unchanged. #58 is separately CONFLICTING against main (it predates #59 and is a tree-wide black pass), so it needs a rebase regardless — that is not caused by this branch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Conforms this repo to the fleet's format and lint gates. B and C only —
pyproject.toml(A) is held pending thesrc/layout question.Two commits, deliberately separate:
4117aa2black --line-length 100— 126 files, purely mechanical14ccb6dWhy these were failing
pr-00-gate.ymlcallsstranske/Workflows/.github/workflows/reusable-10-ci-python.yml@main. Its two relevant jobs run, verbatim:The ruff line is the no-explicit-selection fallback — pyflakes plus serious pycodestyle, i.e. real defects rather than style. Both now pass.
A measurement correction worth recording
My first pass reported 914 ruff errors and 180 files needing black, and concluded the gate was unreasonable. Both numbers were artefacts of running the tools bare: with no
pyproject.tomlpresent they fall back to their own defaults (line length 88; the full ruff rule set), not to what CI runs. At CI's real settings it was 126 files and 79 findings — and after black split the 18E702semicolons, 61.Take the command line from
reusable-10-ci-python.yml, never from the tool default.What black actually changes, measured
Code only: tuple/list literals exploded one per line, implicit string concatenation re-indented,
a; bsplit. It also collapses the column-aligned padding before trailing#comments to two spaces, which this tree used extensively — 244 comment-bearing lines are byte-identical after whitespace normalisation. No comment or docstring prose is reworded or reflowed anywhere. (I initially claimed "0 comment lines touched" from a single-file sample; the inline-alignment collapse is real, and cosmetic.)blackverifies AST equivalence on every file it rewrites.The three real defects ruff found
test_observability_activation.pyset"route_weights"twice in one dict literal (lines 52 and 90). Same value, so no behaviour changed — but one silently overrode the other.verify.pyunpackedfc, fpinverify()while onlyfcis used — a leftover from the refactor that moved the passed-floor comparison into_floor_problems. Removed there, kept in_floor_problems, which genuinely uses both.capability_admission.pycomputedcited = {d["record"] for d in com["dangling_citations"]}and asserted nothing on it. This repo's founding defect in miniature: a value computed for a check that no longer checks. The dead binding is removed; the missing assertion is not invented here — that needs a decision about what it should assert.Deliberately not repaired
keepalive_evidence.pybuilthaystack = f"#{issue_number} {issue_title}"and then searchedissue_titlealone — so a bare#Nreference in a title is never matched. Wiringhaystackin would change what the keepalive evidence path matches, and that is Brain input (CLAUDE.md §2). A behaviour change has no business riding along in a lint pass. Only the unused binding is removed, which changes nothing.Also load-bearing and preserved: in
exp_abcd.pythe lambda→def conversion keeps the default-arg capturerepo=meta["repo"], exp_id=edir.nameverbatim in the signature — it binds this iteration's values so a later loop turn cannot rebind them.Method note
My first edit replaced the wrong
fc, fp = ...occurrence and broke_floor_problems.ruff --select F821named it immediately — "Undefined namefp", three sites. That is the argument for this gate existing rather than being configured away.Test gate
python3 verify.py— 368 passed, 0 failed, 0 skipped, 83/83 selftests, 43/43 can-fire, 5/5 gates. Floor and ceilings untouched: nothing was added, removed or renamed.Both gates re-run exactly as CI invokes them:
black --check→ 192 files unchanged;ruff check --select E4,E7,E9,F→ All checks passed.Still red after this, and why
python 3.12/3.13/typecheck-mypyneedpyproject.toml(CI passes--cov-config=pyproject.toml, which currently raisesConfigError). That is commit A, held pending thesrc/layout decision.🤖 Generated with Claude Code