Skip to content

Add a file-budget ratchet like pithead's: tests/run.sh is 8,674 lines with no ceiling #407

Description

@VijitSingh97

Why

pithead runs a file-budget ratchet (scripts/lint-file-budget.sh + docs/dev/file-budget.tsv, its
#1105 Phase 0) that stops its biggest files growing without demanding anyone rewrite them today.
rigforge has no equivalent, and it is already carrying files in the range where pithead started
hurting.

Measured on develop:

lines file
8,674 tests/run.sh
6,013 rigforge.sh
1,386 tests/e2e-real.sh
563 tests/e2e-pithead.sh

3 files over 800 lines, 4 over 400. No gate, no budget file.

This is not a tidiness request. pithead learned the cost twice, and both are ahead of rigforge on the
same curve:

  • make lint-sh gets OOM-killed as one file grows. shellcheck was using over 7 GB on pithead's
    tests/stack/run.sh and took whole sessions down with it; later the same pathology reached CI and
    blocked every PR until the shellcheck invocation was split. tests/run.sh at 8,674 lines is in
    that territory now.
  • Retrofitting is far more expensive than ratcheting. pithead is ~20 PRs into splitting one test
    monolith by domain, and the coupling that surfaced (shared sandbox state, order-dependent
    assertions) cost several red suites to find. A ceiling recorded today costs nothing; a split
    demanded in six months costs a quarter.

What to build

Port the mechanism, not necessarily the numbers:

  1. New tracked file: hard fail over 800 lines (target 400).
  2. Existing offender: record its CURRENT line count in a budget file as a personal ceiling. A PR
    may not grow the file past its ceiling. Ceilings only ever go DOWN — reject any budget edit
    that raises one, checked against the base branch. A file that shrinks to <=400 drops its entry.
  3. Enumerated exemptions, each with its reason — generated code, vendored files, data/config,
    prose docs. rigforge.sh is the shipped artifact and is the obvious candidate for the same
    treatment pithead gives its own pithead script; decide deliberately rather than by accident.
  4. Wire it into make lint and CI, and give it a --self-test with fixtures for each failure
    mode, plus a --generate that reprints the budget for seeding.

Traps pithead already paid for — inherit these, don't rediscover them

  • The ratchet leaves ZERO slack the instant a shrinking cut merges (ceiling == actual), so a
    follow-on PR that adds even 20 lines is refused and the ceiling cannot be raised to make room.
    Before routing around this, ask whether a line-neutral form of the change exists — that
    question dissolved the problem on pithead when three sessions had already tried to carry an
    addition past the gate. Only if there genuinely is none, fold the addition into the shrinking cut's
    own commit (never a follow-on PR), and weigh that a move PR's contract is "no behaviour change".
  • Do not add a fallback that permits a recorded ceiling above the actual count. It leaves slack
    any later change can consume, in a guard whose whole purpose is that slack does not accumulate.
  • Regenerate the budget file per-lane; never merge it by taking a side. On pithead it is
    regenerated, and a stale entry two lines out was caught only because the gate compared against the
    real count.
  • Enumerate exemptions by path with reasons, and detect binaries generically (grep -I) rather
    than listing them, or the exemption list becomes its own maintenance problem.

Acceptance

make lint fails on a new 801-line file and on growing an existing offender past its recorded
ceiling; passes when a file shrinks; refuses a budget edit that raises a ceiling; --self-test covers
each of those plus the empty-enumeration guard; CI runs it on every PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions