fix(optimize): rank findings in core instead of importing the CLI - #730
Conversation
|
| Filename | Overview |
|---|---|
| tokenjam/core/optimize/rank.py | Introduces the shared ranking implementation and canonical card-bearing finding order without an identified blocking regression. |
| tokenjam/core/optimize/init.py | Re-exports the new ranking API from core; the added import is acyclic and included by package-wide wheel configuration. |
| tokenjam/api/routes/optimize.py | Removes the API-to-CLI dependency and obtains finding ranking from the core layer while preserving persona filtering. |
| tokenjam/cli/cmd_optimize.py | Replaces duplicated ranking logic with a thin compatibility wrapper that retains CLI renderer-specific inputs. |
| tests/unit/test_optimize_rank.py | Covers ranking, unranked findings, requested subsets, unknown names, renderer drift, and the API layering constraint. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
Report[OptimizeReport] --> Rank[tokenjam.core.optimize.rank_findings]
Rank --> API[GET /optimize finding_rank]
Rank --> Wrapper[CLI compatibility wrapper]
Wrapper --> CLI[tj optimize renderer]
Reviews (2): Last reviewed commit: "Merge branch 'main' into fix/move-rank-f..." | Re-trigger Greptile
anilmurty
left a comment
There was a problem hiding this comment.
Approving — and welcome, @myukitty, this is a strong first contribution. CI is now green across all seven checks (I approved the workflow run; fork PRs from first-time contributors need that manually).
Verification
The premise checked out on fresh main — one offending import, exactly where #579 said:
tokenjam/api/routes/optimize.py:34: from tokenjam.cli.cmd_optimize import _rank_findings
After this PR, a full-package grep for module-level and function-local imports returns zero hits from core/ or api/ into cli/. All three of #579's "Done when" criteria are met.
Behaviour-preservation was checked rather than assumed: main's _rank_findings was run against both new paths over 30,000 randomized reports, plus an exhaustive sweep of insertion-order permutations at identical shares to exercise tie-breaking specifically — zero mismatches. The three-key sort tuple is intact, and CARD_FINDING_NAMES is byte-identical to _FINDING_RENDERERS's key order. tj optimize --since 30d against a real database still ranks biggest-first, and a persona-gated subset still emits its "Not run" line.
All 233 added lines account for: 109 test file + 100 rank.py + 10 re-exports + 11 CLI wrapper + 3 API import swap. Nothing in the diff is neither a move nor a test.
What you did well — specifically
You noticed the card-bearing name set is not the analyzer registry. Reaching for ANALYZER_REGISTRY or ANALYZER_ORDER is the obvious move when relocating ranking into core/ — it's in the same package and it looks canonical. It would have been wrong: budget-projection is registered but has no ranked card, and placement has a card but is deliberately unregistered (it's produced inside downsize). That's the single easiest way this refactor could have quietly broken tj optimize placement, and you walked past it and said so in the PR body.
You pinned the duplication you introduced, in the same PR. Having created a second declaration of the name ordering, you wrote the drift test binding it to _FINDING_RENDERERS — and bound _ALWAYS_FULL_FINDINGS by identity rather than equality, so a re-declared literal fails instead of passing on equal contents.
You preserved relearn's unranked rule and tested it. That's a subtle, hard-won behaviour that a refactor could very easily have dropped on the floor.
Scope discipline. You kept two CLI re-exports with an honest noqa comment rather than rewriting six unrelated test modules. That was the right call.
Nits — none blocking, all fine as follow-ups
CARD_FINDING_NAMESbeing a second declaration of the renderer key order is safe because your drift test catches desync — but the stronger shape is forcoreto own the names andcmd_optimizeto build its renderer table keyed off them, so drift becomes impossible rather than merely detected.known_names/always_fullare parameters that provably can only hold their defaults (your own drift test proves it). Dropping them would remove the injection seam and about 8 lines. Defensible as-is.test_api_optimize_route_does_not_import_cliguards one file by reading its source text. Two upgrades worth considering: resolve the path viainspect.getsourcefile(...)so it survives a non-editable install, and generalize it to walk every module undercore/andapi/. There's no repo-wide guard onmaintoday, so that would close the whole class rather than the one instance #579 found. Good fast-follow if you want another._reclaimable_share's original docstring explained whyNoneisn't0.0, with the concrete example (cache-recommend recommends a placement, not a token count) and the consequence (it would hide an analyzer's own empty-state message).rank.pycondenses that to "they are not de-minimis". That sentence is precisely what stops a future reader "simplifying" theNoneinto a0.0— worth carrying across.
One housekeeping note: I just merged #726, so this will need Update branch before it goes in.
|
Great first contribution @myukitty - thanks! |
GET /optimizeimported_rank_findingsfromtokenjam.cli.cmd_optimize, which inverts the core/cli/api layering rule.Ranking now lives in
tokenjam.core.optimize.rank. The API imports it from core. The CLI keeps thin wrappers so existing renderer tests stay put.CARD_FINDING_NAMESis the card-bearing set, not the full analyzer registry, and a drift test pins it to_FINDING_RENDERERS.Closes #579