feat(780): commit a ruff config and enforce it in CI #813

Merged
timothy merged 12 commits from fix/780-ruff-config into main 2026-08-22 02:33:20 +02:00
Owner

fixes #780

Python lint here was a property of the operator's laptop, not of the repo: the global instructions say to run ruff check / ruff format --check / pyright, no workflow or hook ran any of them, and with no committed config ruff fell back to whichever ~/.config/ruff/ruff.toml the machine happened to have. Option 1 from the issue.

  • ruff.toml at the root — the operator's global settings, pinned into the repo, narrowed at per-file-ignores.
  • Gated in the script-tests job (renamed Script lint and tests (ruff + pytest)): a pinned ruff==0.12.11, ruff check . + ruff format --check ., as the job's first steps — behind Preflight jq version (a hard --expect tripwire) the lint would go dark for as long as the jq contract was broken, under a red that names jq.
  • Population guard. ruff check . on an empty population warns on stderr and exits 0, so a stray exclude would switch the gate off silently. The step compares --show-files against git ls-files '*.py' and fails on drift. Witnessed: a top-level exclude = ["scripts"] takes ruff check green and the step to ::error::… 0 Python files but git tracks 33. (The same exclude under [format] does not reproduce it — it scopes to the formatter, and a mutation written there passes while proving nothing.)
  • Tree made clean: 72 findings against 706674272 — 54 fixed in code (mostly the ruff format pass), 18 per-site # noqa with the reason inline. S105 is deliberately not exempted directory-wide: a blanket would give up hardcoded-credential coverage over the largest Python surface in the repo to suppress 8 known lines.
  • pyright stays ungated — its only findings are etv_client imports resolvable solely in that script's deploy environment; gating it would put a node toolchain on the git-only small lane to find nothing.

The temporary commit b2e9942 is a deliberate lint violation so the new steps are witnessed red on the runner rather than assumed to work; it is reverted in the following commit once the red is recorded here.

Docs in the same PR: new record ci.python-lint-ruff-config-committed, cross-ref from ci.script-tests-job, docs/ci-cd.md (which also had a stale ~190 tests / ~10s figure — measured 773 tests, ~4.5 min), and docs/defect-shapes-773.md §5.2 marked resolved with a reproducible measurement.

Cold review: Opus, high effort, isolated worktree. It cleared the mechanical reformat (25 of 33 files AST-identical to main, identical collected node IDs, byte-equivalent f-string conversions) and raised 3 HIGH + 4 MEDIUM in the config/CI/doc layer, all addressed in 85ecd35.

