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
#![allow(unused)]
#![cfg_attr(coverage_nightly, coverage(off))]
use super::types::*;
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use std::fs;
use std::path::Path;
// =============================================================================
// CB-081: Dependency Count Detection (Enhanced v2.9)
// Per rust-project-score spec: Too many dependencies degrades build times,
// increases supply chain risk, and bloats binaries.
//
// Enhancements:
// - CB-081-A: Base dependency count scoring
// - CB-081-B: Duplicate crate detection
// - CB-081-C: Feature flag hygiene analysis
// - CB-081-D: Sovereign stack bonus
// - CB-081-E: Trend tracking
// =============================================================================
/// Sovereign stack crates (batuta ecosystem).
/// Includes deprecated names (renacer, trueno-*) and aprender monorepo names.
const SOVEREIGN_CRATES: &[&str] = &[
"aprender",
"aprender-compute",
"aprender-contracts",
"aprender-contracts-macros",
"aprender-profile",
"aprender-rag",
"aprender-simulate",
"trueno",
"trueno-graph",
"trueno-db",
"trueno-rag",
"trueno-viz",
"trueno-zram-core",
"pmcp",
"presentar-core",
"renacer",
"simular",
"certeza",
"bashrs",
"probar",
"ruchy",
"rmedia",
"whisper-apr",
];
/// Dependency count analysis result (enhanced)
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct DependencyCountReport {
pub direct_count: usize,
/// Total packages in Cargo.lock (includes dev-dep transitive)
pub transitive_count: usize,
/// Production-only transitive count (excludes dev-dep transitive), used for scoring
pub prod_transitive_count: Option<usize>,
pub score: u8, // 0-5 points based on rust-project-score thresholds
/// Crates with multiple versions in Cargo.lock
pub duplicate_crates: Vec<DuplicateCrate>,
/// Dependencies using default-features = false
pub feature_gated_count: usize,
pub feature_gated_pct: f64,
/// Sovereign stack crates used
pub sovereign_crates: Vec<String>,
pub sovereign_bonus: u8, // 0-3 bonus points
/// Delta from previous check (if available)
pub trend: Option<DependencyTrend>,
pub violations: Vec<CbPatternViolation>,
}
/// Duplicate crate info
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct DuplicateCrate {
pub name: String,
pub versions: Vec<String>,
}
/// Trend tracking data
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct DependencyTrend {
pub direct_delta: i32,
pub transitive_delta: i32,
pub previous_timestamp: String,
}
/// CB-081 Cache for O(1) dependency analysis (issue #148 fix)
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub(super) struct DependencyCache {
/// Cargo.lock file mtime (unix timestamp)
cargo_lock_mtime: u64,
/// Cached transitive count (all packages from Cargo.lock)
transitive_count: usize,
/// Cached production-only transitive count (via cargo tree --no-dev)
#[serde(default)]
prod_transitive_count: Option<usize>,
/// Cached duplicate crates
duplicate_crates: Vec<DuplicateCrate>,
}
// =============================================================================
// CB-130: Agent Context Adoption (PMAT-470)
// =============================================================================
/// CB-130 Agent Context Adoption report
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentContextReport {
/// Whether the RAG index exists
pub index_exists: bool,
/// Index age in hours (None if no index)
pub index_age_hours: Option<f64>,
/// Whether index is considered stale (>24h)
pub index_stale: bool,
/// Number of functions indexed
pub function_count: usize,
/// Whether CLAUDE.md mentions pmat_query_code
pub claude_md_configured: bool,
/// Required patterns missing from CLAUDE.md
pub missing_required_patterns: Vec<String>,
/// Forbidden patterns found in CLAUDE.md
pub forbidden_patterns_found: Vec<ForbiddenPatternMatch>,
}
/// A forbidden pattern match with location info
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ForbiddenPatternMatch {
/// The pattern that was found
pub pattern: String,
/// Line number where it was found
pub line: usize,
/// The actual line content (truncated)
pub context: String,
}
// --- Include implementation files ---
include!("dependency_checks_cache.rs");
include!("dependency_checks_analysis.rs");
include!("dependency_checks_agent_context.rs");