Skip to content

deleted-symbols-gate does not catch a name removed from __all__ while its def survives - #306

Merged
jaylfc merged 1 commit into
masterfrom
exec/tsk-b5gfwg
Aug 17, 2026
Merged

deleted-symbols-gate does not catch a name removed from __all__ while its def survives#306
jaylfc merged 1 commit into
masterfrom
exec/tsk-b5gfwg

Conversation

@jaylfc

@jaylfc jaylfc commented Aug 17, 2026

Copy link
Copy Markdown
Owner

CARD TITLE (intent, not commit subject): deleted-symbols-gate does not catch a name removed from all while its def survives

Autonomous build of board card tsk-b5gfwg.

The deleted-symbols-gate compared def/class definitions between base and
HEAD, but missed names silently dropped from all while their definitions
remained -- the shape a mechanical merge produces when one side of a
conflicted all block is taken wholesale.

Extend the gate to compare all membership via AST walk, not regex, so
continuation lines and column-0 indentation never matter. An entry in base
all absent from head all is a violation only when the corresponding
top-level def/class still exists at HEAD. A genuine deletion removes both
the definition and the all entry, and stays allowed: it is caught by
the existing definition-removal check.

Violation objects gain a kind field ("deleted" or "export-removed") so
the output distinguishes the two shapes. The Removes-Intentionally trailer
waiver covers both kinds uniformly.

Files:
changelog.d/tsk-b5gfwg-export-gate.md | 2 +
scripts/check_deleted_symbols.py | 130 +++++++++++++++--
tests/test_deleted_symbols.py | 264 ++++++++++++++++++++++++++++++++++
3 files changed, 386 insertions(+), 10 deletions(-)

The deleted-symbols-gate compared def/class definitions between base and
HEAD, but missed names silently dropped from __all__ while their definitions
remained -- the shape a mechanical merge produces when one side of a
conflicted __all__ block is taken wholesale.

Extend the gate to compare __all__ membership via AST walk, not regex, so
continuation lines and column-0 indentation never matter. An entry in base
__all__ absent from head __all__ is a violation only when the corresponding
top-level def/class still exists at HEAD. A genuine deletion removes both
the definition and the __all__ entry, and stays allowed: it is caught by
the existing definition-removal check.

Violation objects gain a kind field ("deleted" or "export-removed") so
the output distinguishes the two shapes. The Removes-Intentionally trailer
waiver covers both kinds uniformly.
@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing

@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@jaylfc, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 19 minutes

Limit details: You’ve used all 1 included review currently available under your plan.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 361fef3a-de5c-4a3b-8c37-7b939a293861

📥 Commits

Reviewing files that changed from the base of the PR and between b8c3d0e and c38ba5f.

📒 Files selected for processing (3)
  • changelog.d/tsk-b5gfwg-export-gate.md
  • scripts/check_deleted_symbols.py
  • tests/test_deleted_symbols.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gitar-bot

gitar-bot Bot commented Aug 17, 2026

Copy link
Copy Markdown

Important

You are using the Gitar free plan. Upgrade to unlock code review, CI analysis, auto-apply, custom automations, and more.

Gitar

return symbols


def _get_all_exports_at_ref(ref: str, repo_root: Path = REPO_ROOT) -> dict[str, str]:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Duplicated tar extraction logic from _get_symbols_at_ref

This function replicates the entire git archive → tar iteration → .py filter pipeline from _get_symbols_at_ref (lines 138-154). The two functions differ only in the dict variable name and the per-file callback. Extract the shared archive-iteration into a helper (e.g. _iter_python_files_at_ref) to avoid divergent bug fixes when the walk logic changes.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

except SyntaxError:
return exports

for node in tree.body:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: __all__ inside functions, classes, or conditionals is silently ignored

for node in tree.body: only visits module-level statements. __all__ assigned inside a function, class body, or if block will not be collected. Module-level __all__ is conventional, but documenting this scope limitation (or handling nested assignments) would prevent surprise false negatives.


Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Aug 17, 2026

Copy link
Copy Markdown

Code Review Summary

Status: 2 Issues Found | Recommendation: Address before merge

Overview

| Severity | Count |
|----------||
| CRITICAL | 0 |
| WARNING | 1 |
| SUGGESTION | 1 |

Issue Details (click to expand)

WARNING

File Line Issue
scripts/check_deleted_symbols.py 157 _get_all_exports_at_ref duplicates the entire tar-archive extraction pipeline from _get_symbols_at_ref; extract a shared helper to avoid divergent bug fixes

SUGGESTION

File Line Issue
scripts/check_deleted_symbols.py 123 for node in tree.body: only visits module-level statements, so __all__ assigned inside functions, classes, or conditionals is silently ignored
Files Reviewed (3 files)
  • scripts/check_deleted_symbols.py - 2 issues
  • tests/test_deleted_symbols.py
  • changelog.d/tsk-b5gfwg-export-gate.md

Fix these issues in Kilo Cloud