fixes #780 Python lint here was a property of the operator's laptop, not of the repo: the global instructions say to run `ruff check` / `ruff format --check` / `pyright`, no workflow or hook ran any of them, and with no committed config ruff fell back to whichever `~/.config/ruff/ruff.toml` the machine happened to have. Option 1 from the issue. - **`ruff.toml` at the root** — the operator's global settings, pinned into the repo, narrowed at `per-file-ignores`. - **Gated in the `script-tests` job** (renamed `Script lint and tests (ruff + pytest)`): a pinned `ruff==0.12.11`, `ruff check .` + `ruff format --check .`, as the job's **first** steps — behind `Preflight jq version` (a hard `--expect` tripwire) the lint would go dark for as long as the jq contract was broken, under a red that names jq. - **Population guard.** `ruff check .` on an empty population warns on stderr and exits **0**, so a stray `exclude` would switch the gate off silently. The step compares `--show-files` against `git ls-files '*.py'` and fails on drift. Witnessed: a top-level `exclude = ["scripts"]` takes `ruff check` green and the step to `::error::… 0 Python files but git tracks 33`. (The same `exclude` under `[format]` does **not** reproduce it — it scopes to the formatter, and a mutation written there passes while proving nothing.) - **Tree made clean**: 72 findings against `706674272` — 54 fixed in code (mostly the `ruff format` pass), 18 per-site `# noqa` with the reason inline. `S105` is deliberately **not** exempted directory-wide: a blanket would give up hardcoded-credential coverage over the largest Python surface in the repo to suppress 8 known lines. - **`pyright` stays ungated** — its only findings are `etv_client` imports resolvable solely in that script's deploy environment; gating it would put a node toolchain on the git-only `small` lane to find nothing. **The temporary commit `b2e9942` is a deliberate lint violation** so the new steps are witnessed red on the runner rather than assumed to work; it is reverted in the following commit once the red is recorded here. Docs in the same PR: new record `ci.python-lint-ruff-config-committed`, cross-ref from `ci.script-tests-job`, `docs/ci-cd.md` (which also had a stale `~190 tests / ~10s` figure — measured 773 tests, ~4.5 min), and `docs/defect-shapes-773.md` §5.2 marked resolved with a reproducible measurement. Cold review: Opus, high effort, isolated worktree. It cleared the mechanical reformat (25 of 33 files AST-identical to main, identical collected node IDs, byte-equivalent f-string conversions) and raised 3 HIGH + 4 MEDIUM in the config/CI/doc layer, all addressed in `85ecd35`.
timothy added 3 commits 2026-08-21 23:13:25 +02:00
Python lint here was a property of the operator's laptop, not of the repo: the
global instructions say to run `ruff check`/`ruff format --check`/`pyright`, no
workflow or hook ran any of them, and with no committed config ruff fell back to
whichever `~/.config/ruff/ruff.toml` the machine happened to have. A second
machine lints this repo differently, or not at all — Family E in
docs/defect-shapes-773.md, in our own toolchain.

Option 1 from the issue:

- `ruff.toml` at the root (the operator's global settings, pinned here — that is
  what the tree was de-facto written against, so adopting it cost a mechanical
  reformat rather than a rewrite).
- The `script-tests` job installs a PINNED `ruff==0.12.11` and runs
  `ruff check .` + `ruff format --check .` before pytest, so a style red arrives
  in seconds instead of after the four-minute suite. The pin is the second half
  of the fix: an unpinned install re-introduces the same divergence one layer up.
  Renamed the job to `Script lint and tests (ruff + pytest)` so a lint red is not
  triaged under a name that says pytest.
- Tree made clean: 72 errors and 20 files needing reformatting. Everything fixed
  except two config-level exemptions with reasons in the config (`S101`, `S105`
  under `scripts/tests/**` — the stub credentials that fire `S105` have no true
  positive anywhere in the tree) and two per-site `# noqa`s that carry their
  reason inline.

`pyright` stays ungated: its only findings are `reportMissingImports` for
`etv_client` in scripts/scripted-schedules/entrypoint.py, resolvable only in that
script's deploy environment, and gating it would put a node toolchain on the
git-only `small` lane to find nothing.

Population is what `ruff check .` discovers from the root, so a new `.py`
anywhere is covered without the job enumerating anything.

Docs: new record `ci.python-lint-ruff-config-committed`, cross-ref from
`ci.script-tests-job`, `docs/ci-cd.md` script-tests section, and
`docs/defect-shapes-773.md` §5.2 marked resolved with the measured numbers.

Refs: #780
Decisions-Edit: yes
Cold review (Opus, isolated worktree) cleared the mechanical reformat: 25 of 33
files AST-identical, the suite's collected node IDs identical to main, and the
three percent-format -> f-string conversions byte-equivalent at both call sites.
Everything below is config/CI/doc layer.

M4: `S105` is no longer exempted directory-wide. A blanket over `scripts/tests/**`
gives up hardcoded-credential coverage over the largest Python surface in the repo
— permanently, and this is the only Python lint we run — to suppress 8 known
lines. Those 8 now carry a per-site `# noqa: S105`; removing one is red
(witnessed). Only `S101` stays directory-wide.

