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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
//! Types for tracking WHY packages need publishing.
//!
//! This module defines `PublishReason` which captures all possible reasons that
//! trigger a package to be republished. Understanding the reason is critical for:
//!
//! - **Diagnostics:** Users can see why their package is being published
//! - **Debugging:** Developers can trace cascade effects
//! - **Optimization:** Can prioritize different reason types
//!
//! # Reason Types
//!
//! 1. **LocalChanges** - Package has uncommitted or unpublished local modifications
//! - Detected via `publish_need()` (compares local vs published crate archives)
//! - Original detection method, existed before staleness fix
//!
//! 2. **VersionBump** - Package version was explicitly incremented
//! - User manually bumped version in Cargo.toml
//! - Rare: usually version bumps happen automatically during publish
//!
//! 3. **StaleDependencies** - Package has workspace dependencies with incompatible versions
//! - NEW in staleness fix
//! - Example: Package requires `former ~2.36.0` but workspace has `former 2.37.0`
//! - Contains list of all stale dependencies for detailed reporting
//!
//! 4. **CascadeEffect** - Package depends on other packages being published in current batch
//! - NEW in staleness fix
//! - Example: `willbe` depends on `wca`, `wca` is being published → `willbe` cascades
//! - Contains list of triggering packages
//!
//! # Design Decision: Why Separate `LocalChanges` and `VersionBump`?
//!
//! These could be merged into a single "Modified" variant. We keep them separate because:
//!
//! - **User Intent:** `LocalChanges` = unintentional changes, `VersionBump` = intentional
//! - **Workflow:** Different actions needed (commit vs publish)
//! - **Future:** May want different handling (e.g., warn on uncommitted changes)
//!
//! # Design Decision: Why Store Stale Dependencies List?
//!
//! The `StaleDependencies` variant contains `Vec<StaleDependency>` rather than just a count.
//! This enables:
//!
//! - **Detailed diagnostics:** Show exactly which dependencies are stale
//! - **User guidance:** "Update dependency X from ~2.36.0 to ~2.37.0"
//! - **Debugging:** Trace why staleness was detected
//!
//! **Cost:** Additional memory (~100 bytes per stale dependency)
//! **Benefit:** Vastly improved user experience and debuggability
//!
//! # Known Pitfalls
//!
//! ## Multiple Reasons Can Apply Simultaneously
//!
//! A package might have BOTH local changes AND stale dependencies. Current design
//! forces choosing one primary reason. This is intentional:
//!
//! - Simplifies data model (enum, not struct with flags)
//! - Publishing happens regardless of reason
//! - Primary reason is "most important" for user communication
//!
//! **Priority order (if multiple apply):**
//! 1. `LocalChanges` (most urgent - uncommitted changes)
//! 2. `StaleDependencies` (critical - version conflicts)
//! 3. `CascadeEffect` (automatic - triggered by others)
//! 4. `VersionBump` (rare - explicit user action)
//!
//! ## `CascadeEffect` Can Chain Deeply
//!
//! In a chain A→B→C→D, if D has local changes:
//! - D: `LocalChanges`
//! - C: `CascadeEffect` (triggered by D)
//! - B: `CascadeEffect` (triggered by C)
//! - A: `CascadeEffect` (triggered by B)
//!
//! The `triggered_by` field only shows immediate triggers, not full chain.
//! To see full chain, must trace recursively through publish plan.
//!
//! **Lesson:** For deep diagnostics, implement recursive reason tracing.
//
crate mod_interface!