Reviewed by step-3.7-flash · Input: 95K · Output: 28.4K · Cached: 312.6K

@jaylfc

jaylfc commented Aug 17, 2026

Copy link
Copy Markdown
Owner Author

APPROVED. Every acceptance item on tsk-b5gfwg verified independently, including the live replay.

Reviewed against card tsk-b5gfwg. Trial merge with current master b8c3d0e, full suite 1420 passed, 12 skipped, 0 failed. Conflict-marker check clean, and the gate run against its own trial merge is clean. Each probe below ran with a control in the same command.

The card's four acceptance items, each measured

1. The precise red, then green. Not just the collection error (the new tests cannot import _extract_all_exports off master's script), but the behavioural pair on real repo input. Dropping "ingest" from taosmd/api.py's __all__ while def ingest() stays in the file:

master's gate : deleted-symbols-guard: clean            exit 0
this PR's gate: DELETED-SYMBOLS FAIL: this PR removes 1 symbol(s) from __all__
                  - taosmd/api.py:ingest (added by ec83f67 ...)   exit 1

2. The false-positive control. A name removed from BOTH __all__ and the file reports the definition violation only, with no export violation attached:

DELETED-SYMBOLS FAIL: this PR deletes 1 symbol(s) ...
  - taosmd/api.py:ingest
(no export-removed block)

That clause is the one that makes the check usable, and it is right.

3. No-op stays green. The gate on the trial merge against master: clean, exit 0.

4. The live replay against ed1d215, and it names exactly the three. This is the one that matters, and it lands precisely:

DELETED-SYMBOLS FAIL: this PR removes 3 symbol(s) from __all__ while the definition still exists at HEAD:
  - taosmd/service.py:a2a_thread_messages
  - taosmd/service.py:a2a_threads
  - taosmd/service.py:fetch_by_ref

Same three the card filed, no more and no less. I also classified the full __all__ delta on that branch, 265 down to 261: the other two removals (get_human_principal_ids, set_human_principal_ids) are genuine deletions whose definitions are gone too, and they are correctly reported by the definition half rather than double-counted by the export half. Coverage on the known-bad input is complete.

Two details that are better than they had to be

find_removed_all_entries returns head_symbols[k], so the real def/class kind reaches _find_adding_commit instead of the literal "export". That is why blame attribution on the replay is correct rather than degrading to unknown. Easy to get wrong, and it was not.

The AST choice is not theoretical: all 18 __all__ assignments in taosmd/ are top-level list literals, so _extract_all_exports covers 100% of the shapes actually present. I checked for augmented assignment, __all__.extend(...), non-literal values and nested assignment, and there are none, so there is no parser-shaped hole behind this.

One limitation, and it is mine, not this PR's

The check is scoped to entries whose def/class lives in the same file, which is exactly what the card's fix section specifies. It therefore does not see a re-export dropped from a package __init__.py. Measured:

KnowledgeGraph removed from taosmd/__init__.py __all__, import line intact -> gate clean, exit 0

Repo-wide that is 109 of 265 export entries, including 72 of the 74 in taosmd/__init__.py, all 19 in loaders/__init__.py and both in claims/__init__.py.

This is not a defect in this PR. The card asked for the same-file rule and this delivers it, correctly and with the controls. I had intended to widen the card to cover re-exports and never landed the edit, so the scope gap is on the card, not on the lane. Filing it as a follow-up card with the measurement above rather than holding a PR that met its brief.

Merging.

@jaylfc
jaylfc merged commit c80f404 into master Aug 17, 2026
5 checks passed
jaylfc added a commit that referenced this pull request Aug 17, 2026
… never exercised their own rule (#311)

Replaces the all-or-nothing #212 revert with eight per-rule reverts, one per
validation rule, so a missing sub-rule can be seen rather than masked by the
other seven. That granularity paid: R1 and R5 were false negatives. The test
inputs used the string "not a list", which has len 10 and so tripped the
max-refs guard, and which iterates into characters and so tripped the
item-type guard, before the isinstance check was ever reached. Disabling the
is-a-list rule left both tests green. The inputs are now non-iterable (42),
and the same perturbation turns both red.

Relabels the report TARGETED/UNRELATED, reserving DECORATIVE for tautologies
(none found), which removes the contradiction where one test was REAL in one
table and DECORATIVE in another. Splits row 13 out: its status assertion is
duplicated at the service layer, so only its message assertion is
load-bearing. Keeps the test_capability_declarations_do_not_diverge
retraction prominent.

Reviewer's note on provenance: the PR body's file table and its reported
suite count of 1401 belong to a different tree. They credit this PR with
scripts/normalise_handle_gate.py, scripts/check_deleted_symbols.py,
tests/test_deleted_symbols.py, tests/test_normalise_handle_gate.py and a
changelog entry for card tsk-vcda2i, all of which are #306's and #308's
already-merged work. This change is two files, 308 insertions, and the suite
on the trial merge is 1435 passed / 12 skipped.

Card tsk-24ybw5. Review: #311 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant