Skip to main content

Module architecture_metrics

Module architecture_metrics 

Expand description

architecture-metrics analysis — repo-level structural-health numbers over the resolved import graph, the kind you trend over time.

  • propagation_cost (MacCormack, Rusnak & Baldwin 2006) — the density of the visibility (transitive-closure) matrix: “a change to a random file can, on average, reach this fraction of the system”.
  • acd — Lakos’s Average Component Dependency: the mean number of files each file depends on directly or transitively (incl. self).
  • nccd — Normalised Cumulative Component Dependency: CCD divided by the CCD of a balanced binary tree of the same size. < 1 ≈ horizontal/flat, > 1 ≈ vertical/layered, > 2 ≈ likely cyclic (Lakos 1996, Large-Scale C++ Software Design).
  • dependency_cycles / largest_cycle — count of non-trivial SCCs and the size of the biggest tangle.
  • architecture_typehierarchical (acyclic), core-periphery (one dominant cyclic group), or multi-core (several comparable ones) — Baldwin, MacCormack & Rusnak 2014.

All derived in one pass from the shared import-graph kernel (SCC + reachability), so this adds no new query cost beyond building the graph. Accuracy follows the import resolver’s language coverage.

Four further rows disclose how much of the import surface the graph above actually covers — coverage transparency, not defect scores, so that a sparse graph can’t read as a clean one. The structural metrics only ever see the resolved edges (target_path IS NOT NULL); these query the full imports table so a poor resolution rate is visible:

  • import_resolution_rate — fraction of all import statements whose target resolved to an in-repo file. External and standard-library imports (numpy, java.util, std::fmt, …) legitimately point outside the repo and count as unresolved, so a repo with many third-party dependencies naturally scores lower — this is expected, not a resolver bug.
  • first_party_import_share — fraction of import statements that are first-party by intent: either already resolved, or a relative import (use crate::…, from .mod import …, ./foo) naming an in-repo path even when the resolver missed it — including a first-party glob (use crate::foo::*;, bare use super::*;), which imports.kind tags wildcard rather than relative (see the “Definition caveat” below) but which is still unambiguously in-repo by its crate::/self::/super:: prefix.
  • resolution_rate_first_party — of those first-party imports, the fraction that resolved. It drops external imports from the denominator, isolating resolver coverage from third-party-dependency density: a low value points at a genuine resolver gap rather than many external deps.
  • wildcard_import_share — fraction of all import statements that are glob imports (imports.kind = 'wildcard'), first-party or not. Purely informational (a glob names a module, not a symbol).

When an active calibration artifact (crate::calibration::load_active_artifact) carries a repo_metrics section (corpus pools populated by codelore calibrate), additional rows report where this repo’s propagation_cost and cycle_file_share sit against that corpus, each paired with a Wilson 95% confidence interval (…:ci_low / …:ci_high) that reflects the finite corpus pool’s sampling uncertainty — see run_architecture_metrics. Absent artifact or absent section ⇒ those rows are simply not emitted (the additivity contract this module’s tests pin).

Structs§

ArchitectureMetricRow
One repo-level architecture metric: (metric, value). The value is a string so the numeric metrics and the textual architecture_type label can share one row shape; numeric values are written as bare, parseable numbers (e.g. 0.0607) so downstream tooling can read them.

Functions§

run_architecture_metrics
Run the architecture-metrics analysis. Returns one row per repo-level metric, in a fixed presentation order, plus the import-resolution disclosure rows (see [import_resolution_rows]). Returns just those disclosure rows when the repo has import statements but none resolve into the graph (n == 0); empty only when the repo has no imports at all.