lenscheck-contract · inside-out

Your backend can't lie about what it does

The reviewer reads your PR from the outside. lenscheck-contract watches the running app from the inside — so the two together catch what neither can alone.

How it works

Three levels — start at zero code

Static analysis can't see routers, loops, or mixins — but Django already resolved all of it at startup. So lenscheck-contract asks the running app instead of parsing files.

1 · Zero code

lenscheck-contract export

Reads Django's real router + model registry → contract.json. Coverage reported, not hidden.

2 · Declare

a decorator, done

Mark the routes + effects that matter — a decorator that looks like every Django one.

3 · Enforce

the runtime guard

One hook at the socket layer: an undeclared call fails loudly. The bad code doesn't ship.

The payoff

3 bad things in. 0 shipped.

A PR that "looks harmless" — caught on two layers: structural (the CI diff) and runtime (the guard).

lenscheck-contract catching three bad things across CI and runtime
  • Layer 2 · CI diff — auth weakened (user → public) and a model field droppedCI blocked before merge.
  • Layer 3 · runtime guard — an undeclared exfiltration call blocked before it ever left the process.
  • Structural mistakes → this. Logic mistakes → your tests. You need both.
The bridge

Runtime truth feeds the reviewer

On its own the reviewer guesses your invariants from git history. lenscheck-contract hands it the truth instead: your app's declared destinations become an enforced allowlist, so a brand-new domain sneaking into a PR is a 🔴 critical alert — grounded in fact, not a hunch.

◭ the bridge — runtime truth feeds the reviewer
$ lenscheck-contract invariants -o invariants.json        # the app's real declared egress + rules
$ lenscheck review <repo> --pr 128 --invariants invariants.json   # the reviewer stops guessing

See the full bridge docs →

Make your backend keep its promises

Zero-code export, one decorator to declare, one hook to enforce. It ships as a normal Python dependency.