From 2428827df6511a1a5f7ee9f0088266f2b5af35b6 Mon Sep 17 00:00:00 2001 From: minsung Date: Tue, 7 Apr 2026 20:45:04 +0900 Subject: [PATCH] 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) --- PROGRESS.md | 10 +++-- .../normalizer-followups.evaluation.md | 38 +++++++++++++++++++ ...26-04-07_normalizer-followups-evaluator.md | 25 ++++++++++++ 3 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 docs/contracts/normalizer-followups.evaluation.md create mode 100644 docs/history/2026-04-07_normalizer-followups-evaluator.md diff --git a/PROGRESS.md b/PROGRESS.md index f07a8c4..54c99a2 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -39,6 +39,8 @@ | 2026-04-07 | Smoke gap fix + Evaluator pass (#11) — STAThread, KeyTranslator, 60 tests, regression trap 검증 | commit `139fbbc` | | 2026-04-07 | Smoke test 1회차 — recorder PID attach + UIA target 정상 (box-v4), player 재생 부분 실패 | `docs/history/2026-04-07_smoke-1회차-결과.md`, scenarios/box-v4*.yaml | | 2026-04-07 | Smoke 2차 gap fix + Evaluator pass (#12) — full-path resolver, type target inheritance, window filter, UTF-8 BOM-less, 71 tests | commit `8784fec` | +| 2026-04-07 | sut-prober snake_case + scaffolding review 1회차 | commit `0f0324e` | +| 2026-04-07 | normalizer follow-ups + Evaluator pass — float epsilon 구성화 + JSON-path 마스크 스코핑, 77 tests | commit `eeee3c2` | ## In progress @@ -50,10 +52,10 @@ _(없음)_ ## Follow-ups -- [ ] sut-prober JSON naming을 `JsonNamingPolicy.SnakeCaseLower`로 변경 (contract 엄격 준수). non-blocking. -- [ ] diff-reporter: 실제 `diff-triager` 에이전트 통합 테스트 (현재 schema 단위 테스트로 대체, DoD #8 partial). non-blocking. -- [ ] normalizer: `mask_volatile_settings` 규칙을 JSON-path 스코핑으로 제한 (현재는 필드명 전역 매칭). non-blocking risk. -- [ ] normalizer: float epsilon 구성화 (현재 6 decimals 하드코딩). contract risks 섹션. +- [x] ~~sut-prober JSON naming snake_case~~ — commit `0f0324e` +- [x] ~~normalizer: mask_volatile_settings JSON-path 스코핑~~ — commit `eeee3c2` +- [x] ~~normalizer: float epsilon 구성화~~ — commit `eeee3c2` +- [ ] diff-reporter: 실제 `diff-triager` 에이전트 통합 테스트. non-blocking. - [ ] recorder/player: **라이브 SUT 수동 smoke test** — 60 FPS / 10회 중 9회 reliability DoD는 샌드박스 unit test 불가, 실제 환경에서 검증 필요. - [ ] player: `wait_for` UIA 이벤트 매핑 강화 (현재 host passthrough). - [ ] player: `UiaPlayerHost` uia_path resolver가 마지막 `@AutomationId`만 사용 — 전체 ancestor chain 지원 필요. diff --git a/docs/contracts/normalizer-followups.evaluation.md b/docs/contracts/normalizer-followups.evaluation.md new file mode 100644 index 0000000..d9c784d --- /dev/null +++ b/docs/contracts/normalizer-followups.evaluation.md @@ -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 `$.` 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() == false`. Pre-fix name-based fallback would have masked both, causing `GetValue()` to throw InvalidOperationException on `` 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()` on a `""` 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. diff --git a/docs/history/2026-04-07_normalizer-followups-evaluator.md b/docs/history/2026-04-07_normalizer-followups-evaluator.md new file mode 100644 index 0000000..68cad10 --- /dev/null +++ b/docs/history/2026-04-07_normalizer-followups-evaluator.md @@ -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 코드 수정 없음.