Skip to content

P1: Complete Python dead-code reachability and entrypoint parity #295

Description

@tomdps

Parent

Tracking parent #291; epic #243. This is the validation consumer of graph-reference prerequisite #294.

Goal

Replace the current Python dead-code check's exported Function/Class with no incoming CALLS heuristic with entrypoint-aware file and symbol reachability comparable to the accepted TypeScript check, while keeping dynamic/ambiguous Python cases explicitly unsupported and non-blocking unless proven.

Dependencies

Current verified limitation on dev (6ed9e0e)

python.dead-code currently:

  • scopes exported graph symbols;
  • supports only Function/Class usage through incoming CALLS;
  • emits unsupported info for variables and unresolved exports;
  • does not discover Python entrypoints;
  • does not compute reachable files/symbols or unused files;
  • does not use imports, general references, inheritance, stubs, tests, or project build metadata as reachability evidence.

Required behavior

  1. Materialize the canonical Python source/project universe and query exact-state CONTAINS, IMPORTS_FROM, CALLS, REFERENCES, INHERITS, file, symbol, export, and test facts through public graph contracts only.
  2. Discover automatic roots per P0 — Resolve Python projects, interpreters, environments, and tools canonically #246 project from supported build metadata and layouts: declared [project.scripts], [project.gui-scripts], supported entry-point tables, package/module build declarations, package __main__.py, public package __init__.py roots, conventional/graph test roots, and .py/.pyi runtime/stub pairs. Resolve module[:object] targets uniquely; malformed/ambiguous/dynamic metadata is explicit unsupported evidence.
  3. Add Python-specific configured entrypoint overrides through validation-policy with repo-confined normalized paths and optional symbol targets. Explicit configuration replaces automatic roots consistently with the TypeScript contract; invalid, missing, duplicate, cross-project, or out-of-root roots fail config/evidence validation.
  4. Compute deterministic reachability: root files traverse directed imports; contained symbols traverse calls, general references, and inheritance; imported/re-exported symbol evidence and stub/runtime pairs must not create false unused findings. File and symbol alias normalization is shared/contract-bound, not regex guesswork duplicated from TypeScript.
  5. Emit separate stable diagnostics for unused reachable-policy files, unused callable/type/value exports, unsupported export metadata, missing/incomplete graph import/reference/type coverage, and dynamic evidence gaps. A path with missing target evidence is excluded from a false positive and reported as incomplete.
  6. Preserve Python export policy: explicit __all__ wins; otherwise leading underscore convention. Account for module hooks/dunder protocol names, decorators/framework registration only where positive graph/metadata/config evidence exists; unsupported dynamic registration remains labeled evidence absence.
  7. Match accepted TypeScript default severity and report semantics. Do not promote absence-of-evidence findings to error in this slice; any proven/introduced/evidence severity split must coordinate with measured policy issues chore(policy): shadow-run strict severity policy (cycles/dead-code as error) and publish the counts #285/policy(validation): fail hard on TS import cycles; split dead-code into proven/introduced/evidence tiers #288.
  8. Preserve exact overlays and introduced-mode behavior for created/deleted/renamed files, import changes, metadata/config changes, and entrypoint changes. Missing/failed/malformed exact graph or project context is non-pass, never an empty clean result.
  9. Update check outcomes/provenance, policy schema, manifests, capability projections, reports/metrics/ASP, fixtures, docs, package contents, and packed-install receipts. Do not mutate source/config/lock/environment/cache state.

Acceptance criteria

  • CLI scripts, GUI scripts, python -m packages, public libraries, regular/src/namespace packages, __init__ re-exports, .pyi peers, tests, nested/multi-project repos, and configured overrides produce expected roots and reachability.
  • Used/unused functions, async functions, classes, methods, values/constants, aliases, annotations, inheritance, decorators with positive registration evidence, import-only use, re-exports, and transitive imports are classified deterministically.
  • Unused files and exports have stable codes/fingerprints; automatic/configured roots, file reachability, symbol reachability, and supporting edges are observable in test/receipt evidence.
  • Star imports, dynamic imports, reflection, string registration, plugin discovery, monkey patching, metaclass generation, ambiguous modules/symbols, malformed metadata, and missing reference coverage never become false proven-dead findings.
  • Deleted/created/updated overlay source and pyproject.toml entrypoints use one exact after-state and differ correctly from baseline/introduced results.
  • Missing edge capability, partial graph, stale persistent graph, exact build/query failure, unsupported export metadata, unresolved entrypoint, and project ambiguity emit explicit non-clean outcomes.
  • TypeScript/Rust dead-code behavior is unchanged; no readiness/parity wording or strict severity promotion is added.

Observable outcomes

  • Clean success binds project context, entrypoint roots, graph identity/edge coverage, exact source universe, and reachability counts.
  • Every finding identifies whether it is an unused file, callable/type/value export, or incomplete/unsupported evidence.
  • Zero diagnostics without complete required coverage is not a pass.

Non-goals

  • LSP semantic reference parity
  • arbitrary framework/plugin inference
  • automatic deletion or fixes
  • strict severity policy changes
  • release/readiness claims

Verification

  • npm run build
  • focused validation-python dead-code roots/reachability/diagnostic/policy/overlay tests
  • graph contract/exact-state/project-context tests
  • reporting/metrics/ASP/capability and installed-bin tests
  • npm run lint
  • npm run pack:check
  • configured zeroshot cmdproof prove opcore-ci

Attach automatic/configured root fixtures, normalized graph/reachability evidence, unsupported dynamic cells, baseline/after-state/introduced examples, before/after cleanliness, and packed-install proof.

Execution rule

Implement only after #294 and #293 are accepted on current dev and a JIT review reconciles their actual contracts. Keep exactly one implementation run active. PR base is dev; require green checks, clean scoped diff, merged PR, closed child, #291/#243 checklist update, focused reproductions, and opcore-ci proof before closing #291 or starting #217. Do not claim Python readiness/parity, ASP authority, old-tool replacement, security/SAST, all-stack support, automatic fixes, or a blended score.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions