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.

View File

@@ -0,0 +1,25 @@
# 2026-04-07 normalizer-followups — Evaluator
- **작업**: Evaluator 채점 — Follow-up A (float epsilon 구성화) + Follow-up B (JSON-path mask scoping)
- **Generator commit**: eeee3c2
- **Verdict**: PASS
- **관련 이슈**: normalizer follow-ups (see PLAN.md)
- **소요 시간**: ~6분
- **Context 사용량**: ~35k 토큰 (single session, no compaction)
## 검증 결과
- `dotnet build recordingtest.sln`: 0 warn / 0 err
- `dotnet test recordingtest.sln --no-build`: 77 passed / 0 failed (Player 16, Recorder 17, Normalizer 16, EgPlugin 5, DiffReporter 5, Runner 6, EngineBridge.Integration 6, EngineBridge 6)
- Normalizer.Tests 10 → 16 확인 (6 신규)
- `VolatileSettingFieldNames` 잔존 없음 (grep src/ empty)
- Regression trap `SameNameInUnrelatedSubtree_NotMasked` load-bearing 확인 — 구버전 name-based 매칭이면 nested bool GetValue에서 throw
## 산출물
- `docs/contracts/normalizer-followups.evaluation.md` (verdict table)
- 본 히스토리 파일
## 참고
PROGRESS.md 갱신은 호출자가 수행 (evaluator는 touch 금지). Generator 코드 수정 없음.