Skip to main content

Module coupling

Module coupling 

Expand description

Change-coupling analysis per spec §3.2.1 correctness invariants:

  1. max-changeset-size pre-filter (drops huge commits)
  2. Mirrored pair dedup via path_a < path_b
  3. Empty-changeset filter (implicit — commits with 0 files produce no pairs)
  4. min_revs filter (per-file)
  5. min_shared_revs filter (per-pair)
  6. min_coupling_pct filter (degree threshold)
  7. Fisher exact significance test (p < fisher_significance, default 0.05)

The Fisher test guards against spurious coupling from refactor sweeps that 2025 MSR research identified as the dominant noise source.

Research basis: see docs/research-foundations.md entry “coupling” (Gall, Hajek & Jazayeri, ICSM 1998 — original logical-coupling paper; Tornhill, Your Code as a Crime Scene, 2015 — productisation).

Structs§

CouplingAbsence
A historically-coupled partner missing from a change set. Produced by compute_coupling_absences for both the PR-scoped diff surface and the working-tree change-set engine.
CouplingMemoKey
Memo key for run_coupling. Carries EXACTLY the Options fields that build_coupling_sql, good_commits_cte, source_table, build_total_commits_sql, or the Rust-side Fisher pass branch on — and nothing else. Two Options that agree on every field here produce a byte-identical un-row-limited result, so they may share a memo entry.
CouplingRow
A single coupling pair produced by run_coupling.

Functions§

compute_coupling_absences
Flag every coupling pair where exactly one side is in the changed set: the touched file’s historically-coupled partner is absent, which is the signal a co-change was forgotten. Advisory — callers decide severity.
count_coupling_nodes
Count the number of nodes in the behavioral coupling graph universe. Returns the count of distinct files in the same file_revs candidate set used by run_coupling — i.e. files with revs >= opts.min_revs after the configured --time-bucket / --use-canonical-lineage rewrite. Honours opts.max_changeset_size via the same good_commits pre-filter so isolated nodes inside large commits don’t inflate the denominator of density.
density
Density of the behavioral coupling graph: 2·E / (V·(V−1)), in [0, 1].
partner_index
Build a bidirectional partner index from coupling rows: for each file, the set of files it is Fisher-significantly coupled with. The structure×history fusion analyses (unstable-interface, crossing) intersect this with the import graph, so the construction lives here next to CouplingRow rather than being re-derived in each.
run_coupling
Run change-coupling analysis over the ingested fact store.
run_coupling_scoped
Scoped variant of run_coupling: reads change history from changes_source instead of the opt-derived table. Used when a caller has already materialized a date-filtered view (changes_at_ts) and wants coupling restricted to that window. Does NOT memoize — the custom source is not covered by the standard CouplingMemoKey.