M1: `ruff check .` on an empty population prints a stderr warning and exits 0, so
a stray `exclude` would switch the gate off silently — the vacuity failure
`testing.guard-derives-population-from-source` is about. The step now compares
`--show-files` against `git ls-files '*.py'` and fails on drift. Mutation proof:
a top-level `exclude = ["scripts"]` takes `ruff check` to green and the step to
`::error::… 0 Python files but git tracks 33`. Note the same exclude under
`[format]` does NOT reproduce it — it scopes to the formatter, and a mutation
written that way passes while proving nothing.

M3: lint moved ahead of the preflights. Behind `Preflight jq version` (a hard
`--expect` tripwire) the lint would go dark for as long as the jq contract is
broken, under a red that names jq.

H3: ruff.toml named a `Script lint (ruff)` job that does not exist — wrong on the
day it shipped.

H1: the "72 errors" claim is now reproducible against the committed config (it was
only true of the pre-M4 config), carries its reproduction command and base sha, and
splits honestly: 54 fixed in code, 18 per-site `# noqa`s.

H2: `docs/ci-cd.md` still said the suite is ~190 tests / ~10s next to a new
"four-minute" figure. Measured: 773 tests, ~4.5 min. The no-path-filter rationale
rested on the dead number; it now rests on the input set, which is the real reason.

M2: the nine E501 `# noqa`s claimed splitting "would change the payload". Implicit
string concatenation preserves the bytes exactly, so the stated reason was false
nine times. They say what is actually true: kept one-line for greppability.

Nits: the record no longer claims the config is identical to the operator's global
one (per-file-ignores differ), and the unpinned pytest/pyyaml asymmetry is stated
rather than left looking like an oversight.

Refs: #780
Decisions-Edit: yes
test(780): TEMPORARY deliberate lint violation to witness the gate red
PR Gates / CI image pin matches docker/ci (pull_request) Successful in 10s
PR Gates / Docs update reminder (pull_request) Successful in 12s
PR Gates / decisions lifecycle (pull_request) Successful in 18s
PR Gates / Script lint and tests (ruff + pytest) (pull_request) Failing after 9s
Build ErsatzTV Image / Delimiter ban (release path) (pull_request) Successful in 22s
PR Gates / Fix proofs (Proves trailers) (pull_request) Successful in 10s
review-verdict/h10 Awaiting review verdict for b2e9942
Review verdict / Set review-verdict status (pull_request_target) Successful in 10s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 8m32s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Canceled after 32s
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (pull_request) Canceled after 0s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Canceled after 0s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Canceled after 0s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Canceled after 0s
b2e9942106
The Done-when asks for a demonstrated red, not an assumed one. This commit
introduces an unused import and a double-space assignment so `Lint scripts (ruff
check)` and `Lint scripts (ruff format --check)` are seen failing on the runner —
merged ≠ ran. Reverted in the next commit.

Refs: #780
timothy added 1 commit 2026-08-21 23:22:38 +02:00
test(780): TEMPORARY format-only violation, to witness the second lint step red
Build ErsatzTV Image / Delimiter ban (release path) (pull_request) Successful in 22s
PR Gates / CI image pin matches docker/ci (pull_request) Successful in 18s
PR Gates / Docs update reminder (pull_request) Successful in 31s
PR Gates / Fix proofs (Proves trailers) (pull_request) Successful in 25s
PR Gates / decisions lifecycle (pull_request) Successful in 20s
PR Gates / Script lint and tests (ruff + pytest) (pull_request) Failing after 10s
review-verdict/h10 Awaiting review verdict for 6c470e7
Review verdict / Set review-verdict status (pull_request_target) Successful in 31s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Canceled after 1m28s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Canceled after 0s
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (pull_request) Canceled after 0s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Canceled after 0s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Canceled after 0s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Canceled after 0s
6c470e769a
The previous probe reddened `Lint scripts (ruff check)` on F401 and the job stopped
there, so `Lint scripts (ruff format --check)` had still never executed on the
runner — merged is not ran, and a step nobody has seen run proves nothing. This
probe is check-CLEAN and format-DIRTY, so the run reaches the second step. Both
probes are reverted in the next commit.

