[P1][phase:b] Expand reachability roots: __all__, __init__ re-exports, and annotation references #116

Open
opened 2026-06-15 22:56:49 +02:00 by claude · 0 comments
Collaborator

Source: evidence-derived from the 2026-06-15 real-world precision audit (docs/dogfood/real-world-precision-2026-06-15.md).

Problem

unused-symbol (2%) and unused-module (0%) measured the lowest precision of all correctness rules. Beyond the non-package-tree cause (#package-root ticket), the residual false positives come from reachability roots the analyzer does not count:

  1. Public API — symbols re-exported from a package __init__.py / listed in __all__ are "unused" internally but are the library's entire purpose.
  2. Backwards-compat aliasesApp = Celery # XXX compat, TaskType = type # backwards compat.
  3. Annotation-only usageTypeVars and type aliases used only inside type annotations are flagged unused because annotation references are not counted.

Evidence (real repos)

  • flask/app.py: T_shell_context_processor, T_teardown, T_template_filter, T_template_globalTypeVars used only as decorator/annotation bounds → flagged unused-symbol
  • httpx/_client.py: T, U (TypeVars), EventHook (type alias) → flagged unused
  • celery/app/base.py: App = Celery # XXX compat → flagged unused
  • celery/app/task.py: TaskType = type # backwards compatibility → flagged unused

Proposed fix

Expand the reachability root set used by unused-symbol / unused-module:

  1. Treat names in a module's __all__ and names re-exported from any __init__.py as reachable (public API).
  2. Count references that appear inside type annotations (including string/forward-ref annotations) when computing symbol usage.
  3. Consider a conservative # compat / backwards-compat heuristic (or simply: aliases re-exported publicly are reachable).

Acceptance criteria

  • TypeVars used only in annotations are no longer flagged unused (flask, httpx examples clear).
  • Symbols in __all__ / re-exported from __init__.py are not flagged unused.
  • benchmarks/fp-cases/annotation-only-typevar/ and .../public-compat-alias/ fixtures added and pass.
  • Re-running the audit shows unused-symbol / unused-module precision rising from the 2% / 0% baseline.

Priority

P1. Highest-volume rules in the corpus (2,840 + 1,813 findings). After package-root detection lands, this is the next-largest FP reservoir.


Opened by claude (Opus 4.8) from the 2026-06-15 precision audit. Audit PR: #113.

**Source:** evidence-derived from the 2026-06-15 real-world precision audit (`docs/dogfood/real-world-precision-2026-06-15.md`). ## Problem `unused-symbol` (2%) and `unused-module` (0%) measured the lowest precision of all correctness rules. Beyond the non-package-tree cause (#package-root ticket), the residual false positives come from **reachability roots the analyzer does not count**: 1. **Public API** — symbols re-exported from a package `__init__.py` / listed in `__all__` are "unused" internally but are the library's entire purpose. 2. **Backwards-compat aliases** — `App = Celery # XXX compat`, `TaskType = type # backwards compat`. 3. **Annotation-only usage** — `TypeVar`s and type aliases used only inside type annotations are flagged unused because annotation references are not counted. ### Evidence (real repos) - `flask/app.py`: `T_shell_context_processor`, `T_teardown`, `T_template_filter`, `T_template_global` — `TypeVar`s used only as decorator/annotation bounds → flagged unused-symbol - `httpx/_client.py`: `T`, `U` (TypeVars), `EventHook` (type alias) → flagged unused - `celery/app/base.py`: `App = Celery # XXX compat` → flagged unused - `celery/app/task.py`: `TaskType = type # backwards compatibility` → flagged unused ## Proposed fix Expand the reachability root set used by `unused-symbol` / `unused-module`: 1. Treat names in a module's `__all__` and names re-exported from any `__init__.py` as reachable (public API). 2. Count references that appear inside **type annotations** (including string/forward-ref annotations) when computing symbol usage. 3. Consider a conservative `# compat` / backwards-compat heuristic (or simply: aliases re-exported publicly are reachable). ## Acceptance criteria - `TypeVar`s used only in annotations are no longer flagged unused (`flask`, `httpx` examples clear). - Symbols in `__all__` / re-exported from `__init__.py` are not flagged unused. - `benchmarks/fp-cases/annotation-only-typevar/` and `.../public-compat-alias/` fixtures added and pass. - Re-running the audit shows `unused-symbol` / `unused-module` precision rising from the 2% / 0% baseline. ## Priority **P1.** Highest-volume rules in the corpus (2,840 + 1,813 findings). After package-root detection lands, this is the next-largest FP reservoir. --- *Opened by `claude` (Opus 4.8) from the 2026-06-15 precision audit. Audit PR: #113.*
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
pdurlej/fallow-py#116
No description provided.