Conversation
uipreliga
requested review from
CarlesUIPath,
akshaylive,
bai-uipath and
tmatup
as code owners
September 16, 2026 03:03
|
Claude finished @uipreliga's task in 1m 31s —— View job Code Review In Progress
|
prose_budget.py scans a module-level _ROOTS tuple instead of one hard-coded src/coder_eval root. _python_files is the single rglob loop; a root that is not a directory raises FileNotFoundError, in the scan and in assert_code_unchanged, so a renamed root fails the gate instead of passing it on zero files. Reported paths and _TYPER_COMMANDS keys are repo-relative. main prints collect_failures(); its output and exit codes are unchanged. Gate scope is unchanged: _ROOTS is (src/coder_eval,), TOTAL still 17752. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…-rules.md The 2,165-word catalogue paragraph in .claude/notes/README.md is split verbatim into 19 "## CExxx" sections of the new .claude/notes/lint-rules.md (2,138 words; the 27-word difference is the **CExxx** ( markers and the lead-in). README lists the file and says the rule file owns invariant, scope and blind spots; lint-rules.md owns the motivating defect. CLAUDE.md now says the same. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…s.md The 30 rule module docstrings in tests/lint/rules/ over 150 prose words now keep CONTRACT (invariant, forms, scope) and HAZARD (blind spots, noqa guidance) and point at .claude/notes/lint-rules.md § <id> for the defect story. Module docstring prose: 8,347 -> 3,328 words. yaml_models_forbid_extras.py own-line comments: 27 -> 7 (budget 22). New sections: CE009 CE013 CE014 CE020 CE021 CE022 CE024 CE032 CE043 CE046 CE061 _model_ctor. Appended to the Phase-2 sections where new facts existed; facts repeated between a Phase-2 paragraph and the appended text were merged. No pointer (nothing moved, compression only): ce019. Line 1 of every docstring is unchanged. "blind spot" counts, HEAD -> now: _model_ctor 1->1, ce020 0->1, ce058 1->1, ce059 1->1, ce060 2->2, ce061 2->2, ce063 1->1, ce064 1->1, yaml_models_forbid_extras 0->2, all others 0->0. Disagreements resolved (the more precise version kept): - § CE058 said "five syntactic forms"; the rule has six. The notes now defer the list to the docstring. Forms 2-4 flag any number, 1/5/6 zero only. - § CE059 "four suppressions" kept (four generation_duration_ms=None sites). - § CE063 said inverting _imports_the_helper flags four of five reducers; all five import close_window by name, so it is corrected. - ce019: the helpers that do file I/O run only inside init_telemetry's guard; the rest reach side effects through track_event. Review also corrected three misstated contracts (ce053 match scope, ce063 bookkeeping sentence cited by _scrub.py, ce058 field scope) and one wrong comment in ce054 (_written_keys counts only subscript assignment). No executable statement changed — proved by assert_code_unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…les.md The 11 lint tool modules under tests/lint/ and four TestCExxx classes in tests/test_custom_lint.py keep their invariant, scope, opt-out markers and blind spots (these rules have no rule module, so the docstring is their only home) and point at .claude/notes/lint-rules.md § <id>. The 17 essay docstrings: 4,976 -> 1,928 prose words. doc_env_parity.py own-line comments: 31 -> 12 (budget 22). New sections: CE026 CE027 CE028 CE029 CE030 CE031 CE033 CE034 CE035 CE036 CE044 CE045 TestRunRecordFieldVocabulary. Appended: CE047, CE055. The "not a BaseRule in the AST runner" reason stays in each module docstring; the notes keep it only where the docstring gives no reason (CE026, CE033, CE036). Disagreements resolved: - CE044: the old docstring said "Six fields" and listed eight; SHARED_KEYS has eight. - CE047: the section's "four of those seven" count kept over "most". - TestRunRecordFieldVocabulary: _known_fields joins three models, not two. Review also removed facts repeated between docstrings and notes (CE045, CE055) and put fixed defects in the past tense (CE028, CE034). No executable statement changed — proved by assert_code_unchanged. `make docs-indexes plugin-reference` leaves README.md, docs/ and plugins/ unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…o notes The five essay docstrings in the test helpers keep their contract and hazards and point at the notes: - tests/_bracket_clock.py (module 181 -> 85, assert_overhead_is_measured 175 -> 59) -> lint-rules.md § CE064 - _scrub.py::_tool_union_ms (153 -> 73) and ::assert_timing_captured (720 -> ~120) -> timing.md § The golden-stream timing sensor (new ### under § decompose_turn; nothing covered the sensor before) - opencode_fixtures.py (165 -> 100) -> agents.md § Why a clean exit can still be a crash Kept: "run on the UNSCRUBBED dump", the do-not-simplify hazard on _tool_union_ms (its CE063 citation still resolves), the strict > 0.0 tail hazard, the do-not-correct-toward-session.next.* hazard, and that the identity check is one-sided on purpose. No executable statement changed — proved by assert_code_unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…m notes Fifteen essay docstrings in plain test modules now state what they pin plus at most one hazard, and point at the subsystem note that holds the defect story: - timing.md: test_timing_identity_contract (module, _claude_turn, _claude_slow_result_turn), test_timing_close_window, test_agent_telemetry (three new ### subsections) - reporting.md § Plugin and GitHub Action layout: test_action_inputs, test_action_version_pin, test_pr_review_workflow, test_verify_published_workflow (four new ### subsections) - agents.md: test_antigravity_agent (§ The receive_steps re-entrancy window), test_opencode_agent (§ Per-harness generation marks) - isolation.md: test_sandbox_venv_live - test_agent.py: HISTORY only, deleted Comment density: test_agent_golden_master 107 -> 50, test_early_stop 516 -> ~440, test_new_criteria 41 -> 27. Review corrected a false comment added in test_early_stop.py (NoOpAgent does not support the cooperative interrupt), restored the class-level summaries the deleted banners carried as class docstrings, and removed text repeated between timing.md subsections. The 14 files carry 13 Rationale pointers (0 before). No executable statement changed — proved by assert_code_unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The 3/8 slimming joined two docstring lines into one of 124 characters, which ruff E501 flags. Prose only. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…tring citations HISTORY sweep over every docstring and comment under tests/: about 120 lines that said "used to", "no longer", "previously", "pre-fix" or "an earlier version" now state the current contract in the present tense, or are deleted. No intentional hit is left; both listings from the plan print nothing: - HISTORY regex over prose lines: 0 hits (was 124) - test-function docstrings over 100 prose words: 0 (was 16) CE006 and CE007 first lines are present-tense contracts. CE007 drops the word "fields" from the planned text, which is 122 characters and fails ruff E501. CE006 now says "see CE007" instead of claiming the fields are top-level. Dangling "see ... docstring" citations fixed: - src/coder_eval/harbor/packager.py `_write_verifier_task_yaml` docstring and comment, and tests/test_harbor_packager.py (x2) now point at reporting.md § The non-obvious constraint in the emitted task.yaml - tests/test_harbor_agent.py cites the ImportError in harbor/agent.py, which holds the claim; the module docstring never did The shape is recorded in .claude/harness-candidates.md (not mechanised). Notes: reporting.md said the Action's env passthrough exports into the step shell; action.yml collects it and hands it to `env --`. Corrected in place. Review corrected rewrites that were false: a hazard in test_regrade.py named a symbol that does not exist; test_task_definition_unknown_fields.py listed `skip` as undeclared although TaskDefinition declares it; test_agent.py said the rollback keys on one signal where the code ORs two; and agents.md said the four-bucket identity is only an upper bound, which a test now checks exactly. No executable statement changed — proved by assert_code_unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
tests/lint/prose_budget.py scans _ROOTS = (src/coder_eval, tests), so `make docs-budget` (and `make verify`) now fail on a docstring over 150 prose words, an own-line comment budget breach, or an unresolved/misplaced Rationale pointer anywhere under tests/. - test_prose_budget.py: test_default_roots_include_tests replaces the "not yet on" pin; every synthetic tree now contains every default root, because a missing root raises by design; the follow-roots tests patch _ROOTS to src-only for their "before" half. - prose_budget.py module docstring describes the two per-file rules; it still described the removed single-number ratchet. - .claude/notes/README.md § "The prose budget is not a lint rule" (renamed; no pointer named the old heading) describes the two rules, the pointer checks and both roots. Makefile help text and the CLAUDE.md Design Principles bullet name src/ and tests/. Verified: gate exits 0 with tests in scope (0 essays, no comment-budget failures); a temporary 200-word test docstring makes it exit 1; make verify passes (5744 passed, coverage 92.60%). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…typos Two ways the prose budget tool could pass without checking what it claims: - assert_code_unchanged compared directive comments one way only, so adding a `# noqa` or `# pragma` to a "prose-only" commit passed the proof. It now reports added directives as well as dropped ones, as its docstring says. - main() ran the ordinary gate for any argv, so a misspelled `--assert-code-unchanged` exited 0 without proving anything. Unknown arguments are now a usage error (exit 2). Both caught by the final review of the tests prose slimming run; tests added first and seen failing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both are deferred with the reason: the Args-then-narrative placement case needs an indentation-aware walk plus false-positive triage, and restricting pointer targets to .claude/notes/ is a design decision, not a mechanical guard. The two cheap gaps from the same review were closed in e71a16f0. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
assert_code_unchanged listed files with `git diff --name-only <ref>`, which
never names an untracked file, and the proof runs on uncommitted edits. A new
.py file holding code therefore passed a "prose only" check. The listing now
adds `git ls-files --others --exclude-standard` over the same roots; a new file
has no "before", so any statement in it is reported.
test_prose_budget.py also drops ratchet-era wording ("drifting baseline",
"replaced the hand-maintained baseline", "promoted after three phases") from
three docstrings.
Caught by the final review of the tests prose slimming run; test added first
and seen failing.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Final review (two models plus an Opus pass over the whole 946ca96 range): - timing.md § The golden-stream timing sensor said two harnesses take the duration from a monotonic clock and the bounds from the wall clock. Every clocked harness takes both from one TurnClock; the paragraph now gives the real reason the bounds check is not redundant. - Six TestCExxx class docstrings in test_custom_lint.py (CE026, CE029, CE035, CE036, CE044, CE056) still told the defect story that lint-rules.md holds; they now keep invariant and wiring and point at the section. - One home per fact: the Pi one-sided-sensor argument stays in timing.md (removed from lint-rules.md § CE061 and agents.md); the OpenCode/Pi overstatement examples stay in agents.md (removed from § CE063). - lint-rules.md § CE064 gave the antigravity tail as 0.035 ms and as 0.007-0.03 ms; it is one range, 0.007-0.035 ms. - test_harbor_export_golden.py cited the packager's module docstring for the placeholder-agent design, which it never held; it points at reporting.md. - reporting.md said CLAUDE.md lists "five" agent lifecycle requirements; it lists six, so the count is dropped. No executable statement changed — proved by assert_code_unchanged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`test_every_exempt_pair_still_exists` (added on main, #177) joined each _TYPER_COMMANDS entry onto src/coder_eval. 1/8 made those keys repo-relative because the gate now reports repo-relative paths for two roots, so the join produced src/coder_eval/src/coder_eval/... and the test failed after the rebase. It resolves against the repo root instead; what it guards is unchanged. A silent conflict: both sides merged textually, and only the test run showed it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The prose budget now covers `tests/`, and `396c22cc` landed three new modules plus two reworded ones whose docstrings are over the 150-word bar. Their narrative moves to `.claude/notes/lint-rules.md` behind a `Rationale:` pointer, the shape the rest of this branch uses. New notes sections: CE004, CE065, CE066, `_layers`, `TestRuffExternalCoversEveryRule`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…xists `src/coder_eval/proxy/` is gone — CHANGELOG 2487 records deleting the `coder_eval.proxy.pricing` shim. The rule that banned importing it stayed, so it cannot fire, and its docstring still described the shim as present. Removed from all five places a rule lives: the module, its `runner.py` import and `ALL_RULES` entry, its test class, and its id in `[tool.ruff.lint] external`. The id stays retired, as `runner.py` already requires for CE062. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
uipreliga
force-pushed
the
docs/slim-tests-prose
branch
from
September 16, 2026 04:48
eec2c4e to
1ad75ef
Compare
`MAX(20, 0.15 x lines)` on a file's total own-line comments was inverted. It blocked `isolation/docker_runner.py` at 229/229 for carrying 62 short annotations pinned to the lines they explain, while a 16-line essay in `tests/test_regrade.py` sat at 29% of its budget. Four files had settled at exactly 100% of the cap: the budget had stopped being a ceiling and become a target. The failure mode the rule exists to stop is a PARAGRAPH in the code, which is a long run, not a high total. So the bar is now the run: no own-line comment run over 8 lines, reading through one blank line so splitting a paragraph does not duck it, and through none at two, which is the separation PEP 8 already puts between a banner and its section. There is no per-file allowance, so a file may carry any number of one-line notes and none of them may grow into an essay. Measured before choosing 8: 78.5% of runs in the tree are 1-2 lines, 2.5% are 6 or more, and the longest was 16. The cap is below the current maximum, as a cap rule must be. 24 runs in 25 files are moved to `.claude/notes/` behind a `Rationale:` pointer or shortened. New notes sections: reporting § Ungraded rows in a rollup, permissions § Why the chmod tests are Linux-only, lint-rules § The CE id space, § CE058 field families, § Keeping DELIBERATELY_UNMIRRORED honest. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…e run cap The run cap governs the SHAPE of any one comment and has no allowance, so it cannot see a file that passes with every block short and is still mostly commentary. `MAX(20, 0.15 x lines)` on the file total is restored verbatim to catch that, and `check_comment_density` now says so in its own docstring rather than standing alone. Three rules now, in order of what they do: the run cap is primary, the file total is the backstop, the 150-word essay bar governs docstrings. `test_it_catches_what_the_run_cap_cannot` pins the seam — thirty three-line blocks pass the run cap and fail the total — so neither rule can be deleted as redundant without that test going red. Four files sit at exactly 100% of their total budget (`docker_runner.py` 229/229, `criteria/agent_judge.py` 65/65, `evaluation/sub_agent.py` 34/34, `config.py` 33/33). A comment added to one of them has to be paid for by deleting another; that is recorded in `.claude/notes/README.md`, with the measurements behind the run cap. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

Applies the prose rules this repo enforces on
src/coder_evaltotests/, turns the gate on for it, and — withtests/lint/finally in scope — fixes the one gate rule that turned out to be measuring the wrong thing. Follows #177, which did the same forsrc/, and is rebased onto #176.Four things happen here.
1. The gate now scans
tests/as well assrc/tests/lint/prose_budget.pyscans a_ROOTStuple instead of one hard-coded root, reports repo-relative paths, and fails when a root does not exist — in the scan and in--assert-code-unchanged, so a renamed root can never pass on zero files._python_filesis the single traversal;mainprintscollect_failures(). Phase 8 flips the default to(src/coder_eval, tests).That put the essay police on their own beat for the first time. 67 docstrings over 150 prose words and 5 files over their comment budget, cleared:
tests/lint/rules/TestCExxxclasses_scrub.py,_bracket_clock.py,opencode_fixtures.pytests/Across the branch,
tests/lint/goes from 18,265 to 11,668 docstring prose words and all oftests/from 105,305 to 95,722.Each docstring keeps its contract and hazards; the defect story moves behind a resolving
Rationale: <path> § <heading>pointer. Rule rationale now lives in the new.claude/notes/lint-rules.md(one section per CE id, split verbatim out of.claude/notes/README.md); test rationale goes to the subsystem note it belongs to.Dangling citations fixed:
harbor/packager.pyandtests/test_harbor_packager.pycited a module docstring that no longer held the claim;tests/test_harbor_agent.pycited one that never did.Prose-only, proved
Every prose phase passes
--assert-code-unchanged, which compares the docstring-stripped AST and the directive comments against the base.Gate holes the final review found, and closed here
Three ways the tool could pass without checking what it claims (each fixed test-first):
assert_code_unchangedcompared directive comments one way, so adding a# noqapassed a "prose-only" proof.main()ran the ordinary gate for any argv, so a mistyped--assert-code-unchangedexited 0 having proved nothing.git diff --name-only, which never names an untracked file, so a new.pyfile full of code passed.Two further gaps needed design work and are deferred in
.claude/harness-candidates.md: narrative after anArgs:block that follows a pointer, and pointer targets outside.claude/notes/.2. Rebased onto #176, which brought five new essays
396c22cc(the reports split) landed three new modules and reworded two more, all over the 150-word bar once this branch's gate sees them:New notes sections carry what moved:
CE004,CE065,CE066,_layers,TestRuffExternalCoversEveryRule. Three merge conflicts resolved:ce053's docstring (kept the slimmed side),harness-candidates.md(kept both appends) and theMakefile(keptpricing-mirrorand the newdocs-budgethelp text).3. CE023 deleted — it guarded a package that no longer exists
src/coder_eval/proxy/is gone;CHANGELOG.md:2487records deleting thecoder_eval.proxy.pricingshim. The rule banning imports of it stayed behind, so it could not fire, and its docstring still described the shim as present.Removed from all five places a rule lives: the module, its
runner.pyimport andALL_RULESentry, its test class, and its id in[tool.ruff.lint] external. The id stays retired, asrunner.pyalready requires for CE062 — both are now recorded in.claude/notes/lint-rules.md § The CE id space, which replaces the 14-line comment that used to carry it.46 → 45 registered rules.
4. The comment budget was inverted, so the rule is now the comment RUN
With
tests/lint/in scope I measured whatMAX(20, 0.15 × lines)on a file's total comment lines was actually doing. It was backwards:isolation/docker_runner.pytests/test_regrade.pysrc/coder_eval/criteria/base.pyIt taxed short annotations pinned to the line they explain, and waved through the paragraphs that
.claude/notes/exists to hold. Four files had settled at exactly 100.0% of budget (docker_runner.py229/229,criteria/agent_judge.py65/65,evaluation/sub_agent.py34/34,config.py33/33) — nobody lands on 229/229 by accident; the budget had become a target.So a third rule is added, and it is the primary one:
A run reads through one blank line, so splitting a paragraph does not duck it, and through none at two, which is the separation PEP 8 already puts between a banner and its section. It caps a shape, with no per-file allowance: carry as many one-line notes as earn their place.
Measured before choosing 8: 78.5% of runs in the tree are 1–2 lines, 2.5% are 6 or more, and the longest was 16. The cap is below the current maximum, as a cap rule must be. 24 runs across 19 files were shortened or moved to
.claude/notes/behind a pointer — 6 insrc/, 18 intests/.The file total is kept as the backstop underneath, unchanged at
MAX(20, 0.15 × lines): a file can pass the run cap with every block short and still be mostly commentary.test_it_catches_what_the_run_cap_cannotpins that seam — thirty three-line blocks pass the run cap and fail the total — so neither rule can later be deleted as redundant without a red test.make docs-budgetnow enforces three rules on both roots: comment run ≤ 8 lines, file total ≤MAX(20, 0.15 × lines), docstring ≤ 150 prose words.Worth a human's eye
.claude/notes/README.mdwith the measurements, so the next person to hit it sees the trade rather than bumping the number blind.src/is touched, in 6 files — all of them one over-long comment run each, moved to notes behind a pointer. No behaviour change..claude/notes/README.md— docs: move design rationale out of src/ into .claude/notes, gate it, and slim CLAUDE.md #177 had rewritten that section to say no prose summary is kept there; this branch points it atlint-rules.md. The rule file owns invariant/scope/blind spots,lint-rules.mdowns the motivating defect, and the rule file wins on disagreement.tests/loses ~12,700 docstring words and.claude/notes/gains ~12,400..claude/has no prose budget, so the repo total is roughly flat; that is the design (rationale has one home) but it is worth stating plainly rather than claiming a reduction.Verification
make verify: 5,816 passed, 2 skipped, 92.63% coverage, 671 custom lint rules — ruff format, ruff check, pyright, lint suite, prose gate, full test run. The gate reports 0 essays, 0 over-long runs and 0 files over budget with both roots in scope.🤖 Generated with Claude Code