Skip to content

Latest commit

 

History

History
121 lines (93 loc) · 4.93 KB

File metadata and controls

121 lines (93 loc) · 4.93 KB

API diff & breaking-change (codemap diff)

Compare two graph.json snapshots — a before and an after — and get what moved on the public API surface: symbols added / removed, and for symbols present in both, the signature-level changes, each classified breaking, warning, or info. "What broke between these two commits", at the API level. It complements codemap check: check guards internal structure, diff guards outward compatibility.

What counts as breaking

Signatures are parsed with the stdlib ast (each stored signature is read as def <sig>: …), so parameter analysis is exact, not string-diffing. Only public symbols participate — private churn is not an API change.

Scope: one provenance root — the package (core). On a repo-scoped graph (built with --consumer ./tests and friends) a public function in tests/ is not this package's API, and counting it as one turns --exit-code into a gate on test churn. R1-C52, reported by the dogfood target from their own release-gate run: 40 of 47 "added public symbols" were test functions. The report now names its scope under the verdict, and lists what it did not judge:

✅ No breaking changes. 7 added, 0 removed, 0 changed.

_Compared: public symbols of root `core` — the package. **Not judged:** 40 public
symbol(s) in `tests`, 3 in `examples` — a consumer root is not this package's API._

A single-package graph has one root by construction, so nothing there changes but the scope line. diff_api(old, new, root=None) compares every root when that is what you want.

Change Severity Why
public symbol removed breaking callers referencing it break
public → private breaking removed from the public API
kind changed (function ↔ class) breaking usage form changes
parameter removed breaking callers passing it break
required parameter added breaking existing calls omit it
parameter made required (default dropped) breaking calls relying on the default break
parameter made keyword-only (* inserted before it) breaking every positional call breaks
*args / **kwargs removed breaking calls using them break
parameter type changed warning may narrow — needs a human's eye
return type changed warning may narrow — needs a human's eye
newly @deprecated warning signals coming removal
parameter no longer keyword-only info widening — old calls still work
optional parameter added info backward-compatible
symbol added info new API

A signature ast cannot parse degrades to a conservative signature-changed warning — never a false "breaking".

Rebuild both snapshots with the same codemap. Parameter kind only entered the stored signature in R1-C34: before it, *args was rendered as a parameter named args with a default of (), **kw as kw={}, and / and the bare * were dropped entirely. Diffing a pre-R1-C34 snapshot against a newer one therefore reports signature churn that is the renderer changing, not the code. The two rows about keyword-only above cannot fire on an old snapshot at all — nothing in it parsed as keyword-only.

Usage

# render the delta between two snapshots
codemap diff old.json new.json

# release gate: exit 1 if any breaking change is found
codemap diff old.json new.json --exit-code

Build the two snapshots from two revisions and diff them:

git stash            # or check out the baseline in a worktree
codemap build ./yourpkg -o /tmp/old.json
git stash pop
codemap build ./yourpkg -o /tmp/new.json
codemap diff /tmp/old.json /tmp/new.json --exit-code

Example output:

# API diff — `pkg` → `pkg`

❌ **2 breaking change(s).** 1 added, 1 removed, 1 changed.

## Removed public symbols — breaking (1)
- `pkg.api.Old`

## Breaking signature changes (1)
- `pkg.api.run` — parameter `verbose` is now required

## Added public symbols (1)
- `pkg.api.New`

In review and over MCP

The diff folds into change-set review: hunk-based review sees only modified lines, so --base adds the symbols hunks miss — removed and added public symbols, and breaking signature changes:

git diff | codemap review - --graph new.json --base old.json

The same is a serve op and an MCP diff tool (base = path to the baseline graph.json; the session graph is the after), returning {ok, added, removed, changes:[{symbol, kind, severity, detail}], summary} — the structured "did this change break the API?" check an agent runs after an edit.

CI example

# fail the PR if it introduces a breaking API change vs the base branch
- run: codemap build ./yourpkg -o new.json
- run: git checkout "$BASE_SHA" && codemap build ./yourpkg -o old.json
- run: codemap diff old.json new.json --exit-code

Deterministic — same pair of graphs ⇒ same verdict.