Skip to content

fix(runtime): stabilize finder waits and untargeted scrolling#119

Merged
drown0315 merged 4 commits into
mainfrom
fix/scenario-runtime-stability
Jul 12, 2026
Merged

fix(runtime): stabilize finder waits and untargeted scrolling#119
drown0315 merged 4 commits into
mainfrom
fix/scenario-runtime-stability

Conversation

@drown0315

Copy link
Copy Markdown
Owner

What Changed

  • Synchronize Finder-backed actions with Flutter frames and poll within a shared timeout budget, allowing tap, type, targeted scroll, and waitFor to handle asynchronous UI updates.
  • Make untargeted scrolling select the unique outermost visible scrollable on the dominant drag axis, avoiding same-axis nested scrollables while allowing cross-axis nesting.
  • Extend the runtime protocol and documentation to cover frame synchronization, Finder Action Budgets, and automatic scroll selection semantics.

Risk Assessment

✅ Low: The Finder polling and primary-scrollable changes are internally consistent, covered across protocol, adapter, runner, and runtime tests, and the previously identified cross-axis nested-scroll issue is resolved without introducing another substantiated defect.

Testing

Focused runtime and runner suites passed, including transient Finder polling, frame-budget handling, and nested/cross-axis scrolling; a real macOS CLI Scenario successfully scrolled to and found an off-screen row, produced report/timeline/log evidence, then failed only at the final environment-dependent Flutter screenshot capture.

Evidence: Live macOS CLI transcript

Scenario: pilot_runtime_scroll (4 steps) 2/4 scroll scroll_target_list ok 124ms 3/4 waitFor wait_for_late_row ok 62ms 4/4 capture capture_logs failed: Flutter screenshot failed for Target Device "macos" with exit code 1.

