Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
c27198b
feat(lint): 1/8 — scan a _ROOTS tuple in the prose budget
uipreliga Sep 15, 2026
008a778
docs(tests): 2/8 — move the CE catalogue from notes/README.md to lint…
uipreliga Sep 15, 2026
785e5e4
docs(tests): 3/8 — move lint-rule defect stories into notes/lint-rule…
uipreliga Sep 15, 2026
35e21e8
docs(tests): 4/8 — move doc-surface rule rationale into notes/lint-ru…
uipreliga Sep 15, 2026
63afce3
docs(tests): 5/8 — move golden-sensor and bracket-clock rationale int…
uipreliga Sep 15, 2026
deae3c8
docs(tests): 6/8 — move plain test-module rationale into the subsyste…
uipreliga Sep 15, 2026
a50c981
fix(docs): wrap an over-long line in the CE063 docstring
uipreliga Sep 15, 2026
479f1a3
docs(tests): 7/8 — delete HISTORY prose from tests, fix dangling docs…
uipreliga Sep 15, 2026
4e1bebb
feat(lint): 8/8 — turn the prose budget gate on for tests/
uipreliga Sep 15, 2026
a9bb313
fix(lint): make the prose-only proof see added directives and reject …
uipreliga Sep 15, 2026
c821fd8
docs: record two prose-budget guard gaps the final review found
uipreliga Sep 15, 2026
a79e75b
fix(lint): include untracked files in the prose-only proof
uipreliga Sep 15, 2026
425b7ce
fix: code review fixes for tests-slim-prose
uipreliga Sep 15, 2026
b8700f2
fix(lint): point main's exempt-pair test at the repo root
uipreliga Sep 16, 2026
9bb48d2
docs(lint): slim the five essays main's reports split brought in
uipreliga Sep 16, 2026
1ad75ef
refactor(lint): delete CE023, which guards a package that no longer e…
uipreliga Sep 16, 2026
c4d91e1
feat(lint): cap the comment RUN, replacing the per-file comment budget
uipreliga Sep 16, 2026
73165be
feat(lint): keep the file-total comment budget as a backstop under th…
uipreliga Sep 16, 2026
ed1c01c
docs(lint): answer review — cut runs off the cap, drop lint-rules.md …
uipreliga Sep 16, 2026
d20d40e
fix(lint): fail the prose gate cleanly on a missing root, and name th…
uipreliga Sep 16, 2026
5cfec18
Merge branch 'main' into docs/slim-tests-prose
uipreliga Sep 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix(lint): fail the prose gate cleanly on a missing root, and name th…
…e blank-line blind spot

A renamed root now prints one line and exits 1 instead of a traceback. The
own_comment_runs docstring and CLAUDE.md now state that two blank lines at
module scope split a run.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
  • Loading branch information
uipreliga and claude committed Sep 16, 2026
commit d20d40e603fbdf5775d2968049d120c268c03410
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,8 @@ bandit, pre-commit, mcp
it correctly. Why the design is this shape belongs in `.claude/notes/`; what it used to
be belongs in git. `make docs-budget` applies three self-adjusting rules to `src/` and
`tests/`: no own-line comment RUN may exceed 8 lines (a run reads through one blank line,
so splitting a paragraph does not duck it), a file's own-line comments may not exceed
`MAX(20, 0.15 × its length)` in total, and no docstring may exceed 150 words of PROSE (an
so a paragraph split on one blank line does not duck it), a file's own-line comments may
not exceed `MAX(20, 0.15 × its length)` in total, and no docstring may exceed 150 words of PROSE (an
`Args:`/`Returns:`/`Raises:` block is structure, not prose; an `@abstractmethod` is exempt
because its docstring IS the interface contract). The run cap governs the SHAPE of any one
comment — put the paragraph in `.claude/notes/` behind a `Rationale:` pointer — and the
Expand Down
10 changes: 10 additions & 0 deletions tests/lint/prose_budget.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,9 @@ def own_comment_runs(source: str) -> list[tuple[int, int]]:
does not read as several short comments. Code between two comments always ends
the run. A trailing ``# noqa`` never starts one: it is a directive, not
commentary.

Blind spot: at module scope ruff format keeps two blank lines, so a paragraph split
on two blank lines there reads as two runs.
"""
lines = source.split("\n")
try:
Expand Down Expand Up @@ -583,7 +586,14 @@ def assert_code_unchanged(repo_root: Path, ref: str) -> list[str]:

def main(argv: list[str]) -> int:
repo_root = Path(__file__).resolve().parents[2]
try:
return _run(repo_root, argv)
except FileNotFoundError as error:
print(error, file=sys.stderr)
return 1


def _run(repo_root: Path, argv: list[str]) -> int:
if argv[:1] == ["--assert-code-unchanged"]:
if len(argv) != 2:
print("usage: --assert-code-unchanged <git-ref>", file=sys.stderr)
Expand Down
7 changes: 7 additions & 0 deletions tests/test_prose_budget.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,13 @@ def test_a_missing_root_raises(self, tmp_path: Path, monkeypatch: pytest.MonkeyP
with pytest.raises(FileNotFoundError, match="nope"):
prose_budget.measure(tmp_path)

def test_a_missing_root_fails_the_gate_without_a_traceback(
self, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
) -> None:
monkeypatch.setattr(prose_budget, "_ROOTS", (Path("nope"),))
assert prose_budget.main([]) == 1
assert capsys.readouterr().err == "prose budget root does not exist: nope\n"

def test_two_roots_are_both_measured(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
root = _write(tmp_path, {"src/coder_eval/a.py": _ESSAY, "tests/b.py": _ESSAY})
monkeypatch.setattr(prose_budget, "_ROOTS", (Path("src/coder_eval"), Path("tests")))
Expand Down
Loading