Skip to content

Subject: Public API depends on an internal declaration

A public declaration's own contract secretly depends on a private/internal declaration -- reachable only through the L5 source-graph evidence tier, including how the detector reconciles a dependency that was merely renamed or moved rather than truly removed.

15 case(s). ← back to all subjects

The pattern

This is the L5 source-graph evidence tier's own subject: a public declaration's contract can depend on a private one through a channel no artifact-level diff (binary, debug info, or even headers alone) can see -- a private base class, a private field's type, an inline function's body referencing an internal constant, or an ordinary function's internal call graph. case160/187/188/189/190/191 each demonstrate one such channel; case192/193 show the same reachability question applied to suppression (a call-graph-reachable break can survive a suppression rule aimed at the wrong symbol) and to a negative case (an internal call that genuinely is not publicly reachable, so nothing should fire). case194-197 then test the detector's own precision under a compound edit: when the internal target is renamed, moved, or merely re-identified across a header change, does the reconciliation logic correctly recognize "same dependency, moved" rather than reporting a false removal-and-addition pair? case161/162/181 round out the family with the build-topology and audit-mode variants of the same underlying question -- did a dependency's source, not just its presence, change. The throughline for a maintainer: a public API's real dependency surface is not what its own header declares, it is everything reachable from that header -- and demonstrating that reachability, correctly and without false positives on an unrelated rename, is what this entire evidence tier exists to prove.

Cases

Case Title Verdict Category
case160_public_api_internal_dep_added Public API Gains an Internal Dependency 🟡 COMPATIBLE_WITH_RISK Risk
case161_target_dependency_added New Inter-Target Build/Link Dependency 🟡 COMPATIBLE_WITH_RISK Risk
case162_symbol_source_owner_changed Exported Symbol's Declaring File Moved 🟡 COMPATIBLE_WITH_RISK Risk
case181_xcheck_public_to_internal_dependency Public API Reaches an Internal Declaration 🟢 COMPATIBLE Quality (Compatible)
case187_public_struct_private_field_type Public Struct Field Retyped to an Internal Type 🔴 BREAKING Breaking
case188_public_class_private_base_class Public Class Gains a Private Base Class 🔴 BREAKING Breaking
case189_public_function_private_parameter_type Public Function Parameter Retyped to an Internal Type 🔴 BREAKING Breaking
case190_public_inline_function_references_internal_constant Public Inline Function References Internal Constant 🟡 COMPATIBLE_WITH_RISK Risk
case191_header_only_graph_field_type Public Struct Gains a Field of a Private Type (Header-Only Graph) 🔴 BREAKING Breaking
case192_call_graph_break_survives_suppression Call-Graph-Reachable Break Survives Suppression 🔴 BREAKING Breaking
case193_ordinary_exported_fn_call_not_reachable Ordinary Exported Function's Internal Call Is Not Public-Reachable 🔴 BREAKING Breaking
case194_header_graph_rename_reconciled Internal Dependency Target Renamed, Safely Reconciled 🟡 COMPATIBLE_WITH_RISK Risk
case195_header_graph_ambiguous_rename_not_reconciled Ambiguous Simultaneous Rename, Correctly Not Reconciled 🟡 COMPATIBLE_WITH_RISK Risk
case196_header_graph_move_reconciled Declaration Reconciled as Moved Across a Compound Edit 🟡 COMPATIBLE_WITH_RISK Risk
case197_header_graph_identity_reconciled Declaration Reconciled as Identity-Reconciled (Header Unchanged) 🟡 COMPATIBLE_WITH_RISK Risk