API

Same-origin JSON under /api. Anything the page can do, a script can do. Unknown fields and unknown query parameters are rejected with 400 unknown_field, never ignored. Errors look like {"error":{"code","message"}}.

POST /api/scan

No account needed (5 scans an hour per visitor; signed in, 60 a month).

curl -s https://leanbump.grain64.com/api/scan \
  -H 'content-type: application/json' \
  -d '{"repo_url":"https://github.com/b-mehta/PrimeCert","ref":"f699a3e5"}'
repo_url
required. A public GitHub address; a /tree/<ref> URL works.
ref
optional. Branch, tag or commit. Default: the default branch.
from
optional, like v4.20.0. Default: detected from lean-toolchain and the Lake manifest.
to
optional. Default: newest release in the map.

Returns id, repo_url, ref, commit_sha, from, to, pin, line (the totals sentence), totals (occurrences, files, safe_renames, check_renames, removed_no_alias, will_break, warn_only), per_file, path (release by release), hits (each: file, line, col, token, old, new, label, certainty, confidence, module, since, breaks), files_scanned, truncated. Results of the same repository, ref and target are reused for 10 minutes.

GET /api/scans/:id

A saved result by id, the same body as the scan.

GET /api/rename

Query: name (required: an old name, or a whole unknown identifier line), from, to (optional releases). Returns query, matches (each: old, new, module, deprecated_since, deprecated_in, removed_in, last_present_in, type_changed, source, confidence, source_url, match) and coverage.

curl -s 'https://leanbump.grain64.com/api/rename?name=mul_right_eq_self'

GET /api/deprecations

Query: from (required), to, module_prefix, cursor, limit (1 to 200, default 50). Returns items and next_cursor.

GET /api/rename-map

Query: from (required), to. The whole slice as compact rows with columns: old, new, confidence, module, deprecated_since, first_idx, last_idx, removed.

GET /api/benchmark

The benchmark results behind /benchmark as JSON, no parameters.

POST /api/waitlist and POST /api/contact

Waitlist body: email, plan (Pro), both required. Contact body: message required; topic (feedback, correction, remove_project, bug, other), email, page, honeypot optional.

Account routes

POST /api/auth/request {email} sends a one-time link; POST /api/auth/verify {token} opens a session cookie; POST /api/auth/logout; GET /api/me; GET /api/projects; POST /api/projects {repo_url, name?}; POST /api/projects/:id/scan {from?, to?, ref?}; GET /api/projects/:id/scans; DELETE /api/projects/:id; GET /api/export; DELETE /api/account {confirm: your email}; POST /api/survey {answer}.

What a scan means

The scan reads names. certainty is exact (the full name), by-open (a short name resolved through an open) or possible (a bare word or short suffix also in the map; never counted in the totals). confidence below 0.8 means the replacement was taken from the deprecation message text: check it. breaks is true when the name is gone at the target and false when it is deprecated but still present.