Use when planning tasks that touch big source files, when an edit would push a file past the module-size ceiling, when the pre-commit module-size ratchet warns or blocks, or when generating policies/module-size-baseline.txt. Operationalizes FR-25 — module-size ratchet (ceiling default 800; over-ceiling files may shrink, never grow; extraction along a responsibility seam is in-scope, not scope creep). Do NOT use for docs/markdown size (FR-23 owns docs), to force decomposition of an existing mo...
Scanned 9/13/2026
Install to Claude Code
npx -y skills add fusebase-dev/fusebase-flow --skill module-size-discipline --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Module Size Discipline?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/fusebase-dev-module-size-discipline-1c953a81)More formats (shields.io, HTML) on the badges page.
---
name: module-size-discipline
description: Use when planning tasks that touch big source files, when an edit would push a file past the module-size ceiling, when the pre-commit module-size ratchet warns or blocks, or when generating policies/module-size-baseline.txt. Operationalizes FR-25 — module-size ratchet (ceiling default 800; over-ceiling files may shrink, never grow; extraction along a responsibility seam is in-scope, not scope creep). Do NOT use for docs/markdown size (FR-23 owns docs), to force decomposition of an existing monolith (that is its own explicit ticket), or to judge split quality by regex (seam-vs-mechanical is semantic — code-review owns it).
source_inspiration: conceptual-only
license_status: clean-room-original
fusebase_flow_version: "3.16"
risk_level: medium
invocation: automatic
expected_outputs:
- per-task target-file declarations (tasks.md) with extraction-or-exemption for over-ceiling targets
- extraction into a new module along a responsibility seam, or an explicit exemption
- policies/module-size-baseline.txt via agent-run --write-baseline (on the operator's chat go-ahead)
related_workflows:
- greenlight-implement.md
- verification-gate.md
- lightweight-lane.md
hook_dependencies:
- hooks/git/pre-commit (module-size step)
---
# Module-Size Discipline (FR-25)
## Purpose
Stop source files from accreting into monoliths nobody (human or agent) can load in one pass. Source in a Flow workflow is AI-read (FR-22/FR-24 audience principle): a 19k-line file forces slice-reads on every future session. Monoliths are the integral of N individually-reasonable diffs — no single diff is ever flagged — so the framework gates the accumulating dimension deterministically (line count is objective, unlike FR-22/FR-23 semantics) and steers extraction at plan- and write-time.
## The ratchet (deterministic gate)
Config: `policies/module-size.yml` (`ceiling` default 800 · `source_globs` · `exempt_globs` · `baseline_file` · `enforcement` · gitignored `module-size.local.yml` override). Engine: `hooks/shared/module_size.py`, wrapper `hooks/local/check-module-size.sh`, wired into `hooks/git/pre-commit`.
| Case | Verdict |
|---|---|
| Gated file NOT in baseline, lines ≤ ceiling | pass |
| NOT in baseline, **NEW** over ceiling (crosses the ceiling in this change) | **BLOCK** — extract, or adopt (`--write-baseline`) |
| NOT in baseline, **PRE-EXISTING** over ceiling (over ceiling at HEAD), touched/shrunk in a change gate (`--staged`/`--worktree`, not growing) | pass — the refactor path (delta-aware adoption grace) |
| NOT in baseline, **PRE-EXISTING** over ceiling, **GROWN** | **BLOCK** — a monolith may be touched/shrunk, never grown |
| Any over-ceiling not-baselined file under `--all` (audit) | **reported** (absolute; no HEAD delta) — tells you what to adopt |
| Baselined file, lines ≤ its baseline value | pass (shrinking/holding is always fine) |
| Baselined file, lines > its baseline value | **BLOCK** — over-ceiling files may not grow |
| File matches `exempt_globs` | never gated |
| No `baseline_file` committed | **warn-only** + generation instruction (adoption-safe) |
Modes: `--staged` (pre-commit default) · `--worktree` (vs HEAD; optional Stop-hook wiring) · `--all` (full scan; also a CI step in `fusebase-flow-verify.yml`) · `--write-baseline` (**agent-run on the operator's chat go-ahead** — freezes current over-ceiling files; the agent commits the result; presence switches warn → block) · `--write-baseline <path>` (re-keys ONE row — the targeted refresh; a full regen grandfathers every current violation, so prefer the single-file form).
Baseline shipping: the template **ships its own committed baseline** (Flow's own over-ceiling files), so the gate is live from commit #1 on greenfield instantiations. Installing into an **existing** repo with pre-existing monoliths: those files are **not** hard-blocked on first touch — the delta-aware change gate lets you touch/shrink a pre-existing over-ceiling file (only NEW-over-ceiling files and growth block). To freeze them at their current size (so future growth is caught against a recorded value, and to clear the `--all` audit), the agent runs `--write-baseline` once **on the operator's chat go-ahead** — it **auto-mints a single-use FR-07 approval** for the protected baseline path, and the agent then commits and consumes it (the sanctioned path; never `--no-verify`). The operator approves adoption in chat; they run no terminal command.
Local override (`policies/module-size.local.yml`, gitignored) is **additive-only**: it may append `exempt_globs` / `source_globs` entries; `enforcement`, `ceiling`, and `baseline_file` cannot be overridden locally (a gitignored kill switch would disarm the gate invisibly). The engine prints a notice whenever a local override is active.
Rename tripwire: the baseline keys by path — after renaming a baselined over-ceiling file, its first content edit blocks (fail-closed, zero-growth included) until it is re-keyed — the agent runs `--write-baseline <new-path>` on the operator's go-ahead (and the old row disappears on the next targeted or full refresh; stale rows for absent files are inert).
## Plan-time rule (where the problem starts)
In `implementation-planning` / `tasks.md`: **every task names its target file(s)**. A task targeting an over-ceiling file must either (a) extract the addition into a new module, or (b) carry a one-line exemption with reason. "Where does this code live" is a cheap question at Plan and a never-asked question mid-implement.
## Write-time rule (AI Developer)
- An edit that would push a gated file over the ceiling, or grow an already-over-ceiling file → extract along a **responsibility seam** (a nameable concern), not a mechanical `utils2.ts` split.
- That extraction is **in-scope for the task**: it is NOT scope creep and NOT by itself an FR-21 promotion trigger. (FR-21 interplay — see `lightweight-lane`.)
- Never bypass with `--no-verify` (FR-06). Remedies: extract, or surface the exemption question to the operator (FR-19).
## Exemptions (deliberate, reviewable)
Justified monolith classes go in `exempt_globs`: generated code (SDK/OpenAPI output), lockfiles, vendored complete-file mirrors, data-as-code catalogs/fixtures, migrations. Exemption is a policy edit the operator sees — never silent.
## What this skill does NOT do
- No forced refactor: existing monoliths freeze at baseline; decomposition is its own (usually Full-lane) ticket with its own risk assessment.
- No split-quality regex: seam-vs-mechanical is semantic — `code-review` checks it by reading.
- No docs gating: artifact/doc size is FR-23's axis.
## Anti-patterns
- Splitting mechanically to satisfy the gate — observable criterion: an extraction landing in a file whose name does not state a responsibility (`utils2`, `helpers2`, `misc`, `extra`, `more`-style names) is a review blocker; a named seam is judged by reading.
- Raising the baseline to make a violation pass — adoption needs the operator's explicit go-ahead (given in chat), never the agent's own initiative to dodge a block; on that go-ahead the agent runs `--write-baseline` (prefer the single-file form so refreshes are never global amnesties). The guard is the operator's *decision*, not making the operator *type the command*.
- Treating the ratchet warning as noise in warn-only mode — surface it to the operator with the activation instruction instead.
- Adding `exempt_globs` entries for ordinary source because extraction is inconvenient.
## Clean-room note
Original Fusebase Flow content. Ratchet-style size gating is common public CI practice (grandfathering + no-growth baselines); no third-party code, prompts, skill files, or hook scripts are copied. See `docs/source-map.md`.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!