6.7 KiB
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: 355–356, 371
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°Ctest_glycol_concentration_effect– propriétés vs concentration (seul EG30 > water est testé)test_glycol_out_of_range– température hors plage pour glycoltest_humid_air_psychrometrics– enthalpie vs formule psychrométriquetest_performance_vs_coolprop– benchmark 1000× (optionnel selon story)
Fichier: crates/fluids/src/incompressible.rs
Lignes: 302–437 (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: 280–286
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: 129–132, 161–166, 218–225
Correction: Ajouter en début de chaque property_* :
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: 271–273
Correction: Vérifier si le fluide est supporté et retourner UnknownFluid si non :
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: 79–93
Correction: Soit utiliser ValidRange dans les méthodes property_*, soit le retirer s’il n’est 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: L’implémentation a mis IncompFluid dans incompressible.rs au lieu de types.rs. C’est 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.107T - 0.00333T²) |
| 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+10c).ln().exp() → 1+10c |