Refs: #780
timothy added 3 commits 2026-08-21 23:45:19 +02:00
Both are recorded red on the runner before removal:
- run 2158 job 9111 — ` Failure - Main Lint scripts (ruff check)` on F401
- run 2164 job 9137 — ` Failure - Main Lint scripts (ruff format --check)`
Both runs also printed `Population OK: 34 tracked Python files`, so the
anti-vacuity check executed on the runner and agreed with git there.

Refs: #780
Re-review of the previous fix commit found the population guard did not close the
vacuity it was added for. `ruff check . --show-files` reports DISCOVERY, and an
`exclude` defeats discovery in three config scopes — including `[format]`, which
is where an appended line lands by TOML rules. Measured with 0.12.11 against a
tracked file holding an unused import, a hardcoded credential and a formatting
error (GREEN = gate silently off):

  exclude in        check .   explicit   format --check .   explicit
  top level         GREEN     red        GREEN              red
  [lint]            GREEN     red        red                red
  [format]          red       red        GREEN              red
  + force-exclude   -         GREEN      -                  red with --no-force-exclude

So both steps now pass an explicit population from
`git ls-files -z '*.py' '*.pyi' '*.ipynb'` with `--no-force-exclude`, guarded by
an empty-list arm. All five mutants above are detected; an empty population
errors. This also fixes the count-comparison's three defects in one move: it
covers `.pyi` (which the old `git ls-files '*.py'` miscounted into a false red),
tracked-but-gitignored files (a permanent false red — `git add -f` under an
ignored path is established practice here), and compensating drift that a count
comparison nets to zero.

RUF100 is now selected. The previous commit added a `# noqa: UP031` to a site the
FIRST commit had already fixed in code — a suppression suppressing nothing, in a
change whose whole premise is that suppressions must stay honest — and two more
had been dead in the tree for months. All three removed. The split is 55 fixed in
code / 17 suppressed, not 54/18.

The `git` half of `Preflight external tools` moves back ahead of the lint steps,
which now consume `git`: without it a missing git kills the step at the population
assignment under `-e`, and the step's own `::error::` never prints. The orphaned
pytest/PyYAML rationale comment goes back onto its own step.

Docs: the record's mutation paragraph called the `[format]` exclude a
mutation-construction pitfall when it was a live coverage hole — it now carries the
measured matrix instead; `mechanics:` frontmatter rewritten; "all eight S105 hits"
scoped (there are nine in the tree, one pre-existing); the defect-shapes
reproduction block now actually runs (`mkdir -p`, `;` not `&&`, a sha not `main`,
not /tmp).

Refs: #780
Decisions-Edit: yes
test(780): TEMPORARY format-only probe against the REWRITTEN gate
PR Gates / CI image pin matches docker/ci (pull_request) Successful in 8s
Build ErsatzTV Image / Delimiter ban (release path) (pull_request) Successful in 20s
PR Gates / Docs update reminder (pull_request) Successful in 16s
PR Gates / Fix proofs (Proves trailers) (pull_request) Successful in 14s
PR Gates / Script lint and tests (ruff + pytest) (pull_request) Failing after 6s
PR Gates / decisions lifecycle (pull_request) Successful in 21s
review-verdict/h10 Awaiting review verdict for b584f53
Review verdict / Set review-verdict status (pull_request_target) Successful in 11s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Canceled after 0s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Canceled after 0s
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (pull_request) Canceled after 0s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Canceled after 0s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Canceled after 0s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Canceled after 0s
b584f53c33
The reds recorded earlier (runs 2158/2164) were against the previous step bodies,
which invoked `ruff check .`. The steps now enumerate from `git ls-files` with
`--no-force-exclude`, so those reds prove nothing about what is shipping: a guard
is proven by the code that runs, not by its predecessor. Re-witnessing both steps.

