Skip to content

pxnkit/changepilot

Repository files navigation

ChangePilot

ChangePilot is a version-aware migration workbench for Python projects. It finds API usage that crosses a dependency upgrade boundary, traces the affected local call graph, stages conservative edits, and rejects patches that change code outside the declared rewrite set.

The repository contains two working surfaces:

  • An interactive web workbench for exploring the migration flow
  • A Python AST engine and command line interface for repository analysis

ChangePilot is an early engineering prototype. It is useful for inspecting a focused upgrade and testing migration contracts. It is not a replacement for a project test suite or a general Python refactoring platform.

What it does

Given a source tree and a set of current and target dependency versions, ChangePilot performs four steps:

  1. It selects API changes whose version boundary is crossed by the upgrade
  2. It locates matching call sites with Python AST analysis
  3. It follows reverse local calls to estimate the review surface
  4. It applies only deterministic edits and verifies a closed patch contract

Rules that need context-sensitive restructuring stay in the review queue. For example, a method rename can be safe enough for an automatic edit while a call shape rewrite remains manual.

Try the workbench

npm ci
npm run dev

Open the local URL printed by the development server. The sample workspace includes Pydantic and NumPy migration findings, a line-level patch preview, and contract verification.

The browser workbench uses a lightweight source detector so it can run without a backend. The Python package is the reference implementation for AST-based analysis.

Use the Python engine

ChangePilot requires Python 3.11 or newer and has no runtime dependencies.

python -m venv .venv

# Linux and macOS
source .venv/bin/activate

# Windows PowerShell
.venv\Scripts\Activate.ps1

python -m pip install -e .

Scan the included example:

changepilot scan examples/release_service.py \
  --from pydantic=1.10.14 \
  --from numpy=1.26.4 \
  --to pydantic=2.7.4 \
  --to numpy=2.0.0

Expected output:

Scanned 1 files and 28 lines. Found 3 migration call sites.
examples/release_service.py:12:12 LOW BaseModel.parse_obj -> BaseModel.model_validate
examples/release_service.py:16:12 LOW BaseModel.dict -> BaseModel.model_dump
examples/release_service.py:20:37 LOW numpy.float_ -> numpy.float64

Preview the safe patch:

changepilot migrate examples/release_service.py \
  --from pydantic=1.10.14 \
  --from numpy=1.26.4 \
  --to pydantic=2.7.4 \
  --to numpy=2.0.0

Add --write only after reviewing the diff.

Architecture

flowchart LR
    A["Current and target versions"] --> B["Version path resolver"]
    C["Python source tree"] --> D["AST index"]
    B --> E["Applicable change rules"]
    D --> F["Call-site matcher"]
    E --> F
    F --> G["Reverse call impact graph"]
    G --> H["Safe patch set"]
    G --> I["Manual review queue"]
    H --> J["Closed patch contract"]
    J --> K["Verified diff"]
Loading

The core modules have narrow responsibilities:

Module Responsibility
catalog.py Stores API change records and selects rules for a version path
analyzer.py Builds AST indexes, matches call sites, and traces reverse callers
migrate.py Applies the subset of rules marked as deterministic
evaluation.py Verifies patch boundaries and entity state changes
benchmark.py Runs labeled positive and negative regression fixtures
cli.py Exposes scan, migrate, and benchmark commands

See Architecture for the data contracts and failure boundaries.

Rule catalog

The starter catalog contains seven rules across Pydantic, NumPy, pandas, and Flask.

Library Change Action
Pydantic BaseModel.dict to BaseModel.model_dump Automatic
Pydantic BaseModel.json to BaseModel.model_dump_json Automatic
Pydantic BaseModel.parse_obj to BaseModel.model_validate Automatic
NumPy numpy.float_ to numpy.float64 Automatic
NumPy numpy.complex_ to numpy.complex128 Automatic
pandas DataFrame.append to pandas.concat Manual review
Flask Remove the JSON helper app keyword Manual review

Each rule records a version boundary, match target, replacement, risk level, confidence, edit policy, and upstream documentation URL. A rule is active only when the requested upgrade crosses its boundary.

