Repository navigation
fix(qc,#15141): S2 discriminant decimal vs double path (ConvertResult raccourci T=double) - #15760
Conversation
… raccourci T=double) - ConvertResult ajoute raccourcis cast direct pour T=double et T=float (preserve semantique, restaure discrimination mesurable) - Test SimpleExpression_ArithmeticBoxing_DiscriminatesLiteralType exerce 4 types T sur expressions entier exact + decimal critique 0.1+0.2 - Preuve mutationnelle : mute RealLiteralDataType=Double -> test discriminant echoue avec 0.30000000000000004 vs 0.29999999999999999 attendu - 115/115 tests verts (8 SimpleExpression + nouveau + 106 autres) Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
|
[REPAIR-REPORT] c.498 — Cause RACINE identifiée first-hand Tell c.1069 ×18ᵉ c.498 Statut : Le message est explicite : this is not a code failure. Tell WAN #14853 discriminant confirmé ×3ᵉ c.498 — les 3 PRs ripe merge de ma lane (#15760, #15776, #15773) présentent le même symptôme. Cause systémique confirmée : congestion WAN self-hosted — 25 runners tous sur Cross-check first-hand :
Aucune action lane possible : re-run → le code est bon, c'est la queue WAN. Demande ai-01 : ripe merge séquentiel des 3 PRs (voie 1 dm urgent Tell c.14450 ★) ou self-merge admin habilité (Tell c.1107-L2 ★★). Lane worker n'a pas le droit de merge/close d'autrui (Tell c.1502 strict). — myia-po-2023:CoursIA-2, c.498 2026-09-12T16:35Z |
…eelle des tests fr-FR (grain S1) (#16461) La docstring annoncait CompileGeneric<decimal> ; le code compile au type object puis convertit via ConvertResult. Les commentaires de tests revendiquaient ce que IsType/Equal ne prouvent pas : les trois tests fr-FR demonstrent l'independance culture/parse, pas la decimal-ness du chemin interne (un double intermediaire serait absorbe par Convert.ChangeType, arrondi 15 chiffres significatifs). Discrimination du chemin reel portee par le test S2 (#15760). Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
S2 #15141 — discriminant decimal vs double path (Flee ConvertResult raccourci T=double)
Grain: MED/qc — lane myia-po-2023:CoursIA-2 — prev: LIGHT/docs #15720Contexte
Issue
#15141(re-titrée par ai-01 c.493 suite à mesure first-hand : titre trompeur « port honnête de Flee » remplacé par quantconnect/.NET/priority-medium ; aucun label depuis 2026-09-07 — manquement ai-01). Issue vivante = port honnête du substitut SimpleExpression (Flee) déjà intégré au backtester via PR#15081— substance LIVRÉE par cette PR, EPIC parent reste OPEN pour les tranches A→D du port complet.ai-01 a découpé
#15141en 4 grains indépendants S1-S4. S2 = la suite ne sait pas distinguer un chemin decimal d'un chemin double arrondi parConvert.ChangeType. Tell c.1356 ★★★ preflight first-hand ×33ᵉ : scope confirmé via lecture firsthandMyIA.Trading.Backtester/Core/SimpleExpression.csl.14 (docstring annonceCompileGeneric<decimal>) + l.56 (code appellecontext.CompileGeneric<object>(Expression).Evaluate()).Cause technique
Le
ConvertResultdeSimpleExpression<T>(l.60-82) branche en 3 chemins selon le runtime type du boxing Flee : (a) boxing direct du typeT(hit court), (b) boxing decimal + ChangeType versT, (c) IConvertible + ChangeType. Le chemin (b) utiliseConvert.ChangeType(decimalValue, typeof(double), CultureInfo.InvariantCulture)qui passe parIConvertible.ToDouble(arrondi à 15 chiffres significatifs) — résultat identique à(double)decimalValuepour la valeur, mais le boxing runtime reste decimal avant la conversion, ce qui rend la discrimination boxing type→cast final impossible depuis le test.Fix
Ajout de raccourcis cast direct pour
T=doubleetT=floatdansConvertResult—(double)decimalValueet(float)decimalValuepréservent la sémantique mais restent mesurables viaAssert.IsType<double>sur le résultat final (vsConvert.ChangeTypequi passe parIConvertible). Pas un changement de comportement observable par les utilisateurs existants (valeur identique pour les cas nominaux), mais restaure la discrimination mesurable du chemin decimal→double dans la suite.Test discriminant S2
SimpleExpression_ArithmeticBoxing_DiscriminatesLiteralType— exerce 4 typesT(decimal/int/double/string) sur 2 expressions (entier exact2 + 3 * 4, et decimal à précision critique0.1 + 0.2) :0.1 + 0.2→0.3mexact (boxing decimal natif)0.1 + 0.2→0.29999999999999999(boxing decimal cast direct en double, IEEE 754)0.1 + 0.2avecRealLiteralDataType = Doublemuté →0.30000000000000004(boxing double natif, IEEE 754)Preuve mutationnelle (Tell c.1069 strict honnêteté référentielle ×69ᵉ) : sous mutation
context.Options.RealLiteralDataType = RealLiteralDataType.Double;àSimpleExpression.cs:54, le test discriminant ÉCHOUE avecExpected: 0,29999999999999999/Actual: 0,30000000000000004— la signature exacte du chemin double natif qui devient indiscernable du chemin decimal promu si le raccourci cast direct est retiré.Vérification
dotnet test MyIA.Trading.Backtester.Tests/MyIA.Trading.Backtester.Tests.csproj --filter "FullyQualifiedName~SimpleExpression"→ 9/9 verts (8 existants + 1 nouveau).dotnet test MyIA.Trading.Backtester.Tests→ 115/115 verts en 1 min 16 s.Tells respectées
../CoursIA-15141-s2)--body-file)origin/main)Suite S2 uniquement
Cette PR traite S2 uniquement. S1 (audit
mparlak/Fleeupstream), S3 (namespace migration), S4 (remplacement CodeDom par Linq.Expressions) restent à traiter en PRs séparées si ai-01 les dispatche.