Refs: #780
timothy added 1 commit 2026-08-21 23:46:25 +02:00
test(780): TEMPORARY lint probe against the REWRITTEN gate's check step
PR Gates / CI image pin matches docker/ci (pull_request) Successful in 10s
PR Gates / Docs update reminder (pull_request) Successful in 8s
Build ErsatzTV Image / Delimiter ban (release path) (pull_request) Successful in 21s
PR Gates / decisions lifecycle (pull_request) Successful in 17s
PR Gates / Script lint and tests (ruff + pytest) (pull_request) Failing after 10s
review-verdict/h10 Awaiting review verdict for a8c0740
Review verdict / Set review-verdict status (pull_request_target) Successful in 19s
PR Gates / Fix proofs (Proves trailers) (pull_request) Successful in 10s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Canceled after 0s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Canceled after 0s
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (pull_request) Canceled after 0s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Canceled after 0s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Canceled after 0s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Canceled after 0s
a8c0740b5f
Run 2170 job 9163 recorded the format step red on the new body (and both steps
executing: `Linting 34 tracked Python files` / `Format-checking 34`). This probe
is check-dirty so `Lint scripts (ruff check)` is witnessed on the same body; the
job stops there, which is why the two probes cannot be one.

Refs: #780
timothy added 1 commit 2026-08-21 23:47:36 +02:00
test(780): revert the lint probes; record the reds against the shipped body
Build ErsatzTV Image / Delimiter ban (release path) (pull_request) Successful in 16s
PR Gates / Docs update reminder (pull_request) Successful in 9s
PR Gates / CI image pin matches docker/ci (pull_request) Successful in 11s
PR Gates / Fix proofs (Proves trailers) (pull_request) Successful in 13s
PR Gates / decisions lifecycle (pull_request) Successful in 17s
review-verdict/h10 Awaiting review verdict for 01f7a89
Review verdict / Set review-verdict status (pull_request_target) Successful in 9s
PR Gates / Script lint and tests (ruff + pytest) (pull_request) Successful in 4m37s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 8m50s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Canceled after 2m25s
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (pull_request) Canceled after 0s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Canceled after 0s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Canceled after 0s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Canceled after 0s
01f7a89e8f
Witnessed on the runner, on the step bodies being merged:
- run 2173 job 9176 — ` Failure - Main Lint scripts (ruff check)` on F401
- run 2170 job 9163 — ` Failure - Main Lint scripts (ruff format --check)`
Both printed `Linting 34 tracked Python files` / `Format-checking 34`, so the
git-derived population arm and `mapfile -d ''` both execute on the runner.

The record cited runs 2158/2164 — reds against the previous discovery-based
bodies. Those are superseded by the two above, not merely older.

Refs: #780
Decisions-Edit: yes
timothy added 1 commit 2026-08-22 00:14:09 +02:00
docs(780): delete the mechanism claims that were never executed
PR Gates / CI image pin matches docker/ci (pull_request) Successful in 11s
PR Gates / Docs update reminder (pull_request) Successful in 13s
PR Gates / decisions lifecycle (pull_request) Successful in 17s
Build ErsatzTV Image / Delimiter ban (release path) (pull_request) Successful in 21s
PR Gates / Fix proofs (Proves trailers) (pull_request) Successful in 12s
review-verdict/h10 Awaiting review verdict for 6e38ed8
Review verdict / Set review-verdict status (pull_request_target) Successful in 13s
PR Gates / Script lint and tests (ruff + pytest) (pull_request) Successful in 4m41s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 9m6s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 6m13s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Skipped
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (pull_request) Successful in 6m2s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 7s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 6s
6e38ed839e
Round-3 cold review confirmed the gate itself: ten falsification attempts —
`exclude` in three scopes, `force-exclude`, `extend-exclude`, `include = []`, a
nested `scripts/ruff.toml`, git absent, a non-repo, filenames with spaces,
quotes, newlines and non-ASCII under `core.quotePath` — every one detected, none
green. No BLOCKER, no HIGH on the mechanism. What it did find was three rounds of
the same doc-layer defect: a causal "because" written next to a correct decision
and never run.

