Skip to content

Fix #818: Extraction hardening for python - #872

Merged
squid-protocol merged 1 commit into
mainfrom
feature/818-extraction-hardening-python
Jul 31, 2026
Merged

squid-protocol merged 1 commit into
mainfrom
feature/818-extraction-hardening-python

Conversation

@squid-protocol

Copy link
Copy Markdown
Owner

Summary

Part of the extraction-hardening epic (#813). Closes #818.

Hardens all four extraction gauntlets (func_start, args, class_start, _dependency_capture) for python per tests/extraction/how_to_harden_extraction.md. Unlike javascript/typescript/java/go, this issue had no pre-flagged known bug — a fresh sweep surfaced three real bugs, all sharing one root cause:

  • func_start/args/class_start all shared a flat [^\]]* PEP 695 (3.12+) generic-parameter step-over, truncating at the first ] and breaking any nested-bracket type bound, e.g. def Foo[T: Sequence[int]](x: T) -> T:. This is the square-bracket variant of the same "Rule 11" bug class already fixed for java's/typescript's angle-bracket generics. Widened to \[(?:[^\[\]]|\[[^\[\]]*\])*\].
  • class_start's version of the bug didn't fail the whole match (the class name is captured before the generic step-over) — it silently dropped the base-class capture instead, same failure shape as java's Extraction hardening: java #816 class_start bug.

Also confirmed a genuinely positive finding, not a bug: python's Mode C (_slice_by_indentation) already shields strings/comments via an index-aligned shield before matching func_start against the code — so the string-literal false positive confirmed at the regex level (same shape as the recurring gap already found in js/ts/java/go) is not a live bug in python's actual pipeline. Documented as the reference implementation the eventual Mode-B (_slice_by_braces) broadening follow-up should mirror.

Differential Scan

Ran python tests/tools/crucible_check.py: zero diff across the ~80-repo corpus. Confirmed this is expected, not a red flag — grep across the corpus's python files shows zero usage of def/class NAME[...] PEP 695 syntax anywhere yet (it's a very new, 3.12+-only feature). Per the epic's own recurring bug class 8 ("a zero diff can mean the corpus doesn't exercise the feature, not that the fix is wrong"), verification relied entirely on regex-level empirical checks (verify_candidates.py) plus ReDoS scaling sweeps, all confirmed linear. No golden master changes in this PR.

Test plan

  • pytest tests/extraction/languages/test_python.py (60 new tests) — run via bare pytest from an unrelated CWD to reproduce CI's invocation style
  • pytest tests/core_engine/ tests/extraction/ -q — 3464 passed, 1 known pre-existing tiktoken-environment failure, 1 xfailed
  • python tests/tools/audit_check.py — clean (only the pre-existing, already-tracked guidestar_lens.py mypy findings, unrelated to this change)
  • python tests/tools/crucible_check.py — PASS on both venvs (zero diff, as expected — see above)
  • Migrated python's cases out of the four monolithic dict files into tests/extraction/languages/test_python.py
  • Epic Epic: Harden the four extraction gauntlets (function/args/class/dependency) per language #813 and the methodology doc updated with the new findings (recurring bug classes 15-17)

🤖 Generated with Claude Code

Hardens all four extraction gauntlets for python. This was a fresh sweep
(no pre-flagged known finding, unlike javascript/typescript/java/go) and
surfaced three real bugs, all sharing one root cause:

- func_start/args/class_start all shared a flat `[^\]]*` PEP 695 (3.12+)
  generic-parameter step-over, truncating at the FIRST `]` and breaking
  any nested-bracket type bound, e.g.
  `def Foo[T: Sequence[int]](x: T) -> T:`. This is the square-bracket
  variant of the same Rule 11 bug class already fixed for java's/
  typescript's angle-bracket generics. Widened to
  `\[(?:[^\[\]]|\[[^\[\]]*\])*\]`.

- class_start's version of the bug didn't fail the whole match (the class
  name is captured before the generic step-over) -- it silently dropped
  the base-class capture instead, same failure shape as java's #816
  class_start bug.

crucible_check.py showed a ZERO diff -- confirmed expected, not a red
flag: PEP 695 has zero real-world adoption anywhere in the ~80-repo
corpus yet (grep confirms no python file uses `def/class NAME[...]`
syntax). Verification relied entirely on regex-level empirical checks
(tests/extraction/tools/verify_candidates.py) plus ReDoS scaling sweeps,
consistent with recurring bug class 8's guidance that a zero diff can
mean the corpus doesn't exercise a feature, not that the fix is wrong.

Also confirmed a genuinely positive finding, not a bug: python's Mode C
(_slice_by_indentation) already shields strings/comments via an
index-aligned shield BEFORE matching func_start against the code -- so
the string-literal false positive confirmed at the regex level (same
shape as the recurring gap already found in js/ts/java/go) is NOT a live
bug in python's actual pipeline. Documented as the reference
implementation the eventual Mode-B (_slice_by_braces) broadening
follow-up should mirror.

Migrates python's test cases out of the four monolithic dict files into
tests/extraction/languages/test_python.py, and updates the epic +
methodology doc with the new findings (recurring bug classes 15-17).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

🐦‍⬛ Muninn Security Scan

✅ No security issues found.

🐦‍⬛ Powered by Muninn · Skald Lab

@squid-protocol
squid-protocol merged commit 3becaab into main Jul 31, 2026
27 checks passed
@squid-protocol
squid-protocol deleted the feature/818-extraction-hardening-python branch July 31, 2026 02:20
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.

Extraction hardening: python

1 participant