Release doctor — semantic blast-radius (the pre-link check)
release = build, and this is the link step: it proves the constellation's cross-crate API references resolve before a version bump ships. Where the crate-levelblastanswers "who depends on the changed crate", semantic blast answers "which exact call sites touch the changed crate's API" — what actually breaks. PLAN EPIC 7. Lives insrc/release/semantic_blast.rs.
Design
A linker resolves each object's undefined symbols against the exports of the others and refuses to emit if any is unresolved/incompatible. The release doctor does the same over crates, using the warehouse SCIP call-graph:
- Target crate
C(dirty / to-be-bumped) + the set of its changed/removed symbols (its exported API delta). RepoGraph.blast_radiuson the reverse graphGᵀgives the dependent repos — the only places a call site toCcan live.- Read the SCIP call-graph from the warehouse (
call_edges+symbol_factsIceberg tables, produced bydeep_scan) viaknowledge::query::load_preferred_merged(source-taggedresolved/scip, with a syn-call_edgesfallback when thescipfeature is off). KnowledgeView::callers_of(symbol)— the memoized inverted index overcall_edges— resolves each changed symbol to its exact call sites in the dependents (matches bothfacett::renderand barerender; intra-Cself-calls excluded).- Rank by API-surface delta: most-called symbol first,
RemovedbeforeChanged. Symbols no dependent calls becomeunused_changes(a provably safe delta) — the report distinguishes "might break" from "actually breaks".
Output: SemanticBlast { target_repo, target_crates, impacts: [SymbolImpact { symbol, change, call_sites: [CallSite{crate, caller, callee, kind, file, line}] }], unused_changes, total_call_sites, affected_crates }. Turns "facett → 7 repos might break" into "these 12 call sites in 3 crates call the 2 symbols that changed."
Guide
The plain nornir release doctor runs without a warehouse and leaves the semantic section empty (only crate-level blast). To get exact call sites, use the warehouse-aware entry point doctor::run_with_semantic_blast(repos, policy, wh, changed_by_repo) — it fills DoctorReport.semantic_blast and format_report renders a "Semantic blast radius (exact call sites touching the changed API)" section after the crate-level blast. Feed it the changed-symbol set per dirty repo (from the API diff); it needs a populated warehouse (nornir populate / deep_scan).
Idiot guide
- "Will bumping this crate break anything?" → semantic blast lists the exact files+lines that call the API you changed. Empty list = safe. Non-empty = those are your link errors; fix or coordinate them before releasing.
- "It says
unused_changes." → you changed/removed those symbols but nobody calls them — safe to ship. - Needs the warehouse — run
nornir populatefirst, or you only get the coarse "who depends on it" list.