Skip to content

Commit 0a1e42e

Browse files
etrclaude
andcommitted
ci: per-file line-count gate (FILE_LOC_MAX)
Adds scripts/check-file-size.sh, a third lint-lane gate alongside check-complexity.sh (CCN) and check-duplication.sh (CPD). Counts physical lines via wc -l for every .cpp/.hpp under src/ and fails if any file exceeds FILE_LOC_MAX. FILE_LOC_MAX defaults to 2700, just above the current worst offender (webserver.cpp at 2673), so CI stays green on landing. Long-term target is 500 lines — matches the per-module SLOC ceiling used by the sibling project under ../artistai and the natural break point where everything else already complies. The script header lists the seven current offenders and documents the ratchet-down strategy (one refactor commit at a time tightens the bar), mirroring how CCN_MAX was driven to 10. Wires the gate into: - Makefile.am: new lint-file-size target + EXTRA_DIST entry - .github/workflows/verify-build.yml: new step in the ubuntu lint lane, conditional on build-type == 'lint' (same gating as the sibling gates) Architecture spec is not yet updated; the same gap exists for the existing CCN/CPD gates (see specs/unworked_review_issues/ 2026-05-21_121150_manual-validation.md) and is best closed in one sweep. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 120edcd commit 0a1e42e

3 files changed

Lines changed: 84 additions & 1 deletion

File tree

.github/workflows/verify-build.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -681,6 +681,10 @@ jobs:
681681
run: ./scripts/check-duplication.sh
682682
if: ${{ matrix.build-type == 'lint' && matrix.os-type == 'ubuntu' }}
683683

684+
- name: Run per-file line-count gate
685+
run: ./scripts/check-file-size.sh
686+
if: ${{ matrix.build-type == 'lint' && matrix.os-type == 'ubuntu' }}
687+
684688
- name: Run libhttpserver configure
685689
run: |
686690
# Set memory check flags. They need to stay in step as env variables don't propagate across steps.

Makefile.am

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ EXTRA_DIST = libhttpserver.pc.in $(DX_CONFIG) scripts/extract-release-notes.sh s
4343
scripts/check-doxygen.sh \
4444
scripts/check-soversion.sh scripts/check-parallel-install.sh \
4545
scripts/check-complexity.sh scripts/check-duplication.sh \
46+
scripts/check-file-size.sh \
4647
scripts/verify-installed-examples.sh \
4748
test/headers/consumer_direct.cpp test/headers/consumer_detail.cpp test/headers/consumer_umbrella.cpp \
4849
test/headers/consumer_post_umbrella.cpp \
@@ -366,7 +367,15 @@ lint-duplication:
366367
@echo "=== lint-duplication: enforce zero copy/paste duplication ==="
367368
@$(top_srcdir)/scripts/check-duplication.sh
368369

369-
.PHONY: check-headers check-install-layout check-hygiene check-examples check-readme check-release-notes check-doxygen check-soversion check-parallel-install lint-complexity lint-duplication
370+
# Per-file line-count gate. Fails if any src/ .cpp/.hpp exceeds
371+
# FILE_LOC_MAX (default in the script; ratcheted down toward the
372+
# long-term 500-line target as each offender is decomposed). Not wired
373+
# into `make check` — invoked directly by CI's `lint` lane.
374+
lint-file-size:
375+
@echo "=== lint-file-size: enforce per-file line-count ceiling ==="
376+
@$(top_srcdir)/scripts/check-file-size.sh
377+
378+
.PHONY: check-headers check-install-layout check-hygiene check-examples check-readme check-release-notes check-doxygen check-soversion check-parallel-install lint-complexity lint-duplication lint-file-size
370379

371380
# TASK-039: top-level convenience rule that descends into test/ to
372381
# build and run the bench binaries (see test/Makefile.am and

scripts/check-file-size.sh

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
#!/usr/bin/env bash
2+
#
3+
# check-file-size.sh — enforce a per-file line-count ceiling on the C++
4+
# library sources.
5+
#
6+
# Scope: src/ (library code only). test/ and examples/ are not scanned —
7+
# test fixtures and demo scaffolding legitimately grow large and are not
8+
# the subject of this gate.
9+
#
10+
# Scanned extensions: .cpp, .hpp (matches cpplint's --extensions=cpp,hpp
11+
# and the v2.0 source convention; no .h / .cc in src/).
12+
#
13+
# Metric: physical line count via `wc -l` (blank and comment lines
14+
# included). Physical lines were chosen over SLOC to avoid pulling in a
15+
# tokeniser dependency for this gate; the per-function complexity gate
16+
# already covers semantic density.
17+
#
18+
# Threshold knob:
19+
# FILE_LOC_MAX maximum physical lines per file (default below)
20+
#
21+
# FILE_LOC_MAX is currently set above the largest existing file so CI
22+
# stays green on the day this gate lands. The long-term target is 500
23+
# lines, matching the per-module ceiling used by the sibling project
24+
# under ../artistai (radon SLOC) and the natural break point where the
25+
# remaining files already comply.
26+
#
27+
# The bar will be ratcheted down per refactor commit as each offender
28+
# is decomposed — same pattern used to drive CCN_MAX to 10 in
29+
# scripts/check-complexity.sh. New files must come in well below the
30+
# long-term target; lifting FILE_LOC_MAX is not allowed.
31+
#
32+
# Current offenders above the long-term 500-line target (2026-05-21):
33+
# src/webserver.cpp 2673
34+
# src/http_request.cpp 1175
35+
# src/httpserver/webserver.hpp 845
36+
# src/http_utils.cpp 730
37+
# src/httpserver/detail/webserver_impl.hpp 674
38+
# src/httpserver/http_request.hpp 656
39+
# src/httpserver/http_utils.hpp 505
40+
#
41+
# Exit codes:
42+
# 0 no violations
43+
# 1 one or more files exceed FILE_LOC_MAX
44+
set -euo pipefail
45+
46+
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
47+
FILE_LOC_MAX="${FILE_LOC_MAX:-2700}"
48+
49+
cd "$REPO_ROOT"
50+
51+
echo "check-file-size: scanning src/ with FILE_LOC_MAX=$FILE_LOC_MAX"
52+
53+
violations=0
54+
# -print0/read -d '' keeps the loop safe against any future filename with
55+
# whitespace, even though src/ today is plain ASCII.
56+
while IFS= read -r -d '' file; do
57+
lines=$(wc -l < "$file" | tr -d '[:space:]')
58+
if [ "$lines" -gt "$FILE_LOC_MAX" ]; then
59+
echo " $file: $lines lines (max $FILE_LOC_MAX)" >&2
60+
violations=$((violations + 1))
61+
fi
62+
done < <(find src -type f \( -name '*.cpp' -o -name '*.hpp' \) -print0)
63+
64+
if [ "$violations" -gt 0 ]; then
65+
echo "check-file-size: FAIL — $violations file(s) exceed FILE_LOC_MAX=$FILE_LOC_MAX" >&2
66+
echo " threshold lives in scripts/check-file-size.sh (FILE_LOC_MAX default)" >&2
67+
exit 1
68+
fi
69+
70+
echo "check-file-size: PASS — no file exceeds $FILE_LOC_MAX lines"

0 commit comments

Comments
 (0)