1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//! `modularity-violations` analysis — file pairs that co-change
//! (Fisher-significant) yet have NO structural import edge between
//! them.
//!
//! This is the "implicit cross-module dependency" of Kazman & Cai's
//! DV8 hotspot patterns (Mo, Cai, Kazman, Xiao 2015 *Hotspot
//! Patterns*): two files that change together but don't import each
//! other are coupled through something invisible — a shared global, a
//! leaky abstraction, a contract honoured through a third party.
//! Empirically these pairs are more bug- and change-prone than
//! structurally-coupled ones.
//!
//! ## Fusion — the two graphs `CodeLore` already builds
//!
//! - **Temporal:** [`coupling::run_coupling`](crate::analyses::coupling::run_coupling)
//! Fisher-significant co-change pairs.
//! - **Structural:** the import graph
//! ([`import_graph`](crate::analyses::import_graph)) with transitive
//! reachability.
//!
//! A modularity violation is a co-change pair with **no directed
//! dependency path** between the two files in either direction — neither
//! (transitively) imports the other. That is the "co-change ∧
//! ¬structurally-connected" cell of the structure×history matrix that
//! neither an import-only graph (it has no history) nor a history-only
//! tool (it has no structure) can populate.
//!
//! ## Scope & limits
//!
//! - **Transitive.** A pair coupled through an import chain
//! (`a → b → c`, with `a` and `c` co-changing) is *not* a violation —
//! `a` does depend on `c`, just not directly. Only pairs with no path
//! between them are flagged. Files with no resolved imports aren't
//! graph nodes, so any co-change with them is (correctly) a violation.
//! - **Resolver language coverage.** Connectivity relies on the resolved
//! `imports.target_path`, populated for Rust + Python + JS/TS.
//! Languages whose resolver leaves `target_path` NULL (e.g. Java) make
//! real import edges look absent, so such repos over-report. Same
//! caveat [`god_classes`](crate::analyses::god_classes) documents for
//! fan-in.
use crateFactsDb;
use crate::;
/// A single modularity violation: a Fisher-significant co-change pair
/// with no structural import edge. Carries the co-change evidence so
/// callers can rank and explain the finding.
/// Run the `modularity-violations` analysis. Returns the
/// Fisher-significant co-change pairs that have no structural import
/// edge, ranked by coupling degree (highest first — inherited from
/// `run_coupling`'s ordering).
///
/// # Errors
///
/// Returns [`crate::CodeLoreError::Analysis`] on `DuckDB` query errors
/// (propagated from the inner coupling run or the imports scan).