Files
recordingtest/docs/contracts/smoke2-gap-fix.evaluation.md
minsung de0ca9876a Orchestrate smoke 2차 gap fix evaluation + close #12
- 4 gaps (player resolver, type target, window filter, UTF-8 BOM-less) all pass
- 71/71 tests, regression traps verified
- Ready for smoke 2회차 live validation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 20:34:57 +09:00

4.7 KiB

Evaluation — smoke2 gap fix (issue #12)

  • Commit graded: 8784fec
  • Evaluator: independent session (Opus 4.6 [1m])
  • Date: 2026-04-07
  • Note: Issue #12 used a free-form issue body instead of a Sprint Contract (docs/contracts/smoke2-gap-fix.md does not exist). Acceptable per CLAUDE.md §0.1 for follow-up bug fixes, but recorded here.

Verdict: PASS

Verdict table

Item Required Observed Status
Build 0 warn / 0 err (TWAE) Clean, 0/0 pass
Tests total 71 pass / 0 fail / 0 skip 71 pass / 0 fail / 0 skip (16+10+17+5+5+6+6+6) pass
Gap A — full path resolver UiaPathParser splits /, parses (Class, AutomationId?, Name?); IUiaTreeNode adapter; descend chain id→name→class; bounded fallback; UiaPlayerHost wired; null on miss All present. UiaPathParser.cs quote-aware split, attribute parser. IUiaPathResolver.cs defines IUiaTreeNode + UiaPathResolver with MatchRoot + FindChild + DescendantsBounded(maxDepth:4) documented fallback. Matches priority AutomationId > Name > ClassName. UiaPlayerHost.ResolveElement uses UiaPathResolver.Resolve(new FlaUiTreeNode(window), uiaPath) via Retry.WhileNull, returns null on miss (engine handles throw). Old ExtractAutomationId shortcut removed. pass
Gap B — type target inheritance _lastFocusPath / _lastMousePath state; FlushType fallback chain (typeRes → focus → mouse) DragCollapser adds lastFocusPath + lastMousePath locals (line 46-47); FlushType fallback typeRes ?? lastFocusPath ?? lastMousePath (line 72); focus_change updates lastFocusPath (line 332); mouse_down_l/r updates lastMousePath from downRes (line 128, 188). pass
Gap C — window filter ShouldKeep; mouse uses WindowFromPoint; key uses GetForegroundWindow; wired to SUT pid in Program WindowFilter.cs: IWindowFilter, PassThroughWindowFilter, SutProcessWindowFilter with two pluggable lookups. Mouse path → processFromPoint, key path → processFromForeground, focus_change always kept, pid==0 permissive. Program.cs lines 87-107 wires SutProcessWindowFilter to app.ProcessId using WindowFromPoint+GetWindowThreadProcessId and GetForegroundWindow. LowLevelHook exposes mutable Filter and applies it in both Keyboard/Mouse procs. pass
Gap D — UTF-8 BOM-less Explicit UTF8Encoding(false); round-trip test with Korean strings + no BOM ScenarioWriter.WriteToFile line 43-44: new UTF8Encoding(encoderShouldEmitUTF8Identifier: false). Round-trip test ScenarioWriter_RoundTrip_PreservesKorean asserts byte[0..2] != EF BB BF and Korean Name/Description/Path round-trip. pass
Thread.Sleep in PlayerEngine 0 0 (grep) pass
EG-BIM Modeler writes none none pass

Regression-trap analysis

New test Would have failed pre-fix? Why
UiaPathParser_ParsesMultiSegment_WithClassAndId yes — UiaPathParser did not exist Compile-trap
UiaPathParser_ParsesNameAttribute yes Compile-trap
UiaPathResolver_Descend_FindsNestedElement yes Compile-trap; also exercises chain descent
UiaPathResolver_LastSegmentWithoutId_UsesClassName yes Validates ClassName fallback in Matches
UiaPathResolver_NotFound_ReturnsNull yes Validates null-not-throw contract
SmokeRegression_BoxV4CleanLike_ParsesAndResolves yes — explicitly proves the resolver no longer collapses to "first descendant" (Assert.NotSame) Direct guard against the smoke 1차 bug
DragCollapser_TypeAfterFocusChange_InheritsTarget yes — pre-fix FlushType only used typeRes; with all-null resolver result, Target would be null. Test asserts Target.UiaPath == focusPath. Direct guard for Gap B
DragCollapser_TypeAfterMouseDown_FallbackToMouseTarget yes — same reason; asserts mouse path inheritance Direct guard
WindowFilter_ExternalCoord_DropsEvent yes — SutProcessWindowFilter did not exist Compile-trap; also asserts drop semantics
WindowFilter_SutCoord_KeepsEvent yes Compile-trap; asserts keep + permissive pid=0
ScenarioWriter_RoundTrip_PreservesKorean yes — pre-fix relied on default overload; the explicit byte-level EF BB BF assertion + Korean round-trip would only deterministically pass with the explicit encoder Direct guard for Gap D

All new tests are load-bearing.

Notes

  • docs/guides/smoke-test.md Gap D tip section confirmed (commit diff shows +18 lines).
  • No partial hacks observed; all four gaps are real code-level fixes with unit coverage and reasonable abstractions (pluggable lookups for the filter, pure adapter for the path resolver).
  • Recommend Generator update PROGRESS.md to mark issue #12 done.