chore: remove BMAD framework files and IDE configuration artifacts

Clean up unused BMAD workflow, agent, and command files across all IDE
configurations (.agent, .clinerules, .cursor, .gemini, .github, .kilocode,
.opencode) and internal module files (_bmad/bmb, _bmad/bmm).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Sepehr
2026-04-25 15:01:09 +02:00
parent 891c4ba436
commit ab5dc7e568
3006 changed files with 279068 additions and 59151 deletions

View File

@@ -1,8 +1,9 @@
//! Tests for batch execution.
use entropyk_cli::batch::{discover_config_files, BatchSummary};
use entropyk_cli::batch::{discover_config_files, BatchAggregator, BatchSummary, OutputFormat};
use entropyk_cli::run::{SimulationResult, SimulationStatus};
use std::path::PathBuf;
use std::str::FromStr;
use tempfile::tempdir;
#[test]
@@ -128,3 +129,167 @@ fn test_simulation_result_statuses() {
assert_eq!(error_count, 1);
assert_eq!(timeout_count, 1);
}
#[test]
fn test_batch_aggregator_csv_output() {
let results = vec![
SimulationResult {
input: "scenario1.json".to_string(),
status: SimulationStatus::Converged,
convergence: Some(entropyk_cli::run::ConvergenceInfo {
final_residual: 1e-8,
tolerance: 1e-6,
}),
iterations: Some(25),
state: None,
performance: None,
error: None,
elapsed_ms: 150,
},
SimulationResult {
input: "scenario2.json".to_string(),
status: SimulationStatus::Converged,
convergence: Some(entropyk_cli::run::ConvergenceInfo {
final_residual: 5e-7,
tolerance: 1e-6,
}),
iterations: Some(30),
state: None,
performance: None,
error: None,
elapsed_ms: 200,
},
SimulationResult {
input: "scenario3.json".to_string(),
status: SimulationStatus::Error,
convergence: None,
iterations: None,
state: None,
performance: None,
error: Some("Solver failed".to_string()),
elapsed_ms: 0,
},
];
let aggregator = BatchAggregator::new(results);
let csv = aggregator.to_csv();
let lines: Vec<&str> = csv.lines().collect();
// Header + 3 data lines
assert_eq!(lines.len(), 4);
assert!(lines[0].contains("input,status,iterations,converged"));
assert!(lines[1].contains("scenario1.json"));
assert!(lines[1].contains("converged"));
assert!(lines[1].contains("true"));
assert!(lines[3].contains("error"));
}
#[test]
fn test_batch_aggregator_json_summary() {
let results = vec![
SimulationResult {
input: "test1.json".to_string(),
status: SimulationStatus::Converged,
convergence: None,
iterations: Some(10),
state: None,
performance: None,
error: None,
elapsed_ms: 50,
},
SimulationResult {
input: "test2.json".to_string(),
status: SimulationStatus::Converged,
convergence: None,
iterations: Some(15),
state: None,
performance: None,
error: None,
elapsed_ms: 75,
},
SimulationResult {
input: "test3.json".to_string(),
status: SimulationStatus::Timeout,
convergence: None,
iterations: Some(100),
state: None,
performance: None,
error: None,
elapsed_ms: 5000,
},
];
let aggregator = BatchAggregator::new(results);
let summary = aggregator.summary();
assert_eq!(summary.total, 3);
assert_eq!(summary.succeeded, 2);
assert_eq!(summary.failed, 0);
assert_eq!(summary.non_converged, 1);
}
#[test]
fn test_output_format_parsing() {
assert_eq!(OutputFormat::from_str("json").unwrap(), OutputFormat::Json);
assert_eq!(OutputFormat::from_str("JSON").unwrap(), OutputFormat::Json);
assert_eq!(OutputFormat::from_str("csv").unwrap(), OutputFormat::Csv);
assert_eq!(OutputFormat::from_str("CSV").unwrap(), OutputFormat::Csv);
assert!(OutputFormat::from_str("xml").is_err());
assert!(OutputFormat::from_str("invalid").is_err());
}
#[test]
fn test_batch_summary_json_serialization_roundtrip() {
let summary = BatchSummary {
total: 20,
succeeded: 18,
failed: 1,
non_converged: 1,
total_elapsed_ms: 5000,
avg_elapsed_ms: 250.0,
results: vec![],
};
let json = summary.to_json().unwrap();
let deserialized: BatchSummary = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized.total, 20);
assert_eq!(deserialized.succeeded, 18);
assert_eq!(deserialized.failed, 1);
assert_eq!(deserialized.non_converged, 1);
assert_eq!(deserialized.total_elapsed_ms, 5000);
}
#[test]
fn test_batch_summary_csv_with_convergence() {
let results = vec![SimulationResult {
input: "config1.json".to_string(),
status: SimulationStatus::Converged,
convergence: Some(entropyk_cli::run::ConvergenceInfo {
final_residual: 1e-9,
tolerance: 1e-6,
}),
iterations: Some(42),
state: None,
performance: None,
error: None,
elapsed_ms: 300,
}];
let summary = BatchSummary {
total: 1,
succeeded: 1,
failed: 0,
non_converged: 0,
total_elapsed_ms: 300,
avg_elapsed_ms: 300.0,
results,
};
let csv = summary.to_csv();
assert!(csv.contains("config1.json"));
assert!(csv.contains("converged"));
assert!(csv.contains("42"));
assert!(csv.contains("1.00e-9"));
assert!(csv.contains("300"));
}

