Tracking issue for the approved design "Vendored, typed_ast-free Scalpel as the default L4 oracle" (2026-07-22). Implemented on feat/vendor-scalpel-default-oracle.
Why
python-scalpel is the primary L4 may-alias oracle but hard-depends on typed_ast, abandoned at 1.5.5 with no wheel for Python 3.12+ and no source build on modern compilers. So on 3.12/3.13/3.14 the [scalpel] extra cannot install and L4 silently degrades to the coarser TypeBasedAliasOracle. Scalpel should be the shipping default everywhere.
Design (approved)
- Vendor the exact 9-module closure the oracle loads —
scalpel/__init__, SSA/{__init__,const}, cfg/{__init__,builder,model}, core/{__init__,func_call_visitor,vars_visitor} — verbatim from python-scalpel 1.0b0 (Apache-2.0, LICENSE copied, NOTICE entry added) as codeanalyzer/dataflow/scalpel/. typeinfer (the sole typed_ast importer) is deliberately excluded; verified the slice imports and computes SSA without typed_ast.
- One patch only:
cfg/model.py's module-load import graphviz becomes a lazy import inside the unused build_visual() — drops graphviz as a runtime dep. All analysis code paths byte-identical to upstream.
- Dependencies: add
astor>=0.8.1,<0.9 (runtime dep of SSA/const.py); remove the [project.optional-dependencies].scalpel extra; requires-python unchanged (>=3.9).
- Oracle rewiring:
ScalpelAliasOracle.from_function imports the vendored path; make_alias_oracle's ImportError branch is dead and removed. The per-callable build-failure and per-query unresolved-path fallbacks to TypeBasedAliasOracle stay — the total, never-raises may_alias contract is preserved; the type-based oracle is now a runtime safety net only.
- Behavior change (intended): on 3.12+ (and anywhere the extra was absent) L4's
prov:["points-to"] DDG edges become scalpel-precise instead of the type-based over-approximation. prov:["ssa"] is untouched, so the L3 ⊆ L4 monotonicity invariant holds. No schema change; no prov vocabulary change.
- Tests: import-hygiene (no
typeinfer/typed_ast/graphviz in sys.modules after oracle build), a typed_ast-free property gate, vendored-fidelity vs pip scalpel (skipif ≥3.12), the existing L4/SDG/defuse suites now exercising the scalpel path by default, and an L4 determinism run.
- Rollback: single revert — delete the vendored package, restore the extra + ImportError branch, drop
astor. No schema/id changes to unwind.
Out of scope: replacing astor.to_source with ast.unparse; a scalpel-installed CI lane; vendoring typeinfer.
Ships in 1.1.0 (minor: default L4 alias-oracle behavior change on 3.12+, [scalpel] extra removed).
Tracking issue for the approved design "Vendored, typed_ast-free Scalpel as the default L4 oracle" (2026-07-22). Implemented on
feat/vendor-scalpel-default-oracle.Why
python-scalpelis the primary L4 may-alias oracle but hard-depends ontyped_ast, abandoned at 1.5.5 with no wheel for Python 3.12+ and no source build on modern compilers. So on 3.12/3.13/3.14 the[scalpel]extra cannot install and L4 silently degrades to the coarserTypeBasedAliasOracle. Scalpel should be the shipping default everywhere.Design (approved)
scalpel/__init__,SSA/{__init__,const},cfg/{__init__,builder,model},core/{__init__,func_call_visitor,vars_visitor}— verbatim frompython-scalpel 1.0b0(Apache-2.0, LICENSE copied, NOTICE entry added) ascodeanalyzer/dataflow/scalpel/.typeinfer(the soletyped_astimporter) is deliberately excluded; verified the slice imports and computes SSA withouttyped_ast.cfg/model.py's module-loadimport graphvizbecomes a lazy import inside the unusedbuild_visual()— dropsgraphvizas a runtime dep. All analysis code paths byte-identical to upstream.astor>=0.8.1,<0.9(runtime dep ofSSA/const.py); remove the[project.optional-dependencies].scalpelextra;requires-pythonunchanged (>=3.9).ScalpelAliasOracle.from_functionimports the vendored path;make_alias_oracle'sImportErrorbranch is dead and removed. The per-callable build-failure and per-query unresolved-path fallbacks toTypeBasedAliasOraclestay — the total, never-raisesmay_aliascontract is preserved; the type-based oracle is now a runtime safety net only.prov:["points-to"]DDG edges become scalpel-precise instead of the type-based over-approximation.prov:["ssa"]is untouched, so theL3 ⊆ L4monotonicity invariant holds. No schema change; noprovvocabulary change.typeinfer/typed_ast/graphvizinsys.modulesafter oracle build), a typed_ast-free property gate, vendored-fidelity vs pip scalpel (skipif ≥3.12), the existing L4/SDG/defuse suites now exercising the scalpel path by default, and an L4 determinism run.astor. No schema/id changes to unwind.Out of scope: replacing
astor.to_sourcewithast.unparse; a scalpel-installed CI lane; vendoringtypeinfer.Ships in 1.1.0 (minor: default L4 alias-oracle behavior change on 3.12+,
[scalpel]extra removed).