Entropyk/_bmad-output/implementation-artifacts/2-7-code-review-report.md

200 lines
6.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Code Review Report Story 2.7: Incompressible Fluids Support
**Date:** 2026-02-15
**Story:** 2-7-incompressible-fluids-support
**Status avant review:** review
**Fichiers concernés:** `crates/fluids/src/incompressible.rs` (nouveau), `crates/fluids/src/lib.rs` (modifié)
---
## Git vs Story
- **Story File List:** incompressible.rs (new), lib.rs (modified)
- **Git:** `crates/fluids/` non suivi (??) pas de commit
- **Écart:** Aucun la story ne prétend pas que types.rs a été modifié dans le File List final
---
## Résumé des findings
| Sévérité | Nombre |
|----------|--------|
| HIGH | 1 |
| MEDIUM | 4 |
| LOW | 3 |
| **Total**| **8** |
---
## 🔴 HIGH
### 1. AC #2 non conforme tolérance 1 % au lieu de 0.1 %
**AC #2:** « Results match reference data (IAPWS-IF97 for water, ASHRAE for glycol) within 0.1% »
**Implémentation:** Les tests utilisent une tolérance de 1 % (`< 0.01`), pas 0.1 % (`< 0.001`).
**Fichier:** `crates/fluids/src/incompressible.rs`
**Lignes:** 355356, 371
```rust
assert!((rho_20 - 998.2).abs() / 998.2 < 0.01, "rho_20={}", rho_20); // 1% ≠ 0.1%
assert!((cp - 4182.0).abs() / 4182.0 < 0.01, "Cp={}", cp); // 1% ≠ 0.1%
```
**Correction:** Remplacer `0.01` par `0.001` dans les assertions de précision, ou ajuster les modèles pour atteindre 0.1 % si nécessaire.
---
## 🟡 MEDIUM
### 2. Tests requis manquants (story § Testing Requirements)
**Story:** Les tests suivants sont listés comme requis mais absents :
- `test_water_enthalpy_reference` h(T) par rapport à 0°C
- `test_glycol_concentration_effect` propriétés vs concentration (seul EG30 > water est testé)
- `test_glycol_out_of_range` température hors plage pour glycol
- `test_humid_air_psychrometrics` enthalpie vs formule psychrométrique
- `test_performance_vs_coolprop` benchmark 1000× (optionnel selon story)
**Fichier:** `crates/fluids/src/incompressible.rs`
**Lignes:** 302437 (section tests)
**Correction:** Ajouter au minimum `test_water_enthalpy_reference`, `test_glycol_concentration_effect` et `test_glycol_out_of_range`.
---
### 3. Phase incorrecte pour HumidAir
**Implémentation:** `phase()` retourne `Phase::Liquid` pour tous les fluides, y compris HumidAir.
**Problème:** HumidAir est un mélange gazeux, pas un liquide.
**Fichier:** `crates/fluids/src/incompressible.rs`
**Lignes:** 280286
```rust
fn phase(&self, fluid: FluidId, _state: ThermoState) -> FluidResult<Phase> {
if IncompFluid::from_fluid_id(&fluid).is_some() {
Ok(Phase::Liquid) // HumidAir devrait être Vapor
} else {
Err(FluidError::UnknownFluid { fluid: fluid.0 })
}
}
```
**Correction:** Retourner `Phase::Vapor` pour HumidAir, `Phase::Liquid` pour les autres.
---
### 4. Pas de validation NaN/Inf pour la température
**Implémentation:** Aucune vérification que `t_k` est fini (non NaN, non Inf).
**Problème:** Si `t_k = f64::NAN`, les comparaisons `t_k < min_t || t_k > max_t` sont fausses, la validation passe et les polynômes renvoient NaN.
**Fichier:** `crates/fluids/src/incompressible.rs`
**Lignes:** 129132, 161166, 218225
**Correction:** Ajouter en début de chaque `property_*` :
```rust
if !t_k.is_finite() {
return Err(FluidError::InvalidState {
reason: format!("Temperature {} K is not finite", t_k),
});
}
```
---
### 5. `critical_point` pour fluides non supportés
**Implémentation:** `critical_point()` retourne toujours `NoCriticalPoint` pour tout `FluidId`.
**Problème:** Pour un fluide non supporté (ex. `"R134a"`), le backend retourne `NoCriticalPoint` alors que R134a a un point critique. Cohérence avec `property()` qui retourne `UnknownFluid`.
**Fichier:** `crates/fluids/src/incompressible.rs`
**Lignes:** 271273
**Correction:** Vérifier si le fluide est supporté et retourner `UnknownFluid` si non :
```rust
fn critical_point(&self, fluid: FluidId) -> FluidResult<CriticalPoint> {
if IncompFluid::from_fluid_id(&fluid).is_none() {
return Err(FluidError::UnknownFluid { fluid: fluid.0 });
}
Err(FluidError::NoCriticalPoint { fluid: fluid.0 })
}
```
---
## 🟢 LOW
### 6. `ValidRange` défini mais non utilisé
**Implémentation:** `ValidRange` est défini et exporté, mais le code utilise des tuples `(min_t, max_t)` via `valid_temp_range()`.
**Fichier:** `crates/fluids/src/incompressible.rs`
**Lignes:** 7993
**Correction:** Soit utiliser `ValidRange` dans les méthodes `property_*`, soit le retirer sil nest pas nécessaire.
---
### 7. Formule de viscosité glycol redondante
**Implémentation:** `conc_factor = (1.0 + 10.0 * concentration).ln().exp()` est équivalent à `1.0 + 10.0 * concentration`.
**Fichier:** `crates/fluids/src/incompressible.rs`
**Ligne:** 198
**Correction:** Simplifier en `let conc_factor = 1.0 + 10.0 * concentration;`
---
### 8. Story File List vs Technical Requirements
**Story:** « Modified files » inclut `types.rs` (Add IncompressibleFluid enum to FluidId), mais le File List final ne mentionne que `incompressible.rs` et `lib.rs`.
**Constat:** Limplémentation a mis `IncompFluid` dans `incompressible.rs` au lieu de `types.rs`. Cest cohérent et acceptable.
**Correction:** Mettre à jour la section « Modified files » de la story pour retirer `types.rs` et refléter la structure réelle.
---
## Synthèse
| # | Sévérité | Description |
|---|----------|-------------|
| 1 | HIGH | Tolérance tests 1 % au lieu de 0.1 % (AC #2) |
| 2 | MEDIUM | Tests requis manquants |
| 3 | MEDIUM | Phase HumidAir = Liquid au lieu de Vapor |
| 4 | MEDIUM | Pas de validation NaN/Inf pour t_k |
| 5 | MEDIUM | `critical_point` ne distingue pas fluide inconnu |
| 6 | LOW | `ValidRange` non utilisé |
| 7 | LOW | Formule viscosité glycol redondante |
| 8 | LOW | Incohérence story File List vs Technical Requirements |
---
## Recommandation
- Corriger les points HIGH et MEDIUM avant de passer la story en `done`.
- Les points LOW peuvent être traités dans un suivi ultérieur.
---
## Corrections appliquées (2026-02-15)
| # | Correction |
|---|------------|
| 1 | Tolérance 0.01→0.001 ; polynôme densité eau recalibré (1001.7 - 0.107*T - 0.00333*T²) |
| 2 | Tests ajoutés : test_water_enthalpy_reference, test_glycol_concentration_effect, test_glycol_out_of_range, test_humid_air_psychrometrics, test_phase_humid_air_is_vapor, test_critical_point_unknown_fluid, test_nan_temperature_rejected |
| 3 | phase() retourne Phase::Vapor pour HumidAir |
| 4 | Validation t_k.is_finite() dans property_water, property_glycol, property_humid_air |
| 5 | critical_point() retourne UnknownFluid pour fluides non supportés |
| 7 | conc_factor simplifié : (1+10*c).ln().exp() → 1+10*c |