View File

@@ -652,3 +652,112 @@ fn test_fan_control_bounded_does_not_error() {
);
}
}
/// Integration test for story 15-3: CLI uses real Pump<Connected> (2 equations), not stub.
/// A config with two Pumps in a loop must not fail with "State dimension does not match equation count".
#[test]
fn test_pump_real_component_used() {
use entropyk_cli::run::run_simulation;
let dir = tempdir().unwrap();
let config_path = dir.path().join("water_loop.json");
let json = r#"
{
"name": "Water loop two pumps",
"fluid": "Water",
"circuits": [{
"id": 0,
"name": "Water",
"components": [
{ "type": "Pump", "name": "pump1" },
{ "type": "Pump", "name": "pump2" }
],
"edges": [
{ "from": "pump1:outlet", "to": "pump2:inlet" },
{ "from": "pump2:outlet", "to": "pump1:inlet" }
]
}],
"solver": { "strategy": "newton", "max_iterations": 50, "tolerance": 1e-6 }
}
"#;
std::fs::write(&config_path, json).unwrap();
let result = run_simulation(&config_path, None, false).unwrap();
// Real Pump has 2 equations each -> 4 equations, 2 edges -> 4 state. No dimension mismatch.
if let Some(ref err) = result.error {
assert!(
!err.contains("State dimension") || !err.contains("equation count"),
"Real Pump must be used (no stub); dimension mismatch indicates stub: {}",
err
);
}
}
/// Story 15-4: BphxEvaporator and BphxCondenser are accepted by create_component (config parsing).
/// Asserts that a config with both types does not yield "Unknown component type".
#[test]
fn test_bphx_evaporator_and_condenser_config_parsing() {
use entropyk_cli::run::run_simulation;
let dir = tempdir().unwrap();
let config_path = dir.path().join("bphx_parsing.json");
let json = r#"
{
"name": "BPHX parsing test",
"fluid": "R410A",
"circuits": [
{
"id": 0,
"components": [
{
"type": "BphxEvaporator",
"name": "evap",
"refrigerant": "R410A",
"secondary_fluid": "Water",
"dh_m": 0.003,
"area_m2": 0.5,
"n_plates": 20
},
{
"type": "BphxCondenser",
"name": "cond",
"refrigerant": "R410A",
"secondary_fluid": "Water",
"target_subcooling_k": 3.0,
"dh_m": 0.003,
"area_m2": 0.5,
"n_plates": 20
}
],
"edges": []
}
],
"solver": { "strategy": "newton", "max_iterations": 10, "tolerance": 1e-6 }
}
"#;
std::fs::write(&config_path, json).unwrap();
let result = run_simulation(&config_path, None, false).unwrap();
// create_component must accept both types (no "Unknown component type").
if let Some(ref err) = result.error {
assert!(
!err.contains("Unknown component type"),
"BphxEvaporator and BphxCondenser must be supported: {}",
err
);
}
// We expect Error or NonConverged (edges empty -> topology/finalization failure), not config parse failure.
match result.status {
SimulationStatus::Error => {
// Failure is expected (e.g. isolated nodes); config parsing succeeded.
}
SimulationStatus::NonConverged | SimulationStatus::Converged | SimulationStatus::Timeout => {
// Also acceptable if we get to solver stage.
}
}
}