Module size discipline
Skill fusebase-dev/fusebase-flow/.agents/skills/module-size-discipline
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).From its SKILL.md
npx -y skills add fusebase-dev/fusebase-flow --skill module-size-disciplineAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 8 stars8 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
7.7 KB, as published. Nobody here has run it
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.tssplit. - 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-reviewchecks 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_globsentries 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.