- The preflight-ordering rationale claimed a missing git "kills the step at the
  population assignment, so its `::error::` never prints". Measured: process
  substitution does not propagate exit status, `mapfile` returns 0 with an empty
  array, and the `::error::` DOES print. The decision is unchanged; the reason it
  now gives is the measured one — the empty-population message blames the glob for
  a missing tool.
- `.pyi` was attributed to `ruff check .` skipping it. It does not; the default
  `include` covers `*.pyi`. The gap was the previous COUNT guard's
  `git ls-files '*.py'`. Claim removed; the tracked-but-gitignored half, which is
  true, stays.
- The exclude matrix did not name its pattern, and the one the record itself used
  to recommend (`["scripts"]`) reproduces none of it — `exclude` matches per file,
  so a bare directory name matches nothing under `[lint]`/`[format]`. Captioned.
- `ci.script-tests-job` still told the reader the job runs `ruff check .`, which
  the shipped rule explicitly forbids: two active records disagreeing about the
  command, visible only on a whole-branch read.
- The `Lint runs FIRST` comment still described the pre-reorder design, after
  ci-cd.md and the record had both been corrected.
- The 72/55/17 split was measured against the config as of 85ecd352f, before
  RUF100 was added. Under the config that ships it is 74/57/17 — the two extra
  being the dead suppressions RUF100 exists to catch. Restated, with the
  reproduction pinned to the shipping sha.
- Stated rather than left implicit: the population arm makes an emptied FILE set
  loud, and nothing makes an emptied RULE set loud (`select = []` stays green
  while printing a file count).

Refs: #780
Decisions-Edit: yes
timothy added 1 commit 2026-08-22 01:23:19 +02:00
docs(780): the residual-risk note was itself an unexecuted claim
PR Gates / CI image pin matches docker/ci (pull_request) Successful in 9s
PR Gates / Docs update reminder (pull_request) Successful in 10s
PR Gates / Fix proofs (Proves trailers) (pull_request) Successful in 9s
Build ErsatzTV Image / Delimiter ban (release path) (pull_request) Successful in 23s
PR Gates / decisions lifecycle (pull_request) Successful in 20s
review-verdict/h10 Awaiting review verdict for 27603b2
Review verdict / Set review-verdict status (pull_request_target) Successful in 15s
PR Gates / Script lint and tests (ruff + pytest) (pull_request) Successful in 4m29s
Build ErsatzTV Image / Build & test (.NET) (pull_request) Canceled after 5m37s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Canceled after 0s
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (pull_request) Canceled after 0s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Canceled after 0s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Canceled after 0s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Canceled after 0s
27603b215e
Round-4 verification re-ran everything the previous round wrote down. The gate
survived a seventh and eighth attack (a nested `scripts/ruff.toml`, a tracked file
under a gitignored directory), the §5.2 reproduction block produces exactly its
stated output, and the 74/57/17 split, the CI job citations and the exclude matrix
all reproduce cell for cell. Four claims did not.

- "`select = []` leaves BOTH steps green" — measured, it silences `ruff check`
  only; `ruff format --check` is not rule-selected and still reddens. Half the
  gate, not all of it. Written while adding a note about unexecuted claims, which
  is the joke telling itself.
- "dead in the tree for months" — the two pre-existing RUF100 sites predate this
  branch by 31 and 7 days. The number is not load-bearing; the fact that they
  predate it is. Also separated the two failure modes: one rule had stopped
  firing, the other is never enabled by this config, and only the first is what
  "stops matching" describes.
- "~20 opaque assertion errors" without git — measured 208 failed + 45 errors.
  Deleted rather than restated: the ordering decision does not need a count.
