Orchestrate normalizer follow-ups evaluation + update PROGRESS

- 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>
This commit is contained in:
minsung
2026-04-07 20:45:04 +09:00
parent eeee3c2a03
commit 2428827df6
3 changed files with 69 additions and 4 deletions

View File

@@ -0,0 +1,38 @@
# 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.