{ "intent": "Bring brother_printer/consumables.py under the 250-line cap by moving the dropped-page detection into its own module, with no behaviour change.", "scope": [ "python_pkg/brother_printer/_page_delivery.py (new)", "python_pkg/brother_printer/consumables.py", "python_pkg/brother_printer/_page_count.py (import path only)", "python_pkg/brother_printer/tests/test_consumables_part2.py (second MOD constant, applied per class)", "Non-goal: no assertion changed, no test deleted, skipped or weakened" ], "changes": [ "Moved check_page_delivery and _snapshot_counters verbatim into python_pkg/brother_printer/_page_delivery.py, which imports the three state-file primitives from consumables.", "The primitives themselves stay in consumables.py: test_consumables.py patches _load_consumable_state, _save_consumable_state, _get_cups_total_pages, CONSUMABLE_STATE_FILE and CUPS_PAGE_LOG on that module, and moving any of them would have let a test write to the real state file at ~/.config/brother_printer/state.json.", "consumables.py dropped the now-unused PAGE_DROP_WARN_THRESHOLD and PageDeliveryCheck imports; 279 -> 217 lines.", "test_consumables_part2.py gained a second constant MOD_PD alongside MOD, applied only to TestCheckPageDelivery and TestSnapshotCounters. Its other two classes test functions that did not move and keep MOD. This is the per-name discipline docs/python-split-recipes.md requires, not a blanket swap: the same three primitives are patched from both modules, so which MOD is correct depends on which caller the test exercises.", "_page_count.py imports check_page_delivery from _page_delivery now; test_page_count.py patches that name on _page_count, so it needed no edit." ], "verification": [ { "command": "PYTHONPATH=. python3 -m pytest python_pkg/brother_printer/tests -q", "result": "pass", "evidence": "402 passed before the split and 402 passed after it - identical pass count, not merely a green run." }, { "command": "PYTHONPATH=. python3 -c \"from python_pkg.brother_printer import _page_delivery as pd, consumables as c, _page_count as pc; pd._load_consumable_state; pd._save_consumable_state; pd._get_cups_total_pages; c.CONSUMABLE_STATE_FILE; c.CUPS_PAGE_LOG; c._migrate_state_to_printer_scale; pc.check_page_delivery\"", "result": "pass", "evidence": "runtime probe OK - both MOD and MOD_PD resolve every name their classes patch." }, { "command": "ls -la ~/.config/brother_printer/state.json", "result": "pass", "evidence": "mtime still Jul 17 14:42 after the full suite run, so no test escaped its mock and wrote to the live consumable state. A green pass count alone would not have caught that." }, { "command": "wc -l python_pkg/brother_printer/consumables.py python_pkg/brother_printer/_page_delivery.py", "result": "pass", "evidence": "217 and 76 lines, both under the 250-line cap." }, { "command": "pre-commit run --files ", "result": "pass", "evidence": "ruff, ruff format, mypy, pylint, bandit and pytest-with-coverage all pass on the touched files." } ], "risks": [ "test_consumables_part2.py now carries two module constants; a future edit that patches a state primitive in the wrong one fails loudly with an AttributeError rather than silently, because each name exists in only one of the two modules under its own MOD.", "consumables <- _page_delivery <- _page_count is a three-module chain; consumables must never import from _page_delivery or it becomes a cycle." ], "rollback": [ "git revert the commit; consumables.py returns to 279 lines and _page_delivery.py disappears.", "After rollback, re-run the package suite and confirm it still reports 402 passed." ] }