> Target App Launch
Target Device: macos (macOS, darwin, macOS 26.2 25C56 darwin-arm64)
Selection: --device macos
Entrypoint: lib/pilot_runtime_scroll_demo.dart
Launching Target App Package... elapsed 0s
Launching Target App Package... elapsed 10s
Launching Target App Package... elapsed 20s
Launching Target App Package... elapsed 40s
Launching Target App Package... elapsed 50s
Launching Target App Package... elapsed 70s
Target App launched in 88s
Scenario: pilot_runtime_scroll (4 steps)
1/4 waitFor tt             running
1/4 waitFor tt             ok 121ms
2/4 scroll  scroll_target… running
2/4 scroll  scroll_target… ok 124ms
3/4 waitFor wait_for_late… running
3/4 waitFor wait_for_late… ok 62ms
4/4 capture capture_logs   running
4/4 capture capture_logs   failed after 1415ms: Flutter screenshot failed for Target Device "macos" with exit code 1.
Run report: /Users/drown/.no-mistakes/worktrees/e90d3d1ec8f5/01KXASXF0W38FHHT1RSZEM9C2A/examples/smoke_app/.runs/2026-07-12_10-31_pilot_runtime_scroll/run_report.json
HTML report: /Users/drown/.no-mistakes/worktrees/e90d3d1ec8f5/01KXASXF0W38FHHT1RSZEM9C2A/examples/smoke_app/.runs/2026-07-12_10-31_pilot_runtime_scroll/timeline.html
Evidence: Generated HTML timeline
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>pilot_runtime_scroll timeline</title>
<style>
body {
  margin: 0;
  background: #f6f7f9;
  color: #202124;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

main {
  max-width: 960px;
  margin: 0 auto;
  padding: 32px 20px;
}

.run-summary,
.step {
  background: #ffffff;
  border: 1px solid #d9dde3;
  border-radius: 8px;
  margin-bottom: 16px;
  padding: 20px;
}

.step-heading {
  align-items: center;
  display: flex;
  gap: 12px;
  justify-content: space-between;
}

h1,
h2,
p {
  margin-top: 0;
}

dl {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 8px 16px;
}

dt {
  color: #59616e;
  font-weight: 600;
}

dd {
  margin: 0;
}

.status {
  border-radius: 999px;
  display: inline-block;
  font-size: 13px;
  font-weight: 700;
  padding: 4px 10px;
  text-transform: uppercase;
}

.status-passed {
  background: #d8f5df;
  color: #116329;
}

.status-failed {
  background: #ffe0e0;
  color: #9f1c1c;
}

.status-skipped {
  background: #eceff3;
  color: #4f5b67;
}

.step-failed {
  border-color: #e05b5b;
}

.failure-reason {
  color: #9f1c1c;
  font-weight: 600;
}

.artifacts {
  display: grid;
  gap: 12px;
  list-style: none;
  padding: 0;
}

.artifacts img {
  border: 1px solid #d9dde3;
  display: block;
  margin-top: 8px;
  max-width: 100%;
}

</style>
</head>
<body>
<main>
<header class="run-summary">
<h1>pilot_runtime_scroll</h1>
<p class="status status-failed">failed</p>
<p>Verifies targeted scroll replay through PilotRuntimeAdapter.
</p>
<dl>
<dt>Started</dt>
<dd>2026-07-12T10:31:41.226963Z</dd>
<dt>Duration</dt>
<dd>2768 ms</dd>
</dl>
<p class="failure-reason">Flutter screenshot failed for Target Device &quot;macos&quot; with exit code 1.</p>
</header>
<section class="timeline">
<article class="step step-passed">
<div class="step-heading">
<h2>Step 1: tt</h2>
<span class="status status-passed">passed</span>
</div>
<dl>
<dt>Action</dt>
<dd>waitFor</dd>
<dt>Duration</dt>
<dd>121 ms</dd>
</dl>
</article>
<article class="step step-passed">
<div class="step-heading">
<h2>Step 2: scroll_target_list</h2>
<span class="status status-passed">passed</span>
</div>
<dl>
<dt>Action</dt>
<dd>scroll</dd>
<dt>Duration</dt>
<dd>124 ms</dd>
</dl>
</article>
<article class="step step-passed">
<div class="step-heading">
<h2>Step 3: wait_for_late_row</h2>
<span class="status status-passed">passed</span>
</div>
<dl>
<dt>Action</dt>
<dd>waitFor</dd>
<dt>Duration</dt>
<dd>62 ms</dd>
</dl>
</article>
<article class="step step-failed">
<div class="step-heading">
<h2>Step 4: capture_logs</h2>
<span class="status status-failed">failed</span>
</div>
<dl>
<dt>Action</dt>
<dd>capture</dd>
<dt>Duration</dt>
<dd>1415 ms</dd>
</dl>
<p class="failure-reason">Flutter screenshot failed for Target Device &quot;macos&quot; with exit code 1.</p>
<ul class="artifacts">
<li>
<a href="captures/0004_capture_logs_logs.log">logs</a>
</li>
</ul>
</article>
</section>
</main>
</body>
</html>
Evidence: Structured live run report
{
  "scenario": {
    "name": "pilot_runtime_scroll",
    "totalSteps": 4,
    "description": "Verifies targeted scroll replay through PilotRuntimeAdapter.\n"
  },
  "status": "failed",
  "startedAt": "2026-07-12T10:31:41.226963Z",
  "durationMs": 2768,
  "runDirectory": "/Users/drown/.no-mistakes/worktrees/e90d3d1ec8f5/01KXASXF0W38FHHT1RSZEM9C2A/examples/smoke_app/.runs/2026-07-12_10-31_pilot_runtime_scroll",
  "targetDevice": {
    "id": "macos",
    "name": "macOS",
    "targetPlatform": "darwin",
    "emulator": false,
    "sdk": "macOS 26.2 25C56 darwin-arm64"
  },
  "failureReason": "Flutter screenshot failed for Target Device \"macos\" with exit code 1.",
  "artifacts": [
    {
      "type": "scenario",
      "path": "scenario.json"
    },
    {
      "type": "logs",
      "path": "captures/0004_capture_logs_logs.log",
      "purpose": "capture"
    },
    {
      "type": "stepMetadata",
      "path": "step.json"
    },
    {
      "type": "htmlReport",
      "path": "timeline.html"
    },
    {
      "type": "runReport",
      "path": "run_report.json"
    }
  ],
  "steps": [
    {
      "index": 1,
      "label": "tt",
      "action": "waitFor",
      "status": "passed",
      "durationMs": 121
    },
    {
      "index": 2,
      "label": "scroll_target_list",
      "action": "scroll",
      "status": "passed",
      "durationMs": 124
    },
    {
      "index": 3,
      "label": "wait_for_late_row",
      "action": "waitFor",
      "status": "passed",
      "durationMs": 62
    },
    {
      "index": 4,
      "label": "capture_logs",
      "action": "capture",
      "status": "failed",
      "durationMs": 1415,
      "artifacts": [
        {
          "type": "logs",
          "path": "captures/0004_capture_logs_logs.log",
          "purpose": "capture"
        }
      ],
      "failureReason": "Flutter screenshot failed for Target Device \"macos\" with exit code 1."
    }
  ]
}
Evidence: Captured runtime log
{
  "schema": "pilot_runtime.logs.v1",
  "entries": [
    {
      "timestamp": "2026-07-12T10:31:39.447097Z",
      "level": "info",
      "message": "INFO pilot_runtime_scroll_demo: Pilot Runtime scroll demo started.",
      "source": "debugPrint"
    }
  ],
  "type": "Response"
}
- Outcome: ⏭️ skipped across 1 run (5m14s)

Pipeline

Updates from git push no-mistakes

⏭️ **intent** - skipped

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 1 issue found → auto-fixed ✅
  • ⚠️ packages/pilot_runtime/lib/src/scroll_performer.dart:193 - Drag-start selection excludes points covered by every nested Scrollable, regardless of axis. A vertical outer scrollable covered by a horizontal PageView (or similar nested scrollable) can therefore reject a valid vertical scroll as primaryScrollableUnavailable/notScrollable, even though Flutter's gesture arena would route the vertical drag to the outer widget. Consider excluding only nested scrollables matching the drag's dominant axis, and add a cross-axis nested-scroll test.

🔧 Fix: Allow cross-axis nested scroll drag starts
✅ Re-checked - no issues remain.

⏭️ **Test** - skipped
  • ⚠️ The real macOS Scenario demonstrated scrolling successfully: the scroll Step passed and the subsequent wait found the previously off-screen row. However, the unrelated final capture Step failed because Flutter's macOS screenshot command exited 1, so the complete Scenario did not finish successfully in this environment. Logs, timeline, and run report were still preserved.
  • flutter devices
  • cd packages/pilot_runtime && flutter test test/pilot_runtime_finder_test.dart --plain-name 'untargeted scroll allows a cross-axis nested scrollable'
  • cd packages/pilot_runtime && flutter test test/pilot_runtime_finder_test.dart --plain-name 'untargeted scroll chooses an outer scrollable over a nested one'
  • dart test test/execution/scenario_runner_test.dart --name 'waits for a unique Finder Match before tapping'
  • dart test test/execution/scenario_runner_test.dart --name 'endOfFrame consumes the waitFor timeout budget'
  • cd packages/pilot_runtime && flutter test test/pilot_runtime_finder_test.dart test/pilot_runtime_binding_test.dart test/pilot_runtime_client_test.dart
  • dart test test/execution/scenario_runner_test.dart test/runtime/pilot_runtime_adapter_test.dart
  • cd examples/smoke_app && /Users/drown/development/flutter/bin/dart run ../../bin/flutter_pilot.dart test pilot/pilot_runtime_scroll.yaml --target lib/pilot_runtime_scroll_demo.dart --device macos
  • Inspected the generated run_report.json, HTML timeline, and runtime log; removed generated .runs and nested pubspec.lock artifacts from the worktree
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@drown0315
drown0315 merged commit 7f0dca8 into main Jul 12, 2026
2 checks passed
@drown0315
drown0315 deleted the fix/scenario-runtime-stability branch July 12, 2026 11:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant