@lamentis/naome 1.3.14 → 1.3.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Cargo.lock +2 -2
- package/crates/naome-cli/Cargo.toml +1 -1
- package/crates/naome-cli/src/architecture_commands.rs +5 -4
- package/crates/naome-cli/src/quality_commands.rs +4 -4
- package/crates/naome-core/Cargo.toml +1 -1
- package/crates/naome-core/src/architecture/config/parser/sections.rs +1 -1
- package/crates/naome-core/src/architecture/config.rs +1 -1
- package/crates/naome-core/src/architecture/model.rs +19 -0
- package/crates/naome-core/src/architecture/output.rs +166 -22
- package/crates/naome-core/src/architecture/rules/budgets.rs +2 -1
- package/crates/naome-core/src/architecture/rules.rs +5 -2
- package/crates/naome-core/src/architecture.rs +4 -4
- package/crates/naome-core/src/intent/legacy.rs +1 -1
- package/crates/naome-core/src/intent/model.rs +27 -0
- package/crates/naome-core/src/intent/resolver.rs +3 -28
- package/crates/naome-core/src/intent/resolver_baseline.rs +1 -2
- package/crates/naome-core/src/intent/resolver_policy.rs +1 -2
- package/crates/naome-core/src/intent.rs +2 -1
- package/crates/naome-core/src/lib.rs +7 -7
- package/crates/naome-core/src/quality/adapter_ios.rs +3 -1
- package/crates/naome-core/src/quality/adapter_support.rs +32 -0
- package/crates/naome-core/src/quality/adapters.rs +8 -25
- package/crates/naome-core/src/quality/analysis_model.rs +33 -0
- package/crates/naome-core/src/quality/cache.rs +1 -1
- package/crates/naome-core/src/quality/checks/duplicate_blocks.rs +2 -1
- package/crates/naome-core/src/quality/checks/near_duplicates.rs +2 -1
- package/crates/naome-core/src/quality/mod.rs +1 -0
- package/crates/naome-core/src/quality/scanner/analysis.rs +1 -1
- package/crates/naome-core/src/quality/scanner.rs +1 -32
- package/crates/naome-core/src/quality/semantic/extract.rs +2 -1
- package/crates/naome-core/src/quality/structure/adapter_ios.rs +1 -1
- package/crates/naome-core/src/quality/structure/adapter_model.rs +23 -0
- package/crates/naome-core/src/quality/structure/adapters.rs +2 -23
- package/crates/naome-core/src/quality/structure/config.rs +2 -1
- package/crates/naome-core/src/quality/structure/defaults.rs +2 -2
- package/crates/naome-core/src/quality/structure/mod.rs +1 -0
- package/crates/naome-core/src/quality/structure/model.rs +6 -6
- package/crates/naome-core/src/repository_model.rs +6 -1
- package/crates/naome-core/src/route/builtin_checks.rs +1 -1
- package/crates/naome-core/src/route/builtin_require.rs +1 -1
- package/crates/naome-core/src/route/execution.rs +2 -34
- package/crates/naome-core/src/route/execution_baselines.rs +1 -1
- package/crates/naome-core/src/route/execution_model.rs +37 -0
- package/crates/naome-core/src/route/execution_support.rs +1 -1
- package/crates/naome-core/src/route/execution_tasks.rs +1 -1
- package/crates/naome-core/src/route/quality_gate.rs +0 -1
- package/crates/naome-core/src/route.rs +3 -1
- package/crates/naome-core/src/task_state/api.rs +5 -4
- package/crates/naome-core/src/task_state/commit_gate.rs +1 -1
- package/crates/naome-core/src/task_state/compact_proof.rs +2 -2
- package/crates/naome-core/src/task_state/completed_refresh.rs +0 -13
- package/crates/naome-core/src/task_state/completion.rs +13 -4
- package/crates/naome-core/src/task_state/mod.rs +1 -1
- package/crates/naome-core/src/task_state/progress.rs +1 -1
- package/crates/naome-core/src/task_state/proof.rs +1 -4
- package/crates/naome-core/src/task_state/proof_entry.rs +1 -1
- package/crates/naome-core/src/task_state/proof_model.rs +2 -18
- package/crates/naome-core/src/task_state/proof_sources.rs +2 -2
- package/crates/naome-core/src/task_state/proof_types.rs +17 -0
- package/crates/naome-core/src/task_state/shape.rs +1 -1
- package/crates/naome-core/src/task_state/task_diff_api.rs +1 -1
- package/crates/naome-core/src/verification_contract_policy.rs +2 -6
- package/crates/naome-core/src/workflow/agent/proof.rs +1 -1
- package/crates/naome-core/src/workflow/agent.rs +1 -1
- package/crates/naome-core/src/workflow/mod.rs +3 -1
- package/crates/naome-core/src/workflow/phase_inference.rs +1 -1
- package/crates/naome-core/src/workflow/phase_model.rs +22 -0
- package/crates/naome-core/src/workflow/phases.rs +1 -21
- package/crates/naome-core/tests/architecture_config.rs +67 -0
- package/native/darwin-arm64/naome +0 -0
- package/native/linux-x64/naome +0 -0
- package/package.json +1 -1
- package/crates/naome-core/src/task_state/reconcile.rs +0 -7
package/Cargo.lock
CHANGED
|
@@ -76,7 +76,7 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
|
|
76
76
|
|
|
77
77
|
[[package]]
|
|
78
78
|
name = "naome-cli"
|
|
79
|
-
version = "1.3.
|
|
79
|
+
version = "1.3.16"
|
|
80
80
|
dependencies = [
|
|
81
81
|
"naome-core",
|
|
82
82
|
"serde_json",
|
|
@@ -84,7 +84,7 @@ dependencies = [
|
|
|
84
84
|
|
|
85
85
|
[[package]]
|
|
86
86
|
name = "naome-core"
|
|
87
|
-
version = "1.3.
|
|
87
|
+
version = "1.3.16"
|
|
88
88
|
dependencies = [
|
|
89
89
|
"serde",
|
|
90
90
|
"serde_json",
|
|
@@ -2,9 +2,9 @@ use std::fs;
|
|
|
2
2
|
use std::path::{Path, PathBuf};
|
|
3
3
|
|
|
4
4
|
use naome_core::{
|
|
5
|
-
default_architecture_config_text, format_architecture_explain,
|
|
6
|
-
format_architecture_validation, scan_architecture,
|
|
7
|
-
ArchitectureScanOptions, ARCHITECTURE_RULE_IDS,
|
|
5
|
+
config_findings_for, default_architecture_config_text, format_architecture_explain,
|
|
6
|
+
format_architecture_scan, format_architecture_validation, scan_architecture,
|
|
7
|
+
validate_architecture, ArchitectureScanOptions, ARCHITECTURE_RULE_IDS,
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
use crate::cli_args::{has_flag, option_value};
|
|
@@ -53,7 +53,8 @@ fn run_arch_explain(root: &Path, args: &[String]) -> Result<(), Box<dyn std::err
|
|
|
53
53
|
"layers": scan.config.layers.keys().collect::<Vec<_>>(),
|
|
54
54
|
"contexts": scan.config.contexts.keys().collect::<Vec<_>>(),
|
|
55
55
|
"rules": ARCHITECTURE_RULE_IDS,
|
|
56
|
-
"extractors": ["path", "typescript", "javascript", "rust", "python", "go", "swift"]
|
|
56
|
+
"extractors": ["path", "typescript", "javascript", "rust", "python", "go", "swift"],
|
|
57
|
+
"configFindings": config_findings_for(&scan)
|
|
57
58
|
}))?
|
|
58
59
|
);
|
|
59
60
|
} else {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
use std::path::Path;
|
|
2
2
|
|
|
3
3
|
use naome_core::{
|
|
4
|
-
check_repository_quality, check_repository_quality_paths, check_semantic_legacy,
|
|
5
|
-
clear_quality_cache, explain_repository_structure,
|
|
6
|
-
plan_quality_cleanup, quality_cache_status,
|
|
7
|
-
QualityInitMode, QualityMode,
|
|
4
|
+
check_repository_quality, check_repository_quality_paths, check_semantic_legacy,
|
|
5
|
+
check_semantic_legacy_paths, clear_quality_cache, explain_repository_structure,
|
|
6
|
+
init_repository_quality_with_mode, plan_quality_cleanup, quality_cache_status,
|
|
7
|
+
route_quality_cleanup, semantic_route_for_finding, QualityInitMode, QualityMode,
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
use crate::cli_args::option_value;
|
|
@@ -5,7 +5,7 @@ use super::ConfigParser;
|
|
|
5
5
|
use crate::architecture::config::{
|
|
6
6
|
ContextConfig, ExternalDependencyPolicy, IgnoreRule, LayerConfig, RuleConfig,
|
|
7
7
|
};
|
|
8
|
-
use crate::architecture::
|
|
8
|
+
use crate::architecture::model::Severity;
|
|
9
9
|
|
|
10
10
|
pub(super) fn parse_layers(parser: &mut ConfigParser<'_>) -> Result<(), NaomeError> {
|
|
11
11
|
while let Some((_, line)) = parser.peek_line() {
|
|
@@ -38,6 +38,25 @@ pub struct SourceRange {
|
|
|
38
38
|
pub end_column: usize,
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
|
42
|
+
#[serde(rename_all = "snake_case")]
|
|
43
|
+
pub enum Severity {
|
|
44
|
+
Error,
|
|
45
|
+
Warning,
|
|
46
|
+
Info,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
impl Severity {
|
|
50
|
+
pub fn parse(value: &str) -> Option<Self> {
|
|
51
|
+
match value {
|
|
52
|
+
"error" => Some(Self::Error),
|
|
53
|
+
"warning" | "warn" => Some(Self::Warning),
|
|
54
|
+
"info" => Some(Self::Info),
|
|
55
|
+
_ => None,
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
41
60
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
42
61
|
pub struct ArchitectureMetadata {
|
|
43
62
|
pub path: Option<String>,
|
|
@@ -1,16 +1,8 @@
|
|
|
1
1
|
use serde::{Deserialize, Serialize};
|
|
2
2
|
|
|
3
|
-
use super::model::SourceRange;
|
|
3
|
+
use super::model::{Severity, SourceRange};
|
|
4
4
|
use super::scan::ArchitectureScanReport;
|
|
5
5
|
|
|
6
|
-
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
|
|
7
|
-
#[serde(rename_all = "snake_case")]
|
|
8
|
-
pub enum Severity {
|
|
9
|
-
Error,
|
|
10
|
-
Warning,
|
|
11
|
-
Info,
|
|
12
|
-
}
|
|
13
|
-
|
|
14
6
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
15
7
|
#[serde(rename_all = "camelCase")]
|
|
16
8
|
pub struct ViolationSummary {
|
|
@@ -42,6 +34,17 @@ pub struct ArchitectureAgentFeedback {
|
|
|
42
34
|
pub must_not_do: Vec<String>,
|
|
43
35
|
}
|
|
44
36
|
|
|
37
|
+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
|
38
|
+
#[serde(rename_all = "camelCase")]
|
|
39
|
+
pub struct ArchitectureConfigFinding {
|
|
40
|
+
pub id: String,
|
|
41
|
+
pub severity: String,
|
|
42
|
+
pub subject: String,
|
|
43
|
+
pub message: String,
|
|
44
|
+
pub suggestion: String,
|
|
45
|
+
pub agent_instruction: String,
|
|
46
|
+
}
|
|
47
|
+
|
|
45
48
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
46
49
|
#[serde(rename_all = "camelCase")]
|
|
47
50
|
pub struct ArchitectureValidation {
|
|
@@ -56,6 +59,7 @@ pub struct ArchitectureValidation {
|
|
|
56
59
|
pub changed_only_degraded_to_full_scan: bool,
|
|
57
60
|
pub changed_only_mode: String,
|
|
58
61
|
pub changed_only_degradation_reason: Option<String>,
|
|
62
|
+
pub config_findings: Vec<ArchitectureConfigFinding>,
|
|
59
63
|
pub violations: Vec<ArchitectureViolation>,
|
|
60
64
|
#[serde(rename = "agent_feedback")]
|
|
61
65
|
pub agent_feedback: Vec<ArchitectureAgentFeedback>,
|
|
@@ -74,17 +78,6 @@ pub const ARCHITECTURE_RULE_IDS: &[&str] = &[
|
|
|
74
78
|
"arch.external_dependency_policy",
|
|
75
79
|
];
|
|
76
80
|
|
|
77
|
-
impl Severity {
|
|
78
|
-
pub fn parse(value: &str) -> Option<Self> {
|
|
79
|
-
match value {
|
|
80
|
-
"error" => Some(Self::Error),
|
|
81
|
-
"warning" | "warn" => Some(Self::Warning),
|
|
82
|
-
"info" => Some(Self::Info),
|
|
83
|
-
_ => None,
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
81
|
pub fn architecture_agent_feedback(
|
|
89
82
|
violations: &[ArchitectureViolation],
|
|
90
83
|
) -> Vec<ArchitectureAgentFeedback> {
|
|
@@ -102,6 +95,131 @@ pub fn architecture_agent_feedback(
|
|
|
102
95
|
.collect()
|
|
103
96
|
}
|
|
104
97
|
|
|
98
|
+
pub fn config_findings_for(scan: &ArchitectureScanReport) -> Vec<ArchitectureConfigFinding> {
|
|
99
|
+
let mut findings = Vec::new();
|
|
100
|
+
findings.extend(broad_layer_findings(scan));
|
|
101
|
+
findings.extend(catch_all_context_findings(scan));
|
|
102
|
+
findings.sort_by(|left, right| {
|
|
103
|
+
(left.id.as_str(), left.subject.as_str()).cmp(&(right.id.as_str(), right.subject.as_str()))
|
|
104
|
+
});
|
|
105
|
+
findings.dedup_by(|left, right| left.id == right.id && left.subject == right.subject);
|
|
106
|
+
findings
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
fn broad_layer_findings(scan: &ArchitectureScanReport) -> Vec<ArchitectureConfigFinding> {
|
|
110
|
+
let mut findings = Vec::new();
|
|
111
|
+
for (layer_name, layer) in &scan.config.layers {
|
|
112
|
+
let Some(broad_pattern) = layer
|
|
113
|
+
.paths
|
|
114
|
+
.iter()
|
|
115
|
+
.find(|pattern| is_broad_source_pattern(pattern))
|
|
116
|
+
else {
|
|
117
|
+
continue;
|
|
118
|
+
};
|
|
119
|
+
let overlapping_layers = scan
|
|
120
|
+
.config
|
|
121
|
+
.layers
|
|
122
|
+
.iter()
|
|
123
|
+
.filter(|(other_name, other_layer)| {
|
|
124
|
+
other_name.as_str() != layer_name.as_str()
|
|
125
|
+
&& other_layer
|
|
126
|
+
.paths
|
|
127
|
+
.iter()
|
|
128
|
+
.any(|pattern| pattern_is_narrower_than(pattern, broad_pattern))
|
|
129
|
+
})
|
|
130
|
+
.map(|(name, _)| name.clone())
|
|
131
|
+
.collect::<Vec<_>>();
|
|
132
|
+
if overlapping_layers.is_empty() {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
findings.push(ArchitectureConfigFinding {
|
|
136
|
+
id: "arch.config.broad_layer_overlap".to_string(),
|
|
137
|
+
severity: "warning".to_string(),
|
|
138
|
+
subject: format!("layer:{layer_name}"),
|
|
139
|
+
message: format!(
|
|
140
|
+
"Layer {layer_name} uses broad path pattern {broad_pattern} while narrower layers also match inside it: {}.",
|
|
141
|
+
overlapping_layers.join(", ")
|
|
142
|
+
),
|
|
143
|
+
suggestion: format!(
|
|
144
|
+
"Keep broad compatibility layers intentional and make allowed_dependencies explicit, or narrow {layer_name} so files do not inherit multiple architectural meanings by default."
|
|
145
|
+
),
|
|
146
|
+
agent_instruction: format!(
|
|
147
|
+
"Do not rely on broad layer {layer_name} to hide architecture boundaries; prefer narrower layer paths or explicit allow rules."
|
|
148
|
+
),
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
findings
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
fn catch_all_context_findings(scan: &ArchitectureScanReport) -> Vec<ArchitectureConfigFinding> {
|
|
155
|
+
if scan.config.contexts.len() <= 1 {
|
|
156
|
+
return Vec::new();
|
|
157
|
+
}
|
|
158
|
+
scan.config
|
|
159
|
+
.contexts
|
|
160
|
+
.iter()
|
|
161
|
+
.filter(|(_, context)| {
|
|
162
|
+
context
|
|
163
|
+
.paths
|
|
164
|
+
.iter()
|
|
165
|
+
.any(|pattern| is_broad_source_pattern(pattern))
|
|
166
|
+
})
|
|
167
|
+
.filter_map(|(context_name, context)| {
|
|
168
|
+
let broad_pattern = context
|
|
169
|
+
.paths
|
|
170
|
+
.iter()
|
|
171
|
+
.find(|pattern| is_broad_source_pattern(pattern))?;
|
|
172
|
+
let specific_contexts = scan
|
|
173
|
+
.config
|
|
174
|
+
.contexts
|
|
175
|
+
.iter()
|
|
176
|
+
.filter(|(other_name, other_context)| {
|
|
177
|
+
other_name.as_str() != context_name.as_str()
|
|
178
|
+
&& other_context
|
|
179
|
+
.paths
|
|
180
|
+
.iter()
|
|
181
|
+
.any(|pattern| pattern_is_narrower_than(pattern, broad_pattern))
|
|
182
|
+
})
|
|
183
|
+
.map(|(name, _)| name.clone())
|
|
184
|
+
.collect::<Vec<_>>();
|
|
185
|
+
if specific_contexts.is_empty() {
|
|
186
|
+
return None;
|
|
187
|
+
}
|
|
188
|
+
Some(ArchitectureConfigFinding {
|
|
189
|
+
id: "arch.config.catch_all_context_with_specific_contexts".to_string(),
|
|
190
|
+
severity: "warning".to_string(),
|
|
191
|
+
subject: format!("context:{context_name}"),
|
|
192
|
+
message: format!(
|
|
193
|
+
"Context {context_name} uses catch-all path pattern {broad_pattern} alongside narrower contexts: {}.",
|
|
194
|
+
specific_contexts.join(", ")
|
|
195
|
+
),
|
|
196
|
+
suggestion: format!(
|
|
197
|
+
"Treat {context_name} as a compatibility bucket only. Move shared code into explicit public APIs or replace the catch-all context with narrower bounded contexts."
|
|
198
|
+
),
|
|
199
|
+
agent_instruction: format!(
|
|
200
|
+
"Do not classify cross-context imports as safe only because {context_name} also matches them; model the real bounded context or public API."
|
|
201
|
+
),
|
|
202
|
+
})
|
|
203
|
+
})
|
|
204
|
+
.collect()
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
fn is_broad_source_pattern(pattern: &str) -> bool {
|
|
208
|
+
matches!(pattern, "**" | "**/*" | "src/**" | "packages/**/src/**")
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
fn pattern_is_narrower_than(pattern: &str, broad_pattern: &str) -> bool {
|
|
212
|
+
if pattern == broad_pattern {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
match broad_pattern {
|
|
216
|
+
"**" | "**/*" => true,
|
|
217
|
+
"src/**" => pattern.starts_with("src/") && pattern != "src/**",
|
|
218
|
+
"packages/**/src/**" => pattern.starts_with("packages/") && pattern.contains("/src/"),
|
|
219
|
+
_ => false,
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
105
223
|
pub fn summary_for(violations: &[ArchitectureViolation]) -> ViolationSummary {
|
|
106
224
|
ViolationSummary {
|
|
107
225
|
errors: violations
|
|
@@ -147,6 +265,21 @@ pub fn format_architecture_validation(report: &ArchitectureValidation) -> String
|
|
|
147
265
|
lines.push("changed-only requested: using incremental architecture cache".to_string());
|
|
148
266
|
}
|
|
149
267
|
|
|
268
|
+
if !report.config_findings.is_empty() {
|
|
269
|
+
lines.push(format!(
|
|
270
|
+
"configuration findings: {}",
|
|
271
|
+
report.config_findings.len()
|
|
272
|
+
));
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
for finding in report.config_findings.iter().take(5) {
|
|
276
|
+
lines.push(format!(
|
|
277
|
+
"- Config {} {} {}",
|
|
278
|
+
finding.severity, finding.subject, finding.message
|
|
279
|
+
));
|
|
280
|
+
lines.push(format!(" fix: {}", finding.suggestion));
|
|
281
|
+
}
|
|
282
|
+
|
|
150
283
|
for violation in report.violations.iter().take(10) {
|
|
151
284
|
lines.push(format!(
|
|
152
285
|
"- {:?} {} {}",
|
|
@@ -183,6 +316,7 @@ pub fn format_architecture_scan(report: &ArchitectureScanReport) -> String {
|
|
|
183
316
|
}
|
|
184
317
|
|
|
185
318
|
pub fn format_architecture_explain(scan: &ArchitectureScanReport) -> String {
|
|
319
|
+
let findings = config_findings_for(scan);
|
|
186
320
|
let layers = scan
|
|
187
321
|
.config
|
|
188
322
|
.layers
|
|
@@ -197,12 +331,22 @@ pub fn format_architecture_explain(scan: &ArchitectureScanReport) -> String {
|
|
|
197
331
|
.cloned()
|
|
198
332
|
.collect::<Vec<_>>()
|
|
199
333
|
.join(", ");
|
|
200
|
-
format!(
|
|
334
|
+
let mut output = format!(
|
|
201
335
|
"NAOME Architecture Fitness\nrules: {}\nlayers: {}\ncontexts: {}\npath extractor: enabled for every repository\nimport extractors: typescript, javascript, rust, python, go, swift\n",
|
|
202
336
|
ARCHITECTURE_RULE_IDS.join(", "),
|
|
203
337
|
empty_label(&layers),
|
|
204
338
|
empty_label(&contexts)
|
|
205
|
-
)
|
|
339
|
+
);
|
|
340
|
+
if !findings.is_empty() {
|
|
341
|
+
output.push_str(&format!("configuration findings: {}\n", findings.len()));
|
|
342
|
+
for finding in findings.iter().take(5) {
|
|
343
|
+
output.push_str(&format!(
|
|
344
|
+
"- {} {}: {}\n",
|
|
345
|
+
finding.severity, finding.subject, finding.message
|
|
346
|
+
));
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
output
|
|
206
350
|
}
|
|
207
351
|
|
|
208
352
|
fn empty_label(value: &str) -> &str {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
use crate::architecture::
|
|
1
|
+
use crate::architecture::model::Severity;
|
|
2
|
+
use crate::architecture::output::ArchitectureViolation;
|
|
2
3
|
use crate::architecture::scan::{ArchitectureScanReport, FileFact, ImportTarget};
|
|
3
4
|
|
|
4
5
|
pub(super) fn validate_file_size_budget(
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
use crate::paths;
|
|
2
2
|
|
|
3
|
+
use super::model::Severity;
|
|
3
4
|
use super::output::{
|
|
4
|
-
architecture_agent_feedback, summary_for, ArchitectureValidation,
|
|
5
|
-
|
|
5
|
+
architecture_agent_feedback, config_findings_for, summary_for, ArchitectureValidation,
|
|
6
|
+
ArchitectureViolation,
|
|
6
7
|
};
|
|
7
8
|
use super::scan::ArchitectureScanReport;
|
|
8
9
|
use crate::architecture::model::ArchitectureEdgeKind;
|
|
@@ -44,6 +45,7 @@ pub fn validate_scan(scan: ArchitectureScanReport) -> ArchitectureValidation {
|
|
|
44
45
|
let summary = summary_for(&violations);
|
|
45
46
|
let status = if summary.errors > 0 { "fail" } else { "pass" }.to_string();
|
|
46
47
|
let agent_feedback = architecture_agent_feedback(&violations);
|
|
48
|
+
let config_findings = config_findings_for(&scan);
|
|
47
49
|
|
|
48
50
|
ArchitectureValidation {
|
|
49
51
|
schema: "naome.arch.validation.v1".to_string(),
|
|
@@ -57,6 +59,7 @@ pub fn validate_scan(scan: ArchitectureScanReport) -> ArchitectureValidation {
|
|
|
57
59
|
changed_only_degraded_to_full_scan: scan.changed_only_degraded_to_full_scan,
|
|
58
60
|
changed_only_mode: scan.changed_only_mode,
|
|
59
61
|
changed_only_degradation_reason: scan.changed_only_degradation_reason,
|
|
62
|
+
config_findings,
|
|
60
63
|
violations,
|
|
61
64
|
agent_feedback,
|
|
62
65
|
}
|
|
@@ -13,12 +13,12 @@ pub use config::{
|
|
|
13
13
|
};
|
|
14
14
|
pub use model::{
|
|
15
15
|
ArchitectureEdge, ArchitectureEdgeKind, ArchitectureGraph, ArchitectureMetadata,
|
|
16
|
-
ArchitectureNode, ArchitectureNodeKind, SourceRange,
|
|
16
|
+
ArchitectureNode, ArchitectureNodeKind, Severity, SourceRange,
|
|
17
17
|
};
|
|
18
18
|
pub use output::{
|
|
19
|
-
format_architecture_explain, format_architecture_scan,
|
|
20
|
-
|
|
21
|
-
ViolationSummary, ARCHITECTURE_RULE_IDS,
|
|
19
|
+
config_findings_for, format_architecture_explain, format_architecture_scan,
|
|
20
|
+
format_architecture_validation, ArchitectureAgentFeedback, ArchitectureConfigFinding,
|
|
21
|
+
ArchitectureValidation, ArchitectureViolation, ViolationSummary, ARCHITECTURE_RULE_IDS,
|
|
22
22
|
};
|
|
23
23
|
pub use scan::{scan_architecture, ArchitectureScanOptions, ArchitectureScanReport};
|
|
24
24
|
|
|
@@ -4,8 +4,8 @@ use crate::models::Decision;
|
|
|
4
4
|
|
|
5
5
|
use super::classifier::{has_candidate, winning_intent};
|
|
6
6
|
use super::legacy_response::response_policy;
|
|
7
|
+
use super::model::ResolvedIntent;
|
|
7
8
|
use super::model::{CanonicalIntent, IntentKind};
|
|
8
|
-
use super::resolver::ResolvedIntent;
|
|
9
9
|
|
|
10
10
|
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
|
|
11
11
|
#[serde(rename_all = "camelCase")]
|
|
@@ -75,3 +75,30 @@ pub(crate) struct CanonicalIntent {
|
|
|
75
75
|
pub has_workflow_conflict: bool,
|
|
76
76
|
pub validation_errors: Vec<String>,
|
|
77
77
|
}
|
|
78
|
+
|
|
79
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
80
|
+
pub(crate) enum CompletedTaskReadiness {
|
|
81
|
+
Valid,
|
|
82
|
+
ValidAfterHarnessRefresh,
|
|
83
|
+
ValidWithUnrelatedDirty,
|
|
84
|
+
Invalid,
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
88
|
+
pub(crate) enum DirtyDiffReadiness {
|
|
89
|
+
Unclassified,
|
|
90
|
+
HarnessRefreshOnly,
|
|
91
|
+
HarnessRefreshWithUnrelatedDirty,
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
95
|
+
pub(crate) struct ResolvedIntent {
|
|
96
|
+
pub prompt_intent: IntentKind,
|
|
97
|
+
pub certainty: String,
|
|
98
|
+
pub policy_action: String,
|
|
99
|
+
pub allowed: bool,
|
|
100
|
+
pub summary: String,
|
|
101
|
+
pub next_action: String,
|
|
102
|
+
pub reason_codes: Vec<String>,
|
|
103
|
+
pub risk_codes: Vec<String>,
|
|
104
|
+
}
|
|
@@ -1,37 +1,12 @@
|
|
|
1
1
|
use crate::models::Decision;
|
|
2
2
|
|
|
3
3
|
use super::classifier::winning_intent;
|
|
4
|
-
use super::model::{
|
|
4
|
+
use super::model::{
|
|
5
|
+
CanonicalIntent, CompletedTaskReadiness, DirtyDiffReadiness, IntentKind, ResolvedIntent,
|
|
6
|
+
};
|
|
5
7
|
use super::resolver_policy::state_policy;
|
|
6
8
|
use super::resolver_shared::{ambiguous_conflict, ambiguous_empty, unsafe_policy, Policy};
|
|
7
9
|
|
|
8
|
-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
9
|
-
pub(crate) enum CompletedTaskReadiness {
|
|
10
|
-
Valid,
|
|
11
|
-
ValidAfterHarnessRefresh,
|
|
12
|
-
ValidWithUnrelatedDirty,
|
|
13
|
-
Invalid,
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
17
|
-
pub(crate) enum DirtyDiffReadiness {
|
|
18
|
-
Unclassified,
|
|
19
|
-
HarnessRefreshOnly,
|
|
20
|
-
HarnessRefreshWithUnrelatedDirty,
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
24
|
-
pub(crate) struct ResolvedIntent {
|
|
25
|
-
pub prompt_intent: IntentKind,
|
|
26
|
-
pub certainty: String,
|
|
27
|
-
pub policy_action: String,
|
|
28
|
-
pub allowed: bool,
|
|
29
|
-
pub summary: String,
|
|
30
|
-
pub next_action: String,
|
|
31
|
-
pub reason_codes: Vec<String>,
|
|
32
|
-
pub risk_codes: Vec<String>,
|
|
33
|
-
}
|
|
34
|
-
|
|
35
10
|
pub(crate) fn resolve_intent(
|
|
36
11
|
decision: &Decision,
|
|
37
12
|
canonical: &CanonicalIntent,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
use super::model::IntentKind;
|
|
2
|
-
use super::resolver::DirtyDiffReadiness;
|
|
1
|
+
use super::model::{DirtyDiffReadiness, IntentKind};
|
|
3
2
|
use super::resolver_catalog::{
|
|
4
3
|
POLICY_BASELINE_BLOCK, POLICY_BASELINE_CANCEL, POLICY_BASELINE_COMMIT_UPGRADE,
|
|
5
4
|
POLICY_BASELINE_NEW_REFRESH, POLICY_BASELINE_NEW_UPGRADE, POLICY_BASELINE_NO_COMMIT,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
use crate::models::Decision;
|
|
2
2
|
|
|
3
|
-
use super::model::IntentKind;
|
|
4
|
-
use super::resolver::{CompletedTaskReadiness, DirtyDiffReadiness};
|
|
3
|
+
use super::model::{CompletedTaskReadiness, DirtyDiffReadiness, IntentKind};
|
|
5
4
|
use super::resolver_active::active_policy;
|
|
6
5
|
use super::resolver_baseline::{baseline_policy, dirty_policy};
|
|
7
6
|
use super::resolver_catalog::{
|
|
@@ -24,7 +24,8 @@ use crate::task_state::{
|
|
|
24
24
|
use classifier::canonical_intent;
|
|
25
25
|
pub(crate) use envelope::prompt_envelope_json;
|
|
26
26
|
pub use legacy::{format_intent, IntentDecision, PromptEvidence};
|
|
27
|
-
use
|
|
27
|
+
use model::{CompletedTaskReadiness, DirtyDiffReadiness};
|
|
28
|
+
use resolver::resolve_intent;
|
|
28
29
|
|
|
29
30
|
pub fn evaluate_intent(
|
|
30
31
|
root: &Path,
|
|
@@ -21,13 +21,13 @@ mod verification_contract_policy;
|
|
|
21
21
|
mod workflow;
|
|
22
22
|
|
|
23
23
|
pub use architecture::{
|
|
24
|
-
default_architecture_config_text, format_architecture_explain,
|
|
25
|
-
format_architecture_validation, scan_architecture,
|
|
26
|
-
ArchitectureAgentFeedback, ArchitectureConfig,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
ARCHITECTURE_RULE_IDS,
|
|
24
|
+
config_findings_for, default_architecture_config_text, format_architecture_explain,
|
|
25
|
+
format_architecture_scan, format_architecture_validation, scan_architecture,
|
|
26
|
+
validate_architecture, ArchitectureAgentFeedback, ArchitectureConfig,
|
|
27
|
+
ArchitectureConfigFinding, ArchitectureEdge, ArchitectureEdgeKind, ArchitectureGraph,
|
|
28
|
+
ArchitectureMetadata, ArchitectureNode, ArchitectureNodeKind, ArchitectureScanOptions,
|
|
29
|
+
ArchitectureScanReport, ArchitectureValidation, ArchitectureViolation, ContextConfig,
|
|
30
|
+
LayerConfig, RuleConfig, Severity, SourceRange, ViolationSummary, ARCHITECTURE_RULE_IDS,
|
|
31
31
|
};
|
|
32
32
|
pub use context::{
|
|
33
33
|
select_context_for_changed_paths, select_context_for_prompt, ContextBudgetLedger,
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
use super::
|
|
1
|
+
use super::adapter_support::{
|
|
2
|
+
quality_path_rule as path_rule, quality_test_file_limits as test_file_limits,
|
|
3
|
+
};
|
|
2
4
|
use super::types::{QualityLimitOverrides, QualityPathRule};
|
|
3
5
|
|
|
4
6
|
pub(super) fn swift_path_rules() -> Vec<QualityPathRule> {
|
|
@@ -2,6 +2,8 @@ use std::collections::HashSet;
|
|
|
2
2
|
|
|
3
3
|
use crate::models::NaomeError;
|
|
4
4
|
|
|
5
|
+
use super::types::{QualityLimitOverrides, QualityPathRule};
|
|
6
|
+
|
|
5
7
|
pub(crate) struct RepoSignals<'a> {
|
|
6
8
|
paths: &'a [String],
|
|
7
9
|
}
|
|
@@ -98,6 +100,36 @@ pub(crate) fn extend_unique(target: &mut Vec<String>, values: &[&str]) {
|
|
|
98
100
|
}
|
|
99
101
|
}
|
|
100
102
|
|
|
103
|
+
pub(crate) fn quality_test_file_limits(max_top_level_symbols: usize) -> QualityLimitOverrides {
|
|
104
|
+
QualityLimitOverrides {
|
|
105
|
+
max_file_lines: Some(650),
|
|
106
|
+
max_diff_added_lines: Some(220),
|
|
107
|
+
max_function_lines: Some(140),
|
|
108
|
+
max_top_level_symbols: Some(max_top_level_symbols),
|
|
109
|
+
duplicate_block_lines: Some(14),
|
|
110
|
+
near_duplicate_similarity: Some(0.96),
|
|
111
|
+
..QualityLimitOverrides::default()
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
pub(crate) fn quality_path_rule(
|
|
116
|
+
id: &str,
|
|
117
|
+
paths: &[&str],
|
|
118
|
+
limits: QualityLimitOverrides,
|
|
119
|
+
disabled_checks: &[&str],
|
|
120
|
+
) -> QualityPathRule {
|
|
121
|
+
QualityPathRule {
|
|
122
|
+
id: id.to_string(),
|
|
123
|
+
paths: string_list(paths),
|
|
124
|
+
limits,
|
|
125
|
+
disabled_checks: string_list(disabled_checks),
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
fn string_list(values: &[&str]) -> Vec<String> {
|
|
130
|
+
values.iter().map(|value| (*value).to_string()).collect()
|
|
131
|
+
}
|
|
132
|
+
|
|
101
133
|
pub(crate) fn detects_rust_project(signals: &RepoSignals<'_>) -> bool {
|
|
102
134
|
signals.has_manifest("Cargo.toml") || signals.has_extension(&[".rs"])
|
|
103
135
|
}
|
|
@@ -5,10 +5,10 @@ use super::adapter_support::{
|
|
|
5
5
|
detected_ids, detects_generated_ios_project, detects_ios_app_structure_project,
|
|
6
6
|
detects_ios_resources_project, detects_javascript_typescript_project, detects_rust_project,
|
|
7
7
|
detects_swift_package_project, detects_swift_project, detects_swiftui_project,
|
|
8
|
-
detects_xcode_project, detects_xctest_project, extend_unique, find_adapter_by_id,
|
|
9
|
-
AdapterDescriptor, RepoSignals,
|
|
8
|
+
detects_xcode_project, detects_xctest_project, extend_unique, find_adapter_by_id,
|
|
9
|
+
quality_path_rule, quality_test_file_limits, validate_ids, AdapterDescriptor, RepoSignals,
|
|
10
10
|
};
|
|
11
|
-
use super::types::{
|
|
11
|
+
use super::types::{QualityPathRule, RepositoryQualityConfig};
|
|
12
12
|
|
|
13
13
|
const CONFIG_PATH: &str = ".naome/repository-quality.json";
|
|
14
14
|
|
|
@@ -163,32 +163,15 @@ fn javascript_typescript_test_paths() -> Vec<String> {
|
|
|
163
163
|
paths
|
|
164
164
|
}
|
|
165
165
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
max_file_lines: Some(650),
|
|
169
|
-
max_diff_added_lines: Some(220),
|
|
170
|
-
max_function_lines: Some(140),
|
|
171
|
-
max_top_level_symbols: Some(max_top_level_symbols),
|
|
172
|
-
duplicate_block_lines: Some(14),
|
|
173
|
-
near_duplicate_similarity: Some(0.96),
|
|
174
|
-
..QualityLimitOverrides::default()
|
|
175
|
-
}
|
|
166
|
+
fn test_file_limits(max_top_level_symbols: usize) -> super::types::QualityLimitOverrides {
|
|
167
|
+
quality_test_file_limits(max_top_level_symbols)
|
|
176
168
|
}
|
|
177
169
|
|
|
178
|
-
|
|
170
|
+
fn path_rule(
|
|
179
171
|
id: &str,
|
|
180
172
|
paths: &[&str],
|
|
181
|
-
limits: QualityLimitOverrides,
|
|
173
|
+
limits: super::types::QualityLimitOverrides,
|
|
182
174
|
disabled_checks: &[&str],
|
|
183
175
|
) -> QualityPathRule {
|
|
184
|
-
|
|
185
|
-
id: id.to_string(),
|
|
186
|
-
paths: string_list(paths),
|
|
187
|
-
limits,
|
|
188
|
-
disabled_checks: string_list(disabled_checks),
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
fn string_list(values: &[&str]) -> Vec<String> {
|
|
193
|
-
values.iter().map(|value| (*value).to_string()).collect()
|
|
176
|
+
quality_path_rule(id, paths, limits, disabled_checks)
|
|
194
177
|
}
|