- 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>
4.7 KiB
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.mddoes 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.mdGap 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.