- `ruff.toml`'s header said an `exclude` in any of three scopes empties the run;
  only the top-level scope empties both commands. `docs/ci-cd.md` already had this
  right — the header, which is what an editor about to add an `exclude` reads, did
  not.

Also: the `force-exclude` matrix row reported the flag-off result for one command
and the flag-on result for the other, so the GREEN cell read as "the shipped
command is defeatable". Both copies of the matrix are re-cut with the flag-off and
flag-on rows separated. One stale `72` survived the 72→74 restatement. The `34` in
the witnessed-red quotes now says why it is not 33. `ci.script-tests-job`'s
catalog-visible `rule:` still described a pytest-only job.

Refs: #780
Decisions-Edit: yes
timothy added 1 commit 2026-08-22 01:48:37 +02:00
docs(780): one residual scope claim, and two wordings the measurement outgrew
Build ErsatzTV Image / Delimiter ban (release path) (pull_request) Successful in 15s
PR Gates / CI image pin matches docker/ci (pull_request) Successful in 12s
PR Gates / Docs update reminder (pull_request) Successful in 18s
PR Gates / Fix proofs (Proves trailers) (pull_request) Successful in 10s
PR Gates / decisions lifecycle (pull_request) Successful in 23s
Review verdict / Set review-verdict status (pull_request_target) Successful in 12s
PR Gates / Script lint and tests (ruff + pytest) (pull_request) Successful in 4m20s
review-verdict/h10 Review-verdict: MERGEABLE @ 7b28fc0 (base: main)
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 8m22s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 6m12s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Skipped
Build ErsatzTV Image / Functional E2E (curl + UI contracts) (pull_request) Successful in 5m54s
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (pull_request) Successful in 9s
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (pull_request) Successful in 7s
7b28fc0e66
Round-4 verification came back MERGEABLE with no unexecuted claim introduced.
Three leftovers from it:

- The record still said an `exclude` 'defeats it in three different config
  scopes' with `it` bound to `ruff check .` — measured, `[format]` does not
  defeat `check`. It defeats DISCOVERY in three scopes, two per command, which
  is what the table three lines below already showed.
- The force-exclude matrix row listed the non-shipped (flag-off) values first
  under a column headed 'what ships'. Swapped.
- 'silences the check step entirely / green over any violation' — a syntax error
  still reds under `select = []` (measured). It silences every selected RULE.

Refs: #780
Decisions-Edit: yes
Author
Owner

Review-verdict: MERGEABLE @ 7b28fc0

Four cold review rounds (Opus, isolated worktrees). Round 2 found a BLOCKER: the first population guard checked ruff's DISCOVERY, which an exclude defeats in three config scopes; replaced with an explicit git ls-files population plus --no-force-exclude, which survived ten falsification attempts across two independent rounds. Rounds 3 and 4 were doc-accuracy only. Both lint steps witnessed red on the runner against the shipped step bodies: run 2173 job 9176 (ruff check) and run 2170 job 9163 (ruff format --check). The final head adds one residual scope-claim fix over the round-4-reviewed tree; each claim in it was executed before writing.

Review-verdict: MERGEABLE @ 7b28fc0 Four cold review rounds (Opus, isolated worktrees). Round 2 found a BLOCKER: the first population guard checked ruff's DISCOVERY, which an exclude defeats in three config scopes; replaced with an explicit git ls-files population plus --no-force-exclude, which survived ten falsification attempts across two independent rounds. Rounds 3 and 4 were doc-accuracy only. Both lint steps witnessed red on the runner against the shipped step bodies: run 2173 job 9176 (ruff check) and run 2170 job 9163 (ruff format --check). The final head adds one residual scope-claim fix over the round-4-reviewed tree; each claim in it was executed before writing.
timothy merged commit d4c72697f2 into main 2026-08-22 02:33:20 +02:00
timothy deleted branch fix/780-ruff-config 2026-08-22 02:33:22 +02:00
Sign in to join this conversation.