Skip to content

A deny-by-default gate lands on all 38 sol consumers in one commit, so 30 go red on a diff that did not cause it #388

Description

@thedavidmeister

Unit

.github/workflows/rainix-sol-static.yaml — the gate steps, and the convention by which a new one is added.

Violated property

A red build means the diff is wrong.

Evidence

55c8198 added forge lint -D warnings and pre-commit run --all-files as unconditional denying steps in one commit, having measured the blast radius first:

Measured against all 38 consumers at their current HEADs, this reddens 30 of them — 20 on forge lint -D warnings over 236 findings, 20 on pre-commit run --all-files, 10 on both.

Observed downstream in rain.lib.memkv, which was one of the 30. main at 645ddb9 passed rainix-sol / static at 2026-09-15T13:48Z. The gates landed at 20:59Z. Six mutation-test PRs opened against that same commit the next day each failed static on first push, on two boolean-cst findings in test/lib/LibMemoryKVSlow.sol — lines none of the six diffs touch, present on main — and then on a denofmt rewrap of an untouched README.md line. Three of the six absorbed the fixes because they happened to be editing those files; three were left red through no fault of their own. Filed there as rainlanguage/rain.lib.memkv#44.

This is independent of pinning

rainix#368 is the other half and does not subsume this one. Pinning decides when the org pays, not whether. With every ref pinned, the bump commit becomes the commit that reddens 30 repos at once, and whichever contributor opens it wears the same diagnosis — someone else's lint rule, on lines their diff never touched, before their own work can be reviewed.

Why it might be intended

Landing everywhere at once is the point of a shared workflow, and that is a deliberate trade the org has made before. Both findings were genuine formatter/lint output, not false CI. Making a gate opt-in would thread an input through 38 caller files, which 55c8198 correctly notes is the same per-repo touch as just fixing the findings — so opt-in is not the answer either.

Why it is a bug

It makes a red build indistinguishable from a broken change for every contributor who cut a branch that morning, and because the findings sit on main, the cost is paid once per open PR rather than once per repo. Six concurrent PRs in one repo paid it simultaneously. It also inverts what the gate is for: a contributor whose diff is clean gets the same signal as one whose diff is wrong, so the signal stops carrying information exactly when the most branches are open.

Suggested fix

Either ordering, both of which put the fixes before the denial:

  1. Report-only first, with a dated flip. The step lands as forge lint without -D warnings, and pre-commit run --all-files --show-diff-on-failure || true, with the flip date recorded in the workflow beside the step. The sweep PRs land against the affected consumers during the window. The step goes denying on the date.
  2. Sweep, then gate. The consumer fix PRs land first, enumerated the way 55c8198 enumerated them, and the gate goes straight to denying with a measured blast radius of zero.

The measurement 55c8198 already performs is what makes either one orderable: it names the affected repos, so the sweep is enumerable before the gate moves. The gap is that the measurement is currently used to describe the damage rather than to schedule around it.

Surfaced while ruling on rainlanguage/rain.lib.memkv#44.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    auditAudit finding

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions