- recorder v1 (fail) → v2 (pass): drag state machine, focus events, ts/raw_coord - player pass with caveats: reliability untestable in sandbox - PROGRESS.md Done rows + follow-ups for live SUT smoke test - PLAN.md P1 pivoted to test-runner + live smoke test Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
4.7 KiB
4.7 KiB
Recorder — Evaluation (v2)
- Generator commit:
56b7233 - Build:
dotnet build recordingtest.sln→ green (0 warnings, 0 errors) - Tests:
dotnet test tests/Recordingtest.Recorder.Tests→ 9 passed / 0 failed / 0 skipped - Evaluator: independent re-read of source + tests after Generator iteration 2
- Previous evaluation archived at
docs/contracts/recorder.evaluation.v1.md
Verdict table
| # | DoD item | Verdict | Evidence |
|---|---|---|---|
| 1 | Console attach to SUT + 입력 캡처 시작 | pass (source) / untestable (live) | Program.TryAttach attaches by pid or by window-title scan via Application.Attach; never Launch(). LowLevelHook installs WH_KEYBOARD_LL + WH_MOUSE_LL on a dedicated STA thread. Cannot exercise against EG-BIM Modeler in this sandbox. |
| 2 | 캡처 이벤트: 키 down/up, 클릭/드래그/휠, 포커스 변경 | pass | LowLevelHook emits key_down/up, mouse_down_l/r/m, mouse_up_l, wheel, move. DragCollapser is a real state machine: on mouse_down_l it stores the down event and tracks max distance through moves; on mouse_up_l it picks drag if max(maxDistSq, finalDistSq) >= threshold² else click. Right-click and key/wheel paths emit their own steps. Program.cs calls automation.RegisterFocusChangedEvent(...), builds an UIA path inside the callback (try/catch-guarded) and pushes a synthetic focus_change RawEvent into the same channel; DragCollapser translates it to a focus ScenarioStep. |
| 3 | Event shape {ts, kind, uia_path, offset_norm, raw_coord, value} |
pass | RawEvent carries TimestampMs, Kind, X, Y, Code, WheelDelta, FocusedElementPath. ScenarioStep now exposes Ts, RawCoord, EndOffset, EndRawCoord plus existing Kind/Target{UiaPath,Offset}/Value/WaitFor. DragCollapser populates Ts and RawCoord (and end variants for drags) on every emitted step. |
| 4 | 3D viewport offset_norm ∈ [0..1] |
pass | OffsetNormalizer.Normalize clamps each axis to [0,1]; covered by OffsetNormalizer_ClicksInsideElement_ReturnsZeroToOne. |
| 5 | Yaml schema 준수 | pass | ScenarioWriter uses UnderscoredNamingConvention; ts and raw_coord therefore serialize as snake_case. ScenarioStep_YamlRoundtrip_PreservesTsAndRawCoord asserts both ts: and raw_coord appear in the yaml and round-trip back to identical values. YamlSerializer_RoundtripsScenario covers click + masked-type. |
| 6 | 비밀번호/토큰 마스킹 | pass | MaskPolicy.Apply returns <MASKED> for IsPassword or ClassName == "PasswordBox". DragCollapser calls MaskPolicy.IsMasked on the resolved snapshot for both click and key paths and overrides step.Value = MaskPolicy.MaskedValue. Unit covered by FocusedElementIsPassword_ReturnsMasked. |
| 7 | 60 FPS 영향 없음 | untestable | Requires running SUT + perf measurement; not possible in sandbox. Architecture (separate STA hook thread + unbounded Channel, UIA resolution moved out of the hook callback) is consistent with the requirement. Explicitly deferred. |
| 8 | 종료 시 요약(이벤트 수, 소요 시간, 미결 건수) | pass | Program.Run writes [recorder] done. events={count} elapsed={sw.Elapsed} unresolved_paths={unresolved} on Ctrl+C exit. |
Tests (9)
ElementPathBuilder_WithNestedElements_ReturnsFullPathOffsetNormalizer_ClicksInsideElement_ReturnsZeroToOneFocusedElementIsPassword_ReturnsMaskedYamlSerializer_RoundtripsScenarioCli_MissingAttach_ExitTwoDragCollapser_DownMoveUp_BeyondThreshold_EmitsDrag(new — drag emit beyond threshold)DragCollapser_DownUp_BelowThreshold_EmitsClick(new — click emit below threshold)DragCollapser_FocusChangeEvent_EmitsFocusStep(new — focus_change → focus step)ScenarioStep_YamlRoundtrip_PreservesTsAndRawCoord(new — yaml ts + raw_coord)
All four iteration-2 tests are present, meaningful, and assert the previously-missing behavior (state machine threshold, focus translation, snake_case persistence).
Configurable threshold
DragCollapser constructor: public DragCollapser(int dragThresholdPx = 4) and stored on DragThresholdPx. Default 4 px as required.
Remaining items
- DoD #1 live attach + DoD #7 perf: structurally untestable in this sandbox; deferred to manual smoke on a workstation with EG-BIM Modeler. Source-side wiring is correct. These are no longer "missing code" — they are environment-bound.
- IME (한글 조합) handling: still not implemented; this is a contract Risk, not a DoD item.
Overall verdict
pass — all DoD items with code obligations are satisfied; the only non-pass cells (1 live, 7) are explicitly deferred as untestable in the sandbox, not missing code. v1 release gates (drag collapse, focus capture, ts+raw_coord persistence, drag-state-machine tests) are all closed.