Skip to content

Commit 3dd1cd7

Browse files
committed
Add safe redundant hierarchical relations auto-removal
Implement distinction between safe (auto-fixable) and unsafe (manual review) redundant hierarchical relations in the lint command. Safe redundant relations are those with a single unambiguous chain (A→B→C with redundant direct A→C). These can be safely auto-removed when using `reqvire lint --fix`. Unsafe redundant relations occur when multiple paths converge to the same ancestor (A→B→C and A→D→C with redundant direct A→C). These require manual review as both paths may have semantic meaning. Implementation: - Add SafeRedundantHierarchicalRelations variant to AutoFixableIssue - Implement path counting logic to distinguish single-chain from multi-path - Split detect_maybe_redundant_hierarchical_relations into safe/unsafe cases - Update apply_fixes to handle safe hierarchical relation removal - Add sorting for deterministic output in lint reports - Update test suite with comprehensive test cases Testing: - Extended test-lint-command with single-chain and multi-path examples - Verified diff-based test validation for file modifications - All tests pass successfully Traceability: - Satisfies: specifications/SystemRequirements/Requirements.md#safe-redundant-hierarchical-relations-auto-removal - Verified by: specifications/Verifications/Misc.md#lint-command-verification
1 parent 5ad966c commit 3dd1cd7

28 files changed

+2679
-2160
lines changed

cli/src/cli.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,18 @@ pub enum Commands {
209209
json: bool,
210210
},
211211

212+
/// Generate model structure diagram with optional filtering
213+
#[clap(override_help = "Generate model structure diagram with optional filtering\n\nMODEL OPTIONS:\n --root-id <ID> Filter model from specific root element (forward relations only)\n --json Output results in JSON format")]
214+
Model {
215+
/// Filter model from specific root element using forward-only relation traversal
216+
#[clap(long, value_name = "ID", help_heading = "MODEL OPTIONS")]
217+
root_id: Option<String>,
218+
219+
/// Output results in JSON format
220+
#[clap(long, help_heading = "MODEL OPTIONS")]
221+
json: bool,
222+
},
223+
212224
/// Analyze model quality and detect issues in requirements relations
213225
#[clap(override_help = "Analyze model quality and detect issues in requirements relations\n\nLINT OPTIONS:\n --fixable Show only auto-fixable issues\n --auditable Show only issues requiring manual review\n --fix Apply automatic fixes for auto-fixable issues\n --json Output results in JSON format")]
214226
Lint {
@@ -431,6 +443,7 @@ fn wants_json(args: &Args) -> bool {
431443
Some(Commands::Matrix { json, .. }) => *json,
432444
Some(Commands::Traces { json, .. }) => *json,
433445
Some(Commands::Coverage { json }) => *json,
446+
Some(Commands::Model { json, .. }) => *json,
434447
Some(Commands::Lint { json, .. }) => *json,
435448
_ => false,
436449
}
@@ -655,6 +668,18 @@ pub fn handle_command(
655668
coverage_report.print(json);
656669
return Ok(0);
657670
},
671+
Some(Commands::Model { root_id, json }) => {
672+
// Generate model diagram with optional filtering
673+
let forward_only = root_id.is_some(); // Use forward-only when filtering by root element
674+
let output = diagrams::generate_model_report(
675+
&model_manager.graph_registry,
676+
root_id.as_deref(),
677+
forward_only,
678+
json
679+
)?;
680+
println!("{}", output);
681+
return Ok(0);
682+
},
658683
Some(Commands::Lint { fixable, auditable, fix, json }) => {
659684
// Run lint analysis
660685
let lint_report = lint::analyze_model(&model_manager.graph_registry);

core/src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,4 +106,7 @@ pub enum ReqvireError {
106106
#[error("Validation failed with {} errors", .0.len())]
107107
ValidationError(Vec<ReqvireError>),
108108

109+
#[error("Serialization error: {0}")]
110+
SerializationError(String),
111+
109112
}

0 commit comments

Comments
 (0)