refactor(recall): split pg_recall.py to the local 300-line/40-line caps - #411
Conversation
…ee seams CLAUDE.md/CONTRIBUTING.md tighten the repo-wide 500-line file cap (coding-standards.md §4.1) to 300 lines, and enforce a 40-line method cap (§4.2). pg_recall.py stood at 494 lines against that local 300-line limit after the #368 split stopped at the global 500-line threshold instead — and recall() itself was a single 318-line, 15-parameter orchestration function, far over the 40-line method cap. Continues the "two documented seams" from #368 (pg_recall_weights.py, pg_recall_assembly.py) with two more, following the same facade re-export pattern (mirrors pg_store.py's mixin-over-typed-host split and context_assembly/condensers.py's facade): - pg_recall_signals.py (82 l.) — the store-duck-typed mood/goal/Titans signal readers (_get_user_mood, _get_active_goal, _get_titans). - pg_recall_context.py (130 l.) — RecallContext (Introduce Parameter Object, coding-standards.md §4.4: bundles the 17 invariants of one recall() call so every stage takes exactly (candidates, ctx) instead of 8-13 positional params) plus fetch_and_triage/_wrrf_fetch (steps 1-4·C2). - pg_recall_stages.py (247 l.) — the post-WRRF recollection/rerank/ typed-pool/final stages, plus run_recall_pipeline(ctx) — the pipeline driver, kept out of pg_recall.py so recall() stays a stable, thin public-API wrapper regardless of how many stages the pipeline grows. - pg_recall.py (100 l.) — recall() (39 lines) builds RecallContext and forwards to run_recall_pipeline; facade re-exports every name existing callers/tests reach as pg_recall.<name> (_get_active_goal, _get_user_mood, _chronological_rerank, RecallContext, compute_pg_weights, assemble_context) so no caller or test moved. Public API unchanged: recall()'s signature, defaults, and return contract are identical. Every value moved unchanged; no constant retuned. Also fixed two ruff RET504 (unnecessary assignment before return) findings the extraction surfaced in the moved stage functions (boy-scout, same commit). Before: pg_recall.py 494 lines (1 file over cap), recall() 318 lines (1 method over cap). After: pg_recall.py 100, pg_recall_context.py 130, pg_recall_stages.py 247, pg_recall_signals.py 82 — all ≤300. Every method ≤40 lines (max: recall() 39, apply_recollection_pipeline 36). Tests: uv run --no-sync pytest -q -p no:randomly — 7417 passed, 123 subtests passed, 0 failed (406s), identical count to pre-refactor, 0 modified. ruff check/format --check green. pyright mcp_server/ — 0 errors, 0 warnings, 0 informations. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01263uv1QqR8TVzw2jXYUrXn
|
ZETETIC-REVIEW: APPROVE Reviewed from a fresh scratch clone ( Move 0 — ledger/seen-defect check. Pure code-motion refactor, no branches/error-arms to reconcile against a ledger. No "unrelated/pre-existing/out of scope" rationalization in the report; the RET504 fixes are proactive boy-scout, not a dismissal. Passes. Stakes: Medium. Core recall pipeline, single author session, no schema/API/concurrency change, but load-bearing (imported by the production handler). Full Moves 1-4 applied. 1. "Aucun test modifié" — force ou angle mort?Both, precisely characterized. It's a real strength for the wiring (facade re-exports are exactly what every existing test imports through — 2.
|
Summary
pg_recall.py stood at 494 lines against the repo's local 300-line file cap (CLAUDE.md/CONTRIBUTING.md § Code Style, a tightening of coding-standards.md §4.1) — the prior #368 split had targeted the global 500-line limit instead and stopped short.
recall()itself was a single 318-line, 15-parameter orchestration function, far over the 40-line method cap (§4.2).Continues the two documented seams from #368 (
pg_recall_weights.py,pg_recall_assembly.py) with two more, following the facade re-export pattern already established there (and matchingpg_store.py's mixin-over-typed-host split,context_assembly/condensers.py's facade):pg_recall_signals.py(82 l.) — store-duck-typed mood/goal/Titans signal readers.pg_recall_context.py(130 l.) —RecallContext(Introduce Parameter Object, §4.4) bundling the 17 invariants of onerecall()call, plusfetch_and_triage/_wrrf_fetch(steps 1-4·C2).pg_recall_stages.py(247 l.) — the post-WRRF recollection/rerank/typed-pool/final stages plusrun_recall_pipeline(ctx), the pipeline driver.pg_recall.py(100 l.) —recall()(39 lines) is now a thin public-API wrapper; facade re-exports every name existing callers/tests reach aspg_recall.<name>.Public API unchanged —
recall()'s signature, defaults, and return contract are identical, no caller or test moved. Every value moved unchanged; no constant retuned. Also fixed two ruff RET504 findings the extraction surfaced (boy-scout, same commit).Measured:
recall()39,apply_recollection_pipeline36).Test plan
uv run --no-sync pytest -q -p no:randomly— 7417 passed, 123 subtests passed, 0 failed (406s); identical count to pre-refactor, 0 tests modified.ruff check .— all checks passed.ruff format --check .— all files already formatted..venv/bin/python -m pyright mcp_server/(uv sync'd fromuv.lockper CONTRIBUTING.md's pyright-gate recipe) — 0 errors, 0 warnings, 0 informations.Co-Authored-By: Claude Opus 5 noreply@anthropic.com