Uh oh!
There was an error while loading. Please reload this page.
feat(code-quality): opt-in black --check format job (diff-scoped) - #115
Conversation
Closes the last Layer-0/1 gap on backend#1303: black is CI-enforced only in backend (its own lint.yml). This adds a shared, opt-in 'format' job so any repo can enforce formatting without standing up its own workflow. Diff-scoped like ruff: only the .py files a PR changes must be black-clean (all files in all-files mode). That matters because every Python repo except backend has a real formatting backlog (measured 2026-07-31 with black 26.3.1: engine 157, py-package 168, data-ingestors 78, averaging 71, client-runtime 15; backend 0). Diff scoping means a repo can adopt the gate with zero churn instead of a repo-wide reformat that would collide with in-flight work. 'format-soft-fail' lets a repo adopt advisory-first while its lint and credential gates stay blocking. 'black-version' is pinned per caller because black's stable style changes between releases; no repo enables this job by default, so nothing changes until a caller opts in. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
LukasWodka
commented
Jul 31, 2026
👋 Heads-up — Code review queue is at 35 / 30 Above the WIP limit. The team convention is to review existing PRs before opening new work. Open PRs currently in Code review (oldest first):
Pull from review before opening new work. (This is a nudge from the kanban WIP check, not a block.) |
LukasWodka
commented
Jul 31, 2026
bugbot run |
Uh oh!
There was an error while loading. Please reload this page.
aptracebloc
commented
Jul 31, 2026
Confirmed the Bugbot "xargs remaps soft-fail exit code" finding — it's a real High, not a false positive. Trace: Diff mode (L381-383) runs Exit handling (L401-406) then hits the fail-closed branch first: # RC 123 = internal error (unparsable file), not a formatting verdict.if [ "$RC"!="0" ] && [ "$RC"!="1" ];then# 123 → both trueecho"::error::black exited $RC ... - failing closed."exit"$RC"# exits before the soft-fail checkfiif [ "$RC"!="0" ] && [ "$SOFT_FAIL"="true" ];thenexit 0;fi# never reached in diff modeSo on the diff-scoped path — the job's primary mode — an ordinary "would reformat" always hard-fails, even with Since if [ "$RC"!="0" ] && [ "$RC"!="1" ];then# Diff mode runs black under xargs, which remaps black's exit 1 -> 123.# It's a real internal error only if there are no "would reformat" lines.if [ "$COUNT"-gt 0 ];then
RC=1
elseecho"::error::black exited $RC (not a formatting failure) - failing closed."
cat /tmp/black.out
exit"$RC"fifiThat restores advisory behavior on the diff path while still failing closed on genuine internal errors. Given the whole caller rollout is advisory (soft-fail), worth fixing before repos opt into the format job in diff mode — otherwise the first unformatted file hard-blocks them. |
Bugbot + @aptracebloc: in diff mode black runs under xargs, and GNU xargs remaps any child status in 1-125 to its own 123. So black's ordinary 'would reformat' (exit 1) arrived as 123, hit the fail-closed branch, and hard-failed before soft-fail could apply -- advisory adoption was impossible on the job's primary path, and a real internal error looked identical to a formatting nit. Now the verdict comes from black's OUTPUT: reformat-count vs error-count, checked errors-first so a genuine internal error is never masked by a reformat finding in the same run (the residual hole in the suggested RC=1 rewrite). Exit codes are only a tiebreaker for 'nonzero with no findings', which still fails closed. Why local validation missed it: BSD/macOS xargs propagates 1, GNU xargs remaps to 123 -- verified both. Simulated all 8 outcome combinations (dirty/unparsable/clean x advisory/blocking x diff/all-files). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
LukasWodka
commented
Jul 31, 2026
@aptracebloc confirmed and fixed — thank you, that was a real High and your trace was exact. Verified the platform difference empirically, which is also why my local validation gave a false green: Fix ( ERRS=$(grep -cE '^error:|would fail to reformat' /tmp/black.out || true)if [ "${ERRS:-0}"-gt 0 ];then ... fail closed, always ...
elif [ "${COUNT:-0}"-gt 0 ];then ... soft-fail applies here ...
elif [ "$RC"!="0" ];then ... nonzero with no findings -> fail closed ...Exit codes are now only a tiebreaker for "nonzero but reported nothing". Simulated all 8 combinations (dirty / unparsable / clean × advisory / blocking × diff / all-files) with rc forced to 123 to mimic GNU xargs: advisory now passes on a dirty diff, blocking fails, an unparsable file fails closed regardless of soft-fail, and error+dirty in one run fails closed. Clean stays clean. Side note: the errors-vs-verdicts distinction this fix rests on is the same one that produced a bogus "0 files need formatting" in the #1303 sizing (black 23.1.0 can't run on Python 3.12+ — |
LukasWodka
commented
Jul 31, 2026
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit affc564. Configure here.
Uh oh!
There was an error while loading. Please reload this page.
…#314) * ci(2364): a PR whose title names a ticket must link it (backend#2364) Merging a fix never closed or advanced its ticket. `closingIssuesReferences` was 0 on 7 of 7 sampled merged PRs (release-train#109/#108, .github#304/#300, backend#2266, client#774, docs#131). The house convention puts the ticket in the PR TITLE; GitHub creates a closing link ONLY from a keyword in the BODY, so a title reference is inert. `kanban-closure-router.yml` fires, finds no linked issue, and correctly does nothing -- every kanban workflow green, every card unmoved. Adds a `closing-ref` job to the EXISTING `set-pr-status.yml` reusable: parse the real title, assert the real `closingIssuesReferences` contains what it names. Derived, not restated (rule 1): two live reads, no list of tickets, repos or authors. The four title forms are measured, not imagined. A bare `#N` outside parentheses is deliberately NOT read as a ticket -- backend#2309's `#2271` is prose about a PR, and scanning loose `#N` would redden a compliant PR. Fails closed (rule 3): a blank title, a GraphQL error, `pullRequest: null`, a null/ownerless node, or `totalCount > len(nodes)` all exit 2 as "cannot tell", never a pass and never a finding against the author. The truncation test is load-bearing beyond pagination -- a link to an issue the token cannot read comes back missing from `nodes` while `totalCount` still counts it, which is indistinguishable from "not linked". The cross-repo trap is its own verdict: `WRONG_REPO` is reported apart from `MISSING` because the remedies differ -- a bare `Closes#304` in `.github` links `.github#304`, closing the wrong issue on merge, and needs the line rewritten rather than added. Fixtures are measured bytes (the backend#2114 lesson), captured with `gh api graphql` and re-verified against the live API before commit. Tests: 102 selftest assertions; 34 mutations, 0 stale, 0 uncaught. The mutation harness edits the real gate and re-runs the real suite -- no inline copy of any rule (rule 9, .github#114/#115). Every anchor must match exactly once, which is the assertion that it actually applied. Refusals are asserted by their own message, never a catch-all (rule 10). The commit-type vocabulary is derived out of org-standards.md and the derivation fails closed if it finds nothing (rule 6). Arming: `closing-ref` is a required status check NOWHERE -- measured across 19 repos x develop/staging/main/master x both classic protection and rulesets -- so a finding blocks no merge (rule 4). Callers trigger on opened/reopened/ready_for_review/converted_to_draft, not `synchronize`, so the 13 open PRs that would report a finding are not reddened by a push. Touches no file in `conformance-gate.yml`'s GUARDED list, and needs no `repo-inventory.yml` row: the inventory tracks callers, one row per reusable, and `set-pr-status.yml` already has its rows. Closestracebloc/backend#2364 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(2364): the remedy stops guessing a repo it cannot know (backend#2364) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(2364): the scope pattern admits a leading dot too, so .github stops depending on a coincidence (backend#2364) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
What
Adds an opt-in
formatjob (black --check) to the sharedcode-quality.yml. Nothing changes for any repo until a caller setsformat: true— no caller does in this PR.Why (backend#1303, the epic's last item)
Black is CI-enforced in backend only (its own
lint.yml, pinned fromrequirements-dev.txt). Everywhere else, the pre-commit hooks from #1307 are the only formatting signal, and those are opt-in per developer.The design decision: diff-scoped, not repo-wide
Measured today (black 26.3.1, zero parse errors, so these are real verdicts):
So there is a genuine ~470-file backlog outside backend. A repo-wide
black .sweep right now would collide with the 33 open Code-review PRs and the 23 items sitting in Ready for prod, and would damagegit blameacross five repos.Instead the job is diff-scoped like ruff: only the
.pyfiles a PR changes must be black-clean (all files inall-filesmode). A repo can adopt the gate at zero churn and the tree converges as files are touched.Inputs
format(defaultfalse) — opt in.black-version(default"23.1.0") — pin per caller. black's stable style changes between releases; a mismatched version reports the whole repo as unformatted.format-soft-fail(defaultfalse) — adopt advisory-first while ruff/gitleaks stay blocking.Correctness notes
--isolated: black reads the repo's own[tool.black](line-length/target-version/exclude), so CI matches what contributors run locally.--no-run-if-empty— paths with spaces survive, and an empty changed-file list never silently checks the whole repo.Test plan
actionlintclean.Part of tracebloc/backend#1303
🤖 Generated with Claude Code
Note
Low Risk
Behavior is gated behind
format: falseby default; changes only affect repos that explicitly opt in to the new CI job.Overview
Extends the reusable
code-quality.ymlwith an opt-informatjob (black --check) that is off by default until a caller setsformat: true.New inputs:
format,format-soft-fail(format-only advisory mode), andblack-version(default23.1.0to match the fleet). Scope mirrors ruff: changed.pyfiles on PRs, or the whole tree whenall-filesis set, with the same three-dot diff and fail-open-to-all-files behavior.The job installs black via pipx, respects the repo’s
[tool.black](no--isolated), and writes a step summary. Pass/fail is driven by black’s output, not raw exit codes—so GNU xargs remapping reformat failures to 123 does not break advisory adopters, parse/processing errors are fail-closed and not treated as “needs formatting,” andsoft-fail/format-soft-failonly soften real reformat findings.Reviewed by Cursor Bugbot for commit affc564. Bugbot is set up for automated code reviews on this repo. Configure here.