Skip to content

ci: file-budget line-count ratchet (scripts/file-budget.sh) wired into make ci + build.yml - #316

Merged
saadqbal merged 4 commits into
refactor/284-exitcodes-namingfrom
ci/285-file-budget-ratchet
Jul 14, 2026
Merged

ci: file-budget line-count ratchet (scripts/file-budget.sh) wired into make ci + build.yml#316
saadqbal merged 4 commits into
refactor/284-exitcodes-namingfrom
ci/285-file-budget-ratchet

Conversation

@LukasWodka

@LukasWodkaLukasWodka commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

scripts/file-budget.sh — a per-file line-count ratchet cloning the scripts/coverage-floor.sh pattern (read first, same shape): path:max_lines pairs, wc -l check, bash-3.2-portable, the same malformed-entry guard, plus a missing-file guard so a moved/renamed budgeted file makes the stale list loud instead of silently un-budgeting it.

Ceilings only ratchet down. Raising one requires editing the checked-in script — a reviewed diff, never a side effect of a big PR. Seeds sit just above today's reality (verified on the WS-B branch):

FileBudgetToday
internal/push/preflight.go16501635
internal/cli/data.go500240 (post cli#282/#283)
internal/cli/client.go10501027
internal/cli/home.go850841

Wiring:

  • make ci — new file-budget target in the chain (the Makefile's "make ci green ⇒ CI green" invariant requires both sides, hence also:)
  • build.yml — one surgical step appended to the existing lint job (my brief assigns this shared-file edit; per the standing convention new jobs would get a dedicated workflow file, but this is a single step in an existing job). Expected trivial rebase vs sibling PRs touching build.yml/Makefile — merge order flexible.

Shell ratchet over a golangci funlen-style rule per the #6 standalone-tools decision.

Fixes#285
Part of tracebloc/backend#1106.

Type of change

  • Bug fix
  • New feature
  • Refactor
  • Docs
  • CI/build

Test plan

Ran locally:

  • make file-budget — all four seeds pass
  • Exercised all three failure paths (over budget / missing file / malformed entry) — each exits 1 with a ::error:: annotation
  • shellcheck --severity=warning scripts/file-budget.sh — clean
  • go build ./... + unit tests for touched-adjacent packages (internal/cli, internal/push) — green
  • build.yml parses as valid YAML

Checklist

  • Tests pass locally
  • Failure paths exercised
  • Surgical edits only to shared files (Makefile ci target + one build.yml lint step)

Stacked PR 4/4 of the WS-B data.go chain — merge order: cli#303 (#282) → cli#309 (#283) → cli#315 (#284) → this. Branch is based on refactor/284-exitcodes-naming; until the predecessors merge, this diff shows their commits too. Review only the top commit (8fc62f8). Note: the data.go:500 seed assumes the split lands first — merging this out of order would still pass (500 > today's 240 either way), but the budget's rationale reads post-split.

🤖 Generated with Claude Code


Note

Low Risk
CI/Makefile-only change with no runtime behavior; risk is limited to false positives if line counts or paths drift without updating the budget list.

Overview
Adds scripts/file-budget.sh, a shell gate (same shape as coverage-floor.sh) that fails CI when tracked files exceed checked-in path:max_lines ceilings. Ceilings are meant to ratchet down only; raising a limit requires an explicit edit to the script.

Wiring: new file-budget Makefile target and inclusion in make ci, plus a File budget step in build.yml’s lint job so local make ci and CI stay aligned.

Initial budgets:internal/push/preflight.go, internal/cli/data.go, internal/cli/client.go, and internal/cli/home.go. The script also errors on malformed budget entries or missing budgeted paths so renames don’t silently drop coverage.

Reviewed by Cursor Bugbot for commit def16ab. Bugbot is set up for automated code reviews on this repo. Configure here.

@LukasWodka
LukasWodka requested a review from saadqbalJuly 14, 2026 12:38
@LukasWodka

Copy link
Copy Markdown
ContributorAuthor

👋 Heads-up — Code review queue is at 55 / 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):

  • averaging-service#181 — feat(weights): normalize-on-read — mixed cycles average instead of rejecting (SEC-03 §8 step 2) · author: @shujaatTracebloc · no reviewer assigned
  • averaging-service#182 — feat(weights): averaging writes SafeTensors (TF + PyTorch) — SEC-03 §8 step 4 · author: @shujaatTracebloc · no reviewer assigned
  • backend#1079 — feat(global_meta): edge dataset_meta exposure + attributes contract at ingest (#924 G4a) · author: @divyasinghds · no reviewer assigned
  • backend#1086 — docs(rfc): SafeTensors weight-format migration — SEC-03 Phase 1 (RFC 0004) · author: @shujaatTracebloc · no reviewer assigned
  • backend#1093 — chore(deps): bump django from 5.2.14 to 5.2.15 · author: @dependabot · no reviewer assigned
  • backend#1095 — feat(experiment): configurable preprocessing knobs incl. tabular scaler — RFC 0003 L1 + L1b (#1094) · author: @LukasWodka · no reviewer assigned
  • backend#1100 — fix(boot): pin SDK install to tracebloc==0.11.2, drop 404 dev line (#1098) · author: @LukasWodka · reviewer: @saqlainsyed007
  • backend#1105 — perf(api): query micro-fixes — notifications N+1, cached data_scientist, composite index, sampling (#975) · author: @aptracebloc · no reviewer assigned
  • backend#1107 — perf(experiments): prefetch ExperimentListSerializer relations + cache carbon intensity (#977) · author: @aptracebloc · no reviewer assigned
  • backend#1108 — test(api): CLI response-shape contract fixtures for the 9 CLI endpoints (WS-D.2) · author: @LukasWodka · reviewer: @saadqbal

Pull from review before opening new work. (This is a nudge from the kanban WIP check, not a block.)

@LukasWodka
LukasWodka changed the base branch from develop to refactor/284-exitcodes-namingJuly 14, 2026 12:49
@LukasWodkaLukasWodka self-assigned this Jul 14, 2026
@LukasWodka

Copy link
Copy Markdown
ContributorAuthor

@BugBot run

@cursorcursorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ 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 8fc62f8. Configure here.

@saadqbalsaadqbal left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Same solid ratchet pattern as coverage-floor.sh — fail-loud on malformed/missing entries, clear 'split it or raise the ceiling' remediation, and CI green so every budgeted file is within budget. (home.go at 850 is a tight ceiling given it's ~841 now — deliberate nudge toward splitting, noted.) (Stacked on #315.)

@saadqbal

Copy link
Copy Markdown
Collaborator

Status: approved, stacked on #315 (refactor/284…). Lands after #309#315 are recovered. No content issue.

LukasWodkaand others added 3 commits July 14, 2026 19:40
…unDataIngest
runDataIngest was 586 lines; every pre-cluster step and the cluster
pre-flight now live in two named stanza functions, moved verbatim:
- resolveLocalInput (data_ingest_local.go) — steps 0–4 + the P3 content
preflight: flag guard, banner, guided prompts, ~-expansion +
existence-first check, table-name/category/misapplied-flag validation,
layout walk, per-category spec resolution, spec synthesis + schema
validation, local summary. Mutates a in place (via *runDataIngestArgs)
so the --output-json defer and the cluster steps see the resolved spec
exactly as before.
- connectIngestTarget (data_ingest_cluster.go) — steps 5–8a: kubeconfig
resolve, release + PVC discovery, verbose cluster summary, and the
destination-table guard (incl. the folded interactive replace decision,
which still flips a.Overwrite).
The jsonEmitted/named-return defer dance stays INSIDE runDataIngest,
next to the err it reads — both extracted functions feed that named
return, so the error-JSON contract is unchanged. The dry-run stop (which
sets jsonEmitted) also stays inside.
Only in-stanza edits are what the new signatures force: multi-value
returns on error paths, := to = where a named result already exists, and
&a -> a where a is already a pointer. Step order, output order, and exit
codes are untouched.
data.go: 693 -> 240 lines; runDataIngest: 586 -> 138.
Safety net: the #187 outcome-matrix table test + #264 mutation pins pass
untouched; full suite green under -race; coverage floors hold (82.7%).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
internal/cli/exitcodes.go names every exit code the CLI produces; every
non-test &exitError construction site now uses a named constant instead
of a bare number. exit.go keeps owning the extraction — this is a naming
sweep, not a redesign; all numeric values are unchanged (and documented
as frozen: they're the scripting contract customers branch on).
Site census (the ticket's count of 138 grep hits includes one doc
comment in exit.go; 137 are real construction sites):
61x1, 25x2, 23x3, 7x4, 4x5, 1x6, 5x7, 2x8, 4x9, 2x130,
2x kubeconfigExitCode(...) (the helper now returns named constants),
1x variable (runLocalPreflight's BadFlag fold, now built from
constants). Zero numeric literals remain at non-test sites.
Codes that grew more than one per-command meaning get one constant per
MEANING sharing the value (2: exitBadInput / doctor's exitChecksFailed;
5: exitAuth / data delete's exitNoSuchDataset; 7: exitStagingFailed /
exitTeardownFailed / exitQueryFailed), so each site reads honestly.
docs/troubleshooting.md gains the cross-command exit-code table (code,
meaning, producing commands, constant name), sourced from the per-command
long-help blocks — data ingest's (data_ingest_cmd.go, pre-split
data.go:236-252) is the fullest.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Clones the coverage-floor.sh pattern for file size: path:max_lines pairs,
checked by wc -l, portable to bash 3.2, with the same malformed-entry
guard — plus a missing-file guard so a moved/renamed budgeted file makes
the stale list loud instead of silently un-budgeting it.
Ceilings are a RATCHET: only ever lowered as files shrink; raising one is
a deliberate, reviewed edit to the checked-in script. Seeds sit just
above today's reality (develop + the WS-B split):
internal/push/preflight.go:1650 (now 1635)
internal/cli/data.go:500 (now 240 post cli#282/#283)
internal/cli/client.go:1050 (now 1027)
internal/cli/home.go:850 (now 841)
Wired into `make ci` (new file-budget target, keeping the Makefile's
"make ci green => CI green" invariant) and into build.yml's lint job as
one surgical step. Exercised all three failure paths locally (over
budget, missing file, malformed entry) — each exits 1 with a ::error::
annotation; shellcheck clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@saadqbal
saadqbalforce-pushed the refactor/284-exitcodes-naming branch from a6de340 to 8d93e43CompareJuly 14, 2026 14:43
@saadqbal
saadqbalforce-pushed the ci/285-file-budget-ratchet branch from 8fc62f8 to 7868fe4CompareJuly 14, 2026 14:43

@cursorcursorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 7868fe4. Configure here.

Comment threadscripts/file-budget.sh Outdated
The ratchet seeded internal/push/preflight.go at 1650, but the file is
1655 lines (wc -l, same count the gate uses) and the check is strict-
greater — so `make file-budget` would fail the moment this landed on
develop. Raise the ceiling to 1700, the next round-50 ratchet value just
above actual, matching how the other seeds sit above their files
(client.go 1050>1027, home.go 850>849, data.go 500>240). Also correct
the header comment to reality (preflight ~1655, home ~849); it wrongly
read ~1635 / ~841.
Proof: `bash scripts/file-budget.sh` now passes (preflight 1655 <= 1700).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@saadqbal
saadqbalforce-pushed the refactor/284-exitcodes-naming branch from 8d93e43 to f12fa87CompareJuly 14, 2026 15:55
@saadqbal
saadqbal merged commit ab1a923 into refactor/284-exitcodes-namingJul 14, 2026
5 checks passed
@saadqbal
saadqbal deleted the ci/285-file-budget-ratchet branch July 14, 2026 15:59
saadqbal pushed a commit that referenced this pull request Jul 14, 2026
…mand docs table (#315)
* refactor(cli): name every exit-code site + cross-command docs table
internal/cli/exitcodes.go names every exit code the CLI produces; every
non-test &exitError construction site now uses a named constant instead
of a bare number. exit.go keeps owning the extraction — this is a naming
sweep, not a redesign; all numeric values are unchanged (and documented
as frozen: they're the scripting contract customers branch on).
Site census (the ticket's count of 138 grep hits includes one doc
comment in exit.go; 137 are real construction sites):
61x1, 25x2, 23x3, 7x4, 4x5, 1x6, 5x7, 2x8, 4x9, 2x130,
2x kubeconfigExitCode(...) (the helper now returns named constants),
1x variable (runLocalPreflight's BadFlag fold, now built from
constants). Zero numeric literals remain at non-test sites.
Codes that grew more than one per-command meaning get one constant per
MEANING sharing the value (2: exitBadInput / doctor's exitChecksFailed;
5: exitAuth / data delete's exitNoSuchDataset; 7: exitStagingFailed /
exitTeardownFailed / exitQueryFailed), so each site reads honestly.
docs/troubleshooting.md gains the cross-command exit-code table (code,
meaning, producing commands, constant name), sourced from the per-command
long-help blocks — data ingest's (data_ingest_cmd.go, pre-split
data.go:236-252) is the fullest.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci: file-budget line-count ratchet (scripts/file-budget.sh) wired into make ci + build.yml (#316)
* refactor(cli): extract resolveLocalInput + connectIngestTarget from runDataIngest
runDataIngest was 586 lines; every pre-cluster step and the cluster
pre-flight now live in two named stanza functions, moved verbatim:
- resolveLocalInput (data_ingest_local.go) — steps 0–4 + the P3 content
preflight: flag guard, banner, guided prompts, ~-expansion +
existence-first check, table-name/category/misapplied-flag validation,
layout walk, per-category spec resolution, spec synthesis + schema
validation, local summary. Mutates a in place (via *runDataIngestArgs)
so the --output-json defer and the cluster steps see the resolved spec
exactly as before.
- connectIngestTarget (data_ingest_cluster.go) — steps 5–8a: kubeconfig
resolve, release + PVC discovery, verbose cluster summary, and the
destination-table guard (incl. the folded interactive replace decision,
which still flips a.Overwrite).
The jsonEmitted/named-return defer dance stays INSIDE runDataIngest,
next to the err it reads — both extracted functions feed that named
return, so the error-JSON contract is unchanged. The dry-run stop (which
sets jsonEmitted) also stays inside.
Only in-stanza edits are what the new signatures force: multi-value
returns on error paths, := to = where a named result already exists, and
&a -> a where a is already a pointer. Step order, output order, and exit
codes are untouched.
data.go: 693 -> 240 lines; runDataIngest: 586 -> 138.
Safety net: the #187 outcome-matrix table test + #264 mutation pins pass
untouched; full suite green under -race; coverage floors hold (82.7%).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(cli): name every exit-code site + cross-command docs table
internal/cli/exitcodes.go names every exit code the CLI produces; every
non-test &exitError construction site now uses a named constant instead
of a bare number. exit.go keeps owning the extraction — this is a naming
sweep, not a redesign; all numeric values are unchanged (and documented
as frozen: they're the scripting contract customers branch on).
Site census (the ticket's count of 138 grep hits includes one doc
comment in exit.go; 137 are real construction sites):
61x1, 25x2, 23x3, 7x4, 4x5, 1x6, 5x7, 2x8, 4x9, 2x130,
2x kubeconfigExitCode(...) (the helper now returns named constants),
1x variable (runLocalPreflight's BadFlag fold, now built from
constants). Zero numeric literals remain at non-test sites.
Codes that grew more than one per-command meaning get one constant per
MEANING sharing the value (2: exitBadInput / doctor's exitChecksFailed;
5: exitAuth / data delete's exitNoSuchDataset; 7: exitStagingFailed /
exitTeardownFailed / exitQueryFailed), so each site reads honestly.
docs/troubleshooting.md gains the cross-command exit-code table (code,
meaning, producing commands, constant name), sourced from the per-command
long-help blocks — data ingest's (data_ingest_cmd.go, pre-split
data.go:236-252) is the fullest.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci: file-budget line-count ratchet (scripts/file-budget.sh)
Clones the coverage-floor.sh pattern for file size: path:max_lines pairs,
checked by wc -l, portable to bash 3.2, with the same malformed-entry
guard — plus a missing-file guard so a moved/renamed budgeted file makes
the stale list loud instead of silently un-budgeting it.
Ceilings are a RATCHET: only ever lowered as files shrink; raising one is
a deliberate, reviewed edit to the checked-in script. Seeds sit just
above today's reality (develop + the WS-B split):
internal/push/preflight.go:1650 (now 1635)
internal/cli/data.go:500 (now 240 post cli#282/#283)
internal/cli/client.go:1050 (now 1027)
internal/cli/home.go:850 (now 841)
Wired into `make ci` (new file-budget target, keeping the Makefile's
"make ci green => CI green" invariant) and into build.yml's lint job as
one surgical step. Exercised all three failure paths locally (over
budget, missing file, malformed entry) — each exits 1 with a ::error::
annotation; shellcheck clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci(file-budget): seed preflight.go at true size (Bugbot #316 HIGH)
The ratchet seeded internal/push/preflight.go at 1650, but the file is
1655 lines (wc -l, same count the gate uses) and the check is strict-
greater — so `make file-budget` would fail the moment this landed on
develop. Raise the ceiling to 1700, the next round-50 ratchet value just
above actual, matching how the other seeds sit above their files
(client.go 1050>1027, home.go 850>849, data.go 500>240). Also correct
the header comment to reality (preflight ~1655, home ~849); it wrongly
read ~1635 / ~841.
Proof: `bash scripts/file-budget.sh` now passes (preflight 1655 <= 1700).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@LukasWodka@saadqbal