- Float epsilon configurable (default 6) pass - JSON-path mask scoping pass with regression trap verified - 77/77 tests, 3 follow-ups marked done Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
39 lines
3.5 KiB
Markdown
39 lines
3.5 KiB
Markdown
# normalizer-followups — Evaluation
|
|
|
|
**Verdict: PASS**
|
|
**Generator commit:** eeee3c2
|
|
**Evaluator date:** 2026-04-07
|
|
|
|
## Verdict table
|
|
|
|
| # | Criterion | Evidence | Result |
|
|
|---|-----------|----------|--------|
|
|
| 1 | `dotnet build recordingtest.sln` — 0 warn / 0 err | Build succeeded, 0 Warning(s), 0 Error(s) | pass |
|
|
| 2 | `dotnet test` total 77 pass | 16+17+16+5+5+6+6+6 = 77 passed, 0 failed | pass |
|
|
| A1 | `Profile.FloatDecimals` int? with YAML alias `float_decimals` | `Profile.cs:14-15` `[YamlMember(Alias="float_decimals")] public int? FloatDecimals` | pass |
|
|
| A2 | `RoundFloatsInNode` accepts decimals parameter | `Rules.cs:102` `RoundFloatsInNode(JsonNode?, int decimals)` + default overload using `DefaultFloatDecimals` | pass |
|
|
| A3 | `DefaultFloatDecimals = 6` | `Rules.cs:97` `public const int DefaultFloatDecimals = 6` | pass |
|
|
| A4 | Profile decimals flows via `Normalizer` | `Normalizer.cs:95` `profile.FloatDecimals ?? Rules.DefaultFloatDecimals` | pass |
|
|
| A5 | Omitted `float_decimals` defaults to 6 | Test `Profile_OmittedFloatDecimals_DefaultsTo6` asserts `profile.FloatDecimals == null` and output rounds to 3.141593 | pass |
|
|
| A6 | Configurable decimals actually applied | Test `RoundFloats_ProfileWithDecimals3_RoundsTo3` writes temp profile, expects 3.142 | pass |
|
|
| B1 | `ParseJsonPathLite` exists, rejects `*` and `[...]` | `Rules.cs:200-222` throws on wildcards/indexers, requires leading `$.` | pass |
|
|
| B2 | `MaskVolatileSettings(node, paths)` walks with path stack | `Rules.cs:227-289` pre-parses allowlist, maintains `stack` list, exact-chain compare in `PathMatches()` | pass |
|
|
| B3 | `DefaultVolatileSettingPaths` has 16 entries | `Rules.cs:176-194` — counted 16 paths | pass |
|
|
| B4 | `default.yaml` migrated to list form | `profiles/default.yaml:10-26` — YAML sequence of 16 `$.<path>` strings; `float_decimals: 6` present | pass |
|
|
| B5 | Regression trap: `SameNameInUnrelatedSubtree_NotMasked` | `RuleTests.cs:174-183` — input `{"GridSnap":true,"Foo":{"GridSnap":false}}` with `["$.GridSnap"]`; asserts root masked and `n["Foo"]["GridSnap"].GetValue<bool>() == false`. Pre-fix name-based fallback would have masked both, causing `GetValue<bool>()` to throw InvalidOperationException on `<VOLATILE>` string → test is load-bearing | pass |
|
|
| B6 | Nested path mask works | `MaskVolatileSettings_NestedPath_MasksCorrectly` — `$.GridColor.R` masks only R, leaves G | pass |
|
|
| B7 | Root mask works | `MaskVolatileSettings_RootField_Masks` | pass |
|
|
| B8 | No leftover `VolatileSettingFieldNames` fallback | Grep in `src/` — no matches anywhere | pass |
|
|
| 9 | CoverageTests still green | Normalizer.Tests dll 16 passed (includes coverage tests) | pass |
|
|
|
|
## Notes
|
|
|
|
- Regression trap load-bearing: confirmed. The old `VolatileSettingFieldNames.Contains(kv.Key)` approach would mask both `GridSnap` occurrences → nested `.GetValue<bool>()` on a `"<VOLATILE>"` JsonValue would throw. The test would fail loudly.
|
|
- Test count for Normalizer.Tests went from 10 → 16 as claimed (6 new tests present and accounted for).
|
|
- Default-on behavior preserved: `default.yaml` both specifies `float_decimals: 6` explicitly AND the omitted-profile test proves the `?? DefaultFloatDecimals` fallback path.
|
|
- Count of `DefaultVolatileSettingPaths`: 16 entries confirmed (CanOverrideWireColorWithFace, IsSidePanelVisible, OverrideFaceColor, Solar_IsLocalTime, VisibleGrid, GridSnap, MidpointOsnap, GridSpacing, GridColor.{ALPHA,BLUE,GREEN,RED}, MajorGridColor.{ALPHA,BLUE,GREEN,RED}).
|
|
|
|
## Partial / gaps
|
|
|
|
None. Both follow-ups are complete with no residual fallback code.
|