fix(cli): --top N universally truncates all list-valued keys — closes #36#85
Merged
Conversation
_apply_top_n only truncated keys listed in the hardcoded _LIST_KEYS allowlist (28 names). New commands returning lists under non-standard keys (e.g., 'entities', 'widgets') silently ignored --top N, violating the 'Limit list results to top N items' contract from SKILL-QUICK.md and risking token overflow for MCP clients. Fix: Option A (auto-discover) — replace the allowlist iteration with a runtime scan of ALL top-level keys. Every list-valued key is truncated, except those in _NO_TOP_KEYS (structural/metadata keys like 'available_commands'). Also scans dict-valued keys for category-keyed lists, replacing the separate _NESTED_LIST_KEYS loop. This makes --top N a universal contract: any command, present or future, that returns a list under any key name is automatically truncated. No registration needed. Changes: - _apply_top_n: replaced _LIST_KEYS + _NESTED_LIST_KEYS loops with single auto-discover pass over all result.keys() - Removed _NESTED_LIST_KEYS (dead code — merged into auto-discover) - Added _NO_TOP_KEYS exempt set for structural/metadata keys - Kept _LIST_KEYS for _apply_lite (different purpose: priority-ordered primary result list lookup, not truncation) - coverage_map special case retained (dict-of-dicts, not dict-of-lists) Tests: 8 new tests in TestTopNUniversalTruncation covering: - Non-standard key truncation (the issue #36 repro) - Multiple non-standard keys truncated simultaneously - _NO_TOP_KEYS exempt keys NOT truncated - Standard keys still truncated (backward compat) - --top 0 unlimited for non-standard keys - Nested dict non-standard key truncation - Underscore-prefixed keys skipped - Exact repro from issue #36 Verified: 94/94 pass in test_cli.py + test_codelens.py. Full suite: 0 new failures (37 pre-existing failures unchanged — all graph/architecture/pollution issues unrelated to --top). Closes #36.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
# Conflicts: # tests/test_cli.py
|
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.



Summary
Fixes issue #36:
--top Nwas only truncating keys listed in a hardcoded allowlist (_LIST_KEYS, 28 names). Any new command returning a list under a non-standard key (e.g.,entities,widgets) would silently ignore--top N, violating the "Limit list results to top N items" contract fromSKILL-QUICK.mdand risking token overflow for MCP clients.Option chosen: A (auto-discover)
Why Option A over Option B:
The issue states: "--top N harus benar-benar truncate semua list output dari command manapun (yang ada sekarang maupun yang ditambah di masa depan) — tidak boleh ada command yang diam-diam lolos dari kontrak ini." This requires a runtime guarantee, not just a CI-time check. Option B (meta-test) only catches the gap at CI time — if a contributor skips the test or the test is broken, the bug still ships to production. Option A fixes the bug at runtime: every list-valued key is automatically truncated, regardless of its name.
Option A is also simpler (KISS, no dead code): a single auto-discover pass replaces both the
_LIST_KEYSloop and the_NESTED_LIST_KEYSloop. No registration needed for new commands. No_EXEMPT_KEYSmeta-test infrastructure. No CONTRIBUTING.md note about registering keys.What changed
scripts/codelens.py_apply_top_nrewritten — replaced two hardcoded allowlist loops (_LIST_KEYS+_NESTED_LIST_KEYS) with a single auto-discover pass:top_n_NESTED_LIST_KEYS)_NO_TOP_KEYS(structural/metadata keys)_(internal keys like_truncated_categories)_NESTED_LIST_KEYSremoved — dead code after the auto-discover merge. Its logic (scanningresults{category:[]},issues{type:[]},cycles{type:[]}) is now handled by the unified dict-scan in the auto-discover loop._NO_TOP_KEYSadded — explicit opt-out set for keys that should never be truncated:available_commands— help/list-commands metadataengines— analyze engine list (structural)supported_languages— setup infocategories— category names (metadata)tags— tag names (metadata)_LIST_KEYSkept — still used by_apply_lite(different purpose: priority-ordered primary result list lookup for lite mode, not truncation). Added a comment clarifying it's no longer used by_apply_top_n.coverage_mapspecial case retained — it's a dict-of-dicts ({file: {fn: {...}}}), not a dict-of-lists, so the auto-discover's dict-scan doesn't catch it. Kept as an explicit special case.tests/test_cli.pyNew test class
TestTopNUniversalTruncationwith 8 tests:test_non_standard_key_gets_truncated— the core issue [BUG-08] --top truncation only fires on hardcoded _LIST_KEYS — contract violation for new commands #36 reprotest_multiple_non_standard_keys_truncated— multiple non-standard keys truncated simultaneouslytest_no_top_keys_exempt—_NO_TOP_KEYSkeys NOT truncatedtest_standard_keys_still_truncated— backward compat for existing keystest_top_zero_means_no_truncation_for_non_standard_key—--top 0unlimited works for non-standard keystest_nested_dict_non_standard_key_truncated— non-standard dict-of-lists truncatedtest_underscore_prefixed_keys_skipped— internal_-prefixedkeys not processedtest_repro_from_issue— exact repro from issue [BUG-08] --top truncation only fires on hardcoded _LIST_KEYS — contract violation for new commands #36 (1000-itementitieslist → truncated to 5)Files changed
scripts/codelens.py_apply_top_nauto-discover rewrite,_NESTED_LIST_KEYSremoved,_NO_TOP_KEYSaddedtests/test_cli.pyTestTopNUniversalTruncationVerification
Issue #36 repro (manual)
Before fix:
len(out["entities"]) == 1000(silent--topbypass).After fix:
len(out["entities"]) == 5✅pytest tests/test_cli.py -vAll 26 tests pass (18 existing + 8 new).
pytest tests/test_codelens.py -v(existing _apply_top_n tests — backward compat)All 68 existing
_apply_top_n/_apply_lite/_sort_itemstests pass — no backward compatibility regression.Full suite:
pytest tests/ -v --ignore=tests/test_integration.py0 new failures introduced. All 37 failures are pre-existing on
main(confirmed bygit stash && pytest && git stash pop→ identical 37 failures). The pre-existing failures are all intest_graph_model.py,test_graph_incremental.py,test_architecture.py,test_compact_format.py,test_hybrid_type_resolver.py, andtest_vuln_staleness.py— they're related to graph database tables, test pollution (issue #83), and a stale vulnerability database (486 days old), not to--top Ntruncation.Reference
SKILL-QUICK.md--top Ncontract: "Limit list results to top N items (sorts by relevance: severity/complexity). Smart default: 20. Override:--top 0unlimited"Found but not fixed (out of scope)
Per scope-discipline skill, documenting for BOS:
tests/test_architecture.py::test_auto_scans_on_fresh_workspaceand 36 other pre-existing failures — these are graph model / architecture / test pollution issues (issue [BUG-P2] test_auto_scans_on_fresh_workspace fails intermittently — clean_app fixture .codelens not gitignored #83 territory), not related to--top Ntruncation. Fixing them is out of scope for this PR.