The catalog is intentionally small. Adding hundreds of weak rules would make the interface look complete while reducing trust in the patch set. See Rule authoring for the acceptance checklist.

Patch contract

Automatic edits are evaluated under a closed patch boundary.

A patch passes when:

  • The migrated source parses as Python
  • All automatically fixable findings are cleared
  • Every changed line maps to an automatic rule
  • Lines with manual findings remain unchanged

The state evaluator also supports added, deleted, and updated entity assertions. Any state change that is not explained by an assertion causes verification to fail.

This outcome-based check is useful for testing migration runners and agent workflows. It does not execute untrusted source code.

Evaluation

Run the regression benchmark:

changepilot benchmark --output results/baseline.json

The checked-in baseline covers 11 labeled fixtures:

  • Five exact automatic patch cases
  • Two manual review cases
  • Four negative or boundary cases

The current fixture result is:

Metric Result
Detection precision 1.0000
Detection recall 1.0000
Detection F1 1.0000
Exact patch rate 1.0000
Contract pass rate 1.0000

These values describe only the small repository fixture set. They are regression signals, not evidence of broad performance on arbitrary projects.

Test suite

# Python unit and contract tests
python -m unittest discover -s python/tests -v

# Python lint and formatting checks
python -m ruff check python/src python/tests examples
python -m ruff format --check python/src python/tests examples

# Web build and rendered output tests
npm test

# TypeScript and React lint
npm run lint

The Python suite currently contains 25 tests covering:

  • Version boundary selection
  • Import alias resolution
  • Typed Pydantic receiver detection
  • NumPy namespace changes
  • pandas review routing
  • Reverse caller tracing
  • Syntax error handling
  • Safe rewrite idempotence
  • Closed patch rejection
  • Entity state diff assertions
  • Benchmark metric generation

GitHub Actions runs the Python and web suites independently.

Repository layout

app/                         Interactive workbench
src/engine/                  Browser analysis model
python/src/changepilot/      Python AST engine and CLI
python/tests/                Unit and contract tests
examples/                    Small original migration example
results/baseline.json        Reproducible fixture benchmark output
docs/                        Architecture and rule authoring notes
.github/workflows/           Continuous integration

Design decisions

Deterministic before generative

The first release does not call an LLM. Every automatic edit must be explainable by a catalog rule and testable with an exact contract. A future model-backed planner can propose candidates, but it should not weaken the verification boundary.

Version paths are explicit

A deprecated symbol is not automatically relevant. The current version must be below the recorded change boundary and the target version must reach or cross it.

Confidence is not permission

Confidence helps prioritize findings. The auto_fix field controls mutation authority. A high-confidence match can still require manual review when the replacement changes call structure.

Analysis does not execute the target project

The scanner parses source and inspects syntax trees. It does not import or run the analyzed repository. This keeps scans deterministic and avoids triggering project side effects.

Known limitations

  • The catalog is small and manually reviewed
  • Cross-file type and data flow inference are not implemented
  • The reverse call graph covers direct local function names
  • Method receiver inference is deliberately conservative
  • The browser detector is less precise than the Python AST engine
  • Safe rewrites operate at line granularity
  • Python syntax validation does not prove runtime compatibility

Provenance and claims

This repository contains an independent implementation and original fixtures.

It does not include third-party papers, research datasets, benchmark traces, source archives, or copied project assets. The checked-in metrics are produced only from fixtures in this repository. The project does not claim reproduction or authorship of external results.

API migration facts are linked to the official upstream documentation embedded in each catalog rule. The rule catalog is engineering metadata, not a claim of ownership over the underlying libraries or their release notes.

Contributing

Read CONTRIBUTING.md before proposing a new rule. Every automatic rule needs a version boundary, a positive fixture, a negative fixture, an idempotence test, and an upstream documentation link.

Security

ChangePilot does not execute scanned source code. Report security issues through the process in SECURITY.md.

License

ChangePilot is available under the MIT License.

About

Version-aware Python API migration analysis, conservative codemods, and closed-world verification

Topics

Resources

Contributing

Security policy

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages