java-topology/defects/poetry/patch/poetry-diamond-recursion-broader-CLEAN.md
russell@unturf.com 9ef437a348 poetry-0001: show --tree packages_in_tree list O(N²) membership; UNDF-2026-000000575
ShowCommand._display_tree() uses a list for packages_in_tree, making every
`dep.name in current_tree` check O(N). For a project with 500 packages the
total membership-test cost is O(N²) ≈ 250,000 ops vs O(N) = 500 with a set.
Also fixes shared-state correctness bug: list is passed by reference causing
sibling branches to falsely report diamond dependencies as cycles.
Fix: set + per-branch set-union copy; 16-31x speedup measured.

CLEAN markers added for setuptools and celery (diamond recursion).
pip, django, poetry solver already CLEAN (prior or current scan).
2026-03-29 18:09:57 -04:00

1.4 KiB

Diamond Recursion Scan — CLEAN (broader scan beyond poetry-0001)

Scan date: 2026-03-29 Pattern: Recursive DAG traversal without visited set (CWE-407 diamond recursion, O(2^D))

Files examined

  • src/poetry/puzzle/solver.pydepth_first_search(), dfs_visit(), _aggregate_solved_packages()
  • src/poetry/puzzle/provider.pycomplete_package(), incompatibilities_for()
  • src/poetry/mixology/version_solver.py_resolve_conflict()
  • src/poetry/packages/locker.pylocked_packages(), _compute_lock_data()
  • src/poetry/console/commands/show.py_display_tree() (see poetry-0001)

Findings

puzzle/solver.py depth_first_search / dfs_visit(): Explicit visited: set[DFSNodeID] = set() guard. if node.id in visited: return at the top of dfs_visit. CLEAN.

mixology/version_solver.py: Uses the Pubgrub algorithm (backtracking SAT-style solver). No recursive graph walk — operates on incompatibility sets with memoized partial assignments. CLEAN.

packages/locker.py: Iterative dict construction from lock data. No recursive graph walk. CLEAN.

show.py _display_tree(): See poetry-0001. The shared-state bug prevents O(2^D) diamond blowup (accidental guard), but introduces false-positive cycle detection. The O(N) list membership is the primary CWE-407 finding.

Verdict: CLEAN for diamond recursion O(2^D) — one O(N²) list-membership defect (poetry-0001)