Skip to content

Exclude import lines from REQ-CNST-010's line-count guard — current raw count causes a decompose→more-imports→re-violate spiral #4965

Description

@Trecek

Problem

Two independent architectural guards interact to produce a feedback loop:

  1. File line-count guard (REQ-CNST-010)scripts/check_file_lengths.py:36-46 (HARD_CAP = 750, ABSOLUTE_CAP = 1000), enforced via pre-commit (.pre-commit-config.yaml:105-110) and CI (tests/arch/test_file_length_diff_gate.py:42-58), plus a legacy full-tree restatement (tests/arch/test_subpackage_isolation_size.py:27-41 via tests/arch/_helpers.py:35-57 _collect_line_limit_violations, default 1000). Every instance counts lines identically: len(path.read_text(encoding="utf-8").splitlines()) — raw physical line count with no exclusion for blank lines, comments, docstrings, or import statements. Python-only, scoped to src/autoskillit/**/*.py; test files are exempt by design.
  2. Folder file-count guardtests/arch/test_subpackage_isolation_file_counts.py (FILE_COUNT_LIMITS dict, default 10 Python files per directory, per-package overrides up to 76), rationale stated inline as "a root package a single reviewer can still hold in mind" — this is the mechanism that keeps ls on a package directory from showing too many entries.

When a file grows past 750 lines, the standard response is to decompose it into more, smaller files/modules (there is no automated tooling for this — every precedent found, e.g. commit e62823be4 "server and fleet folder decomposition" #4673, was a fully manual, human/agent-planned multi-hundred-file PR; test_*_decomposition.py files only verify a decomposition already happened, they don't perform one). Splitting increases the folder's file count toward guard #2, which pushes further splitting into new subpackages/facades — and each new facade or cross-module boundary adds import lines to make the split files talk to each other again. Those import lines count fully toward guard #1's 750/1000 cap, since nothing is excluded. In the worst case this becomes circular: splitting a file to get under the line cap can, once enough of it is import boilerplate, make further reduction of logic content impossible without splitting yet again.

Concrete evidence of the spiral (from commit e62823be4, issue #4673)

  • src/autoskillit/server/recipe/_recipe_delivery/__init__.py (82 lines total): 42 lines (51%) are import statements (lines 13-55), the rest is an __all__ re-export list. 0% of this file is business logic — it exists purely as a re-export facade required by the folder-decomposition guard.
  • Same pattern elsewhere: cli/prompts/__init__.py (46% import lines), server/tools/tools_kitchen/_open_kitchen/__init__.py (40% import lines).
  • The split introduced new cross-sibling imports that did not exist pre-split, e.g. _finalize.py:56 now imports FinalizedRecipeResponse from sibling _response.py — coupling created by, not reduced by, the decomposition.
  • Commit-wide across just server/ and fleet/: the diff added 298 lines matching ^(from|import) and removed 244 (net +54 import lines), plus 6 new __init__.py re-export facades, purely from re-pointing import paths and satisfying the folder-decomposition layout guard's own required AGENTS.md/CLAUDE.md doc files.

Requested change

Import lines (at least import ... / from ... import ... statements in Python files) should not count toward REQ-CNST-010's 750/1000-line budget the same way business-logic lines do. This doesn't need to be a complete or perfectly precise accounting — an approximate, heuristic exclusion is acceptable, and scoping the fix to Python only (the only language either guard currently covers) is fine. The exact detection mechanism (AST-based, line-pattern-based, handling of multi-line parenthesized imports, TYPE_CHECKING-guarded blocks, etc.) is left to whoever implements this.

Governance note

Both _LINE_LIMIT_EXEMPTIONS (line-count guard's exemption registry) and FILE_COUNT_LIMITS (folder guard) are registered PolicySurface entries in tests/arch/_acceptance_policy_surfaces.py. Changing how lines are counted for REQ-CNST-010 isn't a listed surface itself today, but functionally raises the effective logic-line budget per file, so it's worth checking during implementation whether scripts/check_policy_relaxation.py's gate (tests/AGENTS.md § "Acceptance Policy Surfaces") should treat a counting-methodology change the same way it treats a raised numeric ceiling — i.e. requiring a PolicyRelaxationApproval + code-owner review rather than landing as an ungated change.

No rationale doc found for the "750" figure

There is no ADR/design doc justifying the specific 750/1000 numbers; the closest stated rationale is the general complexity principle in root AGENTS.md ("every added line is a maintenance liability") and the folder guard's "a reviewer can hold it in mind" comment (tests/arch/test_subpackage_isolation_file_counts.py:40-49). Also worth noting: tests/arch/test_subpackage_isolation_size.py:27-33 already documents one case (session.py, ~864 lines) where the team explicitly decided not to split further purely to satisfy the line count — i.e. there's existing precedent for treating the numeric cap as a heuristic rather than an absolute, which may be useful context for whoever scopes the fix.

Dedup check performed

Searched via gh issue list --search across 5 keyword sets plus a manual pass; read the full bodies of every candidate that matched multiple sets or looked topically close: #4662/#4918/#4919 (closed — "Harden file-length enforcement," about hardening/diff-scoping the existing raw-count gate; #4918 explicitly states as a non-goal "Not a change to the rule itself [750/1000/test-exempt] — only the enforcement mechanism"), #4669 (open — folder file-count gate rule codification, explicitly states "Not a rewrite of REQ-CNST-010 [file-length rule] — orthogonal"), #4929/#4933 (open — governance around preventing automated weakening of these guards, a related but distinct concern from how lines are counted), #4951 (open — folder-org follow-up extracting specific sub-packages, not about counting methodology). No existing issue covers excluding import lines from the count.

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions