Repository navigation
docs: state the module-size limit #853 actually enforces - #888
Merged
Merged
Conversation
`scripts/check_module_size.py` has enforced `LIMIT = 500` since 663b0f2 ("reconcile invariants and module-size policy", #853). That change updated AGENTS.md, docs/agent-context/invariants.md, .claude/CLAUDE.md and the script itself, but missed two places that state the rule to anyone looking it up: * `Makefile:246` - "enforces <=300 lines for new modules" * `docs/agent-context/workflows.md:18` - "enforce the <=300-line convention" An agent consulting either would split a cohesive 350-line module for no reason, which is exactly what the gate's own docstring warns against ("not a target to split cohesive modules mechanically"). Also drops a stale self-description in `_schema_gen.py`, which claimed the module "exceeds the 300-line soft cap (~360 lines)". It is 280 lines, and the cap is 500, so the sentence was false in both halves. The exemption note it sat in is kept - the coupling argument for not splitting the file is still the reason it is exempt. `llms-full.txt` regenerated with `make llms` rather than hand-edited; the only delta is the workflows.md line above. Deliberately NOT changed: eleven module docstrings under `src/` that narrate why a past split happened ("Extracted to keep the store module under the 300-line ceiling (issue #497)"). Those are accurate records of a decision taken when 300 was the limit, and rewriting them to 500 would falsify the history without making any current rule clearer. Four of them read as live guidance rather than history and are worth a follow-up; they are listed in the PR body rather than swept silently here. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XhJp1Rnr6mF4vdSLkj14jU
Contributor
Benchmark delta (vs
|
| size | recall@k (head Δ vs base) | MRR (head Δ vs base) | p99 (ms) |
|---|---|---|---|
| 50 | ✅ 0.5649 (+0.0000) | ✅ 0.4978 (+0.0000) | ✅ 0.503 (base 0.650) |
| 83 | ✅ 0.3825 (+0.0000) | ✅ 0.3242 (+0.0000) | ✅ 0.739 (base 1.205) |
| 1000 | ✅ 0.1475 (+0.0000) | ✅ 0.1456 (+0.0000) | ✅ 37.639 (base 47.855) |
Per-backend × per-size matrix
| backend | size | recall@k (Δ) | MRR (Δ) | p99 (ms) |
|---|---|---|---|---|
| bm25 | 100 | ✅ 0.3825 (+0.0000) | ✅ 0.3399 (+0.0000) | ✅ 6.558 (base 8.399) |
| bm25 | 500 | ✅ 0.2250 (+0.0000) | ✅ 0.2165 (+0.0000) | ✅ 29.474 (base 41.865) |
| bm25 | 1000 | ✅ 0.1575 (+0.0000) | ✅ 0.1525 (+0.0000) | ✅ 86.691 (base 112.387) |
| embedding_hashing | 100 | ✅ 0.5175 (+0.0000) | ✅ 0.4360 (+0.0000) | ✅ 7.557 (base 7.218) |
| embedding_hashing | 500 | ✅ 0.2700 (+0.0000) | ✅ 0.2674 (+0.0000) | ✅ 41.186 (base 43.171) |
| embedding_hashing | 1000 | ✅ 0.2000 (+0.0000) | ✅ 0.1931 (+0.0000) | ✅ 99.116 (base 102.979) |
| embedding_st | 100 | skipped (skipped: missing sentence-transformers) | — | — |
| embedding_st | 500 | skipped (skipped: missing sentence-transformers) | — | — |
| embedding_st | 1000 | skipped (skipped: missing sentence-transformers) | — | — |
| fuzzy | 100 | skipped (skipped: missing rapidfuzz) | — | — |
| fuzzy | 500 | skipped (skipped: missing rapidfuzz) | — | — |
| fuzzy | 1000 | skipped (skipped: missing rapidfuzz) | — | — |
| tfidf | 100 | ✅ 0.3825 (+0.0000) | ✅ 0.3220 (+0.0000) | ✅ 1.097 (base 1.193) |
| tfidf | 500 | ✅ 0.2325 (+0.0000) | ✅ 0.2314 (+0.0000) | ✅ 9.102 (base 10.803) |
| tfidf | 1000 | ✅ 0.1475 (+0.0000) | ✅ 0.1456 (+0.0000) | ✅ 37.180 (base 42.986) |
Context pipeline (per scenario)
| scenario | tokens | dropped | dedup |
|---|---|---|---|
| large_catalog | 1480 (base 1480, Δ+0) | 0 (base 0, Δ+0) | 0 (base 0, Δ+0) |
| long_conversation | 2500 (base 2500, Δ+0) | 0 (base 0, Δ+0) | 0 (base 0, Δ+0) |
| mixed_payload | 488 (base 488, Δ+0) | 0 (base 0, Δ+0) | 0 (base 0, Δ+0) |
| short_conversation | 487 (base 487, Δ+0) | 0 (base 0, Δ+0) | 0 (base 0, Δ+0) |
| stress_conversation | 6590 (base 6590, Δ+0) | 11 (base 11, Δ+0) | 4 (base 4, Δ+0) |
| tiny_payload | 256 (base 256, Δ+0) | 0 (base 0, Δ+0) | 0 (base 0, Δ+0) |
Numbers come from make benchmark / make benchmark-matrix.
Latency is hardware-dependent — treat the markers as a rough guide.
See benchmarks/scorecard.md for the full picture.
7 of 8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
scripts/check_module_size.pyhas enforcedLIMIT = 500since663b0f2("reconcile invariants and module-size policy", #853). That commit updatedAGENTS.md,docs/agent-context/invariants.md,.claude/CLAUDE.mdand the script — and missed the two places that state the rule to someone looking it up. This finishes #853.Found while checking my own PR #887 against the checklist item "every modified module stays ≤ 300 lines", which is itself the stale number.
Fixes #
Changes
Makefile:246— "enforces ≤300 lines for new modules" → ≤500.docs/agent-context/workflows.md:18— "enforce the ≤300-line convention" → ≤500.src/contextweaver/_schema_gen.py— drops a stale self-description claiming the module "exceeds the 300-line soft cap (~360 lines)". It is 280 lines and the cap is 500, so the sentence was false in both halves. The exemption note it sat inside is kept: the coupling argument for not splitting the file is still why it is exempt.llms-full.txt— regenerated withmake llms, not hand-edited. Sole delta is theworkflows.mdline above.Why it matters
The gate's own docstring says the limit is "a ratchet, not a target to split cohesive modules mechanically". An agent consulting the Makefile or
workflows.mdwould read 300 and split a cohesive 350-line module for nothing — the precise outcome both documents exist to prevent.Checklist
make cipasses locally — partially, see NotesCHANGELOG.mdupdated under## [Unreleased]gen_api_manifest.py --checkreports "up to date"check_module_size.py:OK (236 modules, 8 grandfathered ≤ frozen ceiling)Notes for reviewers
Deliberately not changed — and I want this reviewed as a judgment call, not assumed. Eleven module docstrings under
src/still say 300. Most narrate why a past split happened:Those are accurate records of a decision taken when 300 was the limit. Rewriting them to 500 would falsify the history without making any current rule clearer, so I left them. Same reasoning the repo applies to dated audit records elsewhere.
Four read as live guidance rather than history, and are worth a follow-up:
extras/embeddings.py:28routing/filters.py:14routing/explanation.py:6__main__.py:30I did not sweep these because the fix is not purely mechanical — each needs a decision about whether the sentence is describing the rule or the reason, and
__main__.py's exemption claim is correct even though its number is not. Listing them explicitly rather than leaving them for someone to rediscover; happy to do them in a follow-up if you'd rather they all move together.What I ran:
check_module_size.py(OK),drift_check.py --check(all 10 artifacts up to date, aftermake llms),gen_api_manifest.py --check(up to date),ruff checkandruff format --checkon the changed source file. I did not run fullmake ci:mkdocsis not installed in this container so thedocstarget cannot run, and the test suite is unaffected by a comment-only change. CI is the authority on the rest.🤖 Generated with Claude Code
https://claude.ai/code/session_01XhJp1Rnr6mF4vdSLkj14jU
Generated by Claude Code