Skip to content

Release sleuth 0.37.0 and sleuth_mcp 0.8.0 - #8

Merged
Harrys76 merged 240 commits into
mainfrom
wp14/mcp-sidecar-hardening
Oct 6, 2026
Merged

Harrys76 merged 240 commits into
mainfrom
wp14/mcp-sidecar-hardening

Conversation

@Harrys76

@Harrys76 Harrys76 commented Oct 6, 2026 •

Copy link
Copy Markdown
Owner

This PR brings 16 stacked branches into main: everything that ships as sleuth 0.37.0 and sleuth_mcp 0.8.0. The versions on pub.dev are sleuth 0.36.0 and sleuth_mcp 0.7.2. CHANGELOG.md (0.37.0) and packages/sleuth_mcp/CHANGELOG.md (0.8.0) have the summaries; the full notes are in doc/release_notes/0.37.0.md and packages/sleuth_mcp/doc/release_notes/0.8.0.md.

How to merge

  • Use Create a merge commit, not squash. It keeps the 240 commits on main, so git bisect can find a regression to one commit.
  • Most of the diff (+108k / −40k lines, 495 files) is tests (+52k) and one formatter commit, 0215afe (285 files). .git-blame-ignore-revs lists that commit, so GitHub's blame skips it.
  • After the merge, publish both packages from main and tag them. pub publish --dry-run reports 0 warnings for both.

Branches, in stack order

Branch Commits What it changes
wp1/flutter-347-compat 9 Flutter 3.47 scan fix, Dart 3.8 / Flutter 3.32 floors, tall-style format, CI on 3.32.8 and 3.47.6
wp2/docs-text-correctness 10 Encyclopedia, fix hints and guides match what the detectors do
wp3/ranking-causal-integrity 7 Confidence-weighted ranking, causal rule corrections
wp4/frame-budget-plumbing 5 Jank budget from the measured refresh rate
wp5/structural-fp-trims 11 Fewer false positives in the structural detectors
wp6/dead-on-device-detectors 6 Shader and platform-channel detectors work on devices
wp7/scan-loop-overhead 10 Cheaper scan loop, serial benchmarks
wp4b/raster-dominance-per-frame 6 Per-frame raster dominance without a VM link
wp5b/structural-new-signals 17 Painter names, sliver boundaries, measured image waste, non_lazy_shrinkwrap
wp8b/device-pass-followups 11 GC floor, memory budget, jank reset on navigation, demos
wp9/vm-axis-duration 2 Rebuild and repaint measured as a share of UI time, nine captures
wp10/vm-poll-overhead 12 Incremental timeline reads, poll timings in diagnose
wp11/overlay-core 8 Back handling, saved overlay state, hide, copy, filters
wp12/a11y-scaling-theme 18 Text scaling, screen readers, contrast, themes
wp13/ai-chat-example-polish 76 AI chat states, example app, review fixes, capture checks, docs audit
wp14/mcp-sidecar-hardening 32 MCP fixes and new tools, plain-language pass, changelog fold, shorter READMEs and changelogs with linked guides, new pub.dev screenshots

Sleuth package

  • Flutter 3.47. Scans no longer abort in bottom-navigation apps. Minimum versions are Dart ^3.8.0 and Flutter >=3.32.0.
  • Accuracy.
    • Issues rank by severity weighted by confidence, and the causal graph has 41 corrected rules.
    • The jank budget follows the refresh rate.
    • Profile rebuild and repaint cards measure the share of UI-thread time.
    • Debug cards count only the app's widgets, and a repaint card names the likely origin of a layer's repaints.
    • Cards near a threshold hold instead of blinking.
    • The shader and platform-channel detectors work on real devices.
  • Sleuth's own cost. The VM timeline is read incrementally. The poll stall on the capture screen fell from 117 ms to 6.6 ms on an iPhone 12.
  • Overlay.
    • Back handling and saved state.
    • Hide with Undo, Copy and severity filters.
    • Text scaling, screen-reader support, high-contrast themes and reduced motion.
  • AI chat. Reply states, Stop and Retry, timeouts, and history that survives closing the dashboard.
  • Validation and docs. Capture screens refuse a leg with missing provenance or a value out of band. The StreamResource triad is re-recorded on Flutter 3.47. Docs and user-facing text are checked against the code and written in plain language.

Sleuth MCP

  • Correct data.
    • compare_snapshots refuses mismatched versions, coverage or warm-up snapshots, and compares per issue id.
    • check_budgets and sleuth_check refuse a session with no VM link.
    • get_issues no longer calls a connected session degraded.
  • Client budget. A plain get_snapshot returned 10 KB instead of 285 KB on an iPhone 12, and full: true returns everything.
  • New.
    • get_logs.
    • Progress and cancel for attach_app.
    • connected / connectedVia in app_status.
    • Hot restarts are followed.
    • connect accepts the http:// URI that flutter run prints.
    • initialize returns instructions.
  • Reliability.
    • With --uri, a reload used to freeze the sidecar.
    • Two crash paths are fixed, and exit is bounded.
    • Timeouts keep the session.
    • detach_app works in every state.
    • connect is refused over a live attach.
    • External processes are owned and killed.

Changes users will notice

  • Profile rebuild and repaint cards use a percentage of UI time. Their numbers and thresholds differ from 0.36, and setBaseline is removed.
  • heap_near_capacity stays off until memoryBudgetBytes is set.
  • Debug repaint cards are titled "Likely Repaint Origin" and are likely.
  • Some overlay titles, sidecar messages and tool descriptions are reworded. MCP error-code prefixes are unchanged.

Verification

  • flutter analyze, the format check and dart doc are clean.
  • 4,296 package tests, the Flutter 3.32.8 floor run, 125 example tests, 653 sidecar tests and 40 serial benchmarks pass.
  • Checked on an iPhone 12 (iOS 17.5):
    • repaint cards;
    • capture legs and provenance;
    • the compact snapshot, get_logs and get_issues;
    • the reload freeze fix, connect refusal, cancel and detach during an iOS attach, and hot-restart following.
  • Covered only by tests: Windows process handling.
  • Not checked: Android attach behaviour.

🤖 Generated with Claude Code

Harrys76 and others added 30 commits October 2, 2026 12:40
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Flutter 3.47 IndexedStack no longer wraps inactive children in
Visibility, so every tab's Scaffold surfaced as a sibling and the
multi-scaffold guard aborted each scan. Descend into RenderIndexedStack
elements via their onstage visitor so only the selected child is walked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…guesses

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…fects

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd fpsTarget

Adds FrameBudget, FrameRateSource, and resolveFrameBudget. The effective
rate is the measured vsync cadence clamped to [fpsTarget, display rate];
without a measurement it stays at fpsTarget. SleuthConfig.autoFrameBudget
(default true) opts out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ames

measuredCadenceHz is 1e6 over the 10th percentile of the last 120 valid
vsyncStart deltas, available after 30 samples. Idle gaps longer than two
fpsTarget frames are ignored. reset() clears the estimate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…thresholds

FrameStats gains frameBudgetUs and classifies jank in microseconds.
FrameTimingDetector, GpuPressureDetector, and HeavyComputeDetector take
the controller's resolved budget through updateFrameBudget; constructor
defaults are unchanged. Above fpsTarget the raster floor and the auto
heavy-compute threshold become half the budget; at fpsTarget they keep
8000 us and 8 ms. Capture mode always resolves the fixed budget.
DetectorThresholds.heavyComputeGapMs defaults to null (auto). The
overlay reports the display refresh rate, and ext.sleuth.diagnose adds
effectiveFrameRateHz, frameBudgetUs, and frameRateSource.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… fired

HeavyComputeDetector and PlatformChannelDetector stamp the controller's
interaction state at emission, and the aggregate stamp no longer
overwrites it, so an issue raised during navigation still reads
navigating after the transition ends. IssueRanker treats navigating like
scrolling and app-lifecycle (recurrence weighted 0.7). Nothing is
suppressed while navigating.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Harrys76 and others added 18 commits October 6, 2026 15:51
A hot restart that replaces the app's isolate is followed. When a call
gets a Collected or Expired sentinel, the bridge picks the app's new main
isolate under the connect lock, waits for it to register
ext.sleuth.diagnose, runs the version check and reports session_changed
once. When no isolate registers it in time, the call fails with the next
step instead of "Sleuth package not initialized".

connect and disconnect start a new connection epoch before they take the
lock. A reconnect or isolate follow that a call started earlier gives up
when the epoch changed, so it never undoes a detach or a newer connect.

SessionChangedException.followed says whether the bridge now follows the
new session; a follow that could not read the new session keeps the old
baseline and reports false.

get_logs: the log resolver keeps the string's length, so a message longer
than 2000 characters stays marked truncated. At most 4 cut messages are
read at once; the rest keep their 128-character prefix, marked truncated.
Lines carry the connection's AppLogEpoch; a disconnect or a connect to
another URI ends it, and the bridge and AppLogBuffer drop lines of an
ended epoch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…come

The message says the sidecar follows the new session only when the
bridge followed it, and says it does not follow yet when the new
session could not be read. Docs describe the hot-restart follow and the
get_logs clearing on a new connection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A detach timeout closed the daemon RPC channel while a call still waited
for flutter to read its stdin, so the close error had no listener and
the sidecar exited. DaemonRpc now marks each call's completer as handled
before the write, ends a pending write when the channel closes, and
settles every call in flight on close.

The iOS pipeline ran devicectl through Process.run with a timeout, so a
timeout or a cancel left the child running, and the cancel was seen only
after that wait. Every command of the attach now runs through an owned
runner that kills and reaps the child on timeout and cancel, the cancel
interrupts every wait, and the Bonjour browse ends dns-sd when its
listener stops.

On Windows flutter runs under cmd.exe, so the session ends the whole
tree with taskkill /T /F. The flutter devices check is owned the same
way and reads its output for a bounded time after a kill.

Each attach has its own cancel signal that detach_app and the shutdown
detach fire, and the detach waits, bounded, for the attach to end its
commands, so a cancelled iOS attach no longer blocks the next one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…andoff cleanup

connect over a live attach_app session pointed the bridge at another app
while hot_reload kept reloading the attached one. connect now refuses
with attached_session while an attach is running or ready, or still
holds its flutter child or iOS tunnel, and names detach_app as the step.

check_budgets and sleuth_check ask the app for currentIssues and
frameStatsSummary only, with no issue cap, instead of the full snapshot.

The disk handoff stops writing once the exit cleanup ran, writes nothing
for a request the client already cancelled, returns disk_handoff_failed
when the file cannot be written, and the startup sweep deletes aged
handoff files of a sidecar whose process is gone. detach_app deletes the
files without closing the handoff.

The tool schema docs and the README describe the new error codes, the
owned commands of an attach and the Windows process tree kill.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…; serve comment and background sweep

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
get_logs reported capturing: none for about a second after connect and
could miss output from that window. connect now waits up to 2 s for
the Stdout, Stderr and Logging subscriptions; a slow one finishes in the
background.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dashes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n style

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sentence-case titles; network rationale states the raised critical tier

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…otes reworded messages

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
0.37.0 was never published, so everything under Unreleased ships in it.
The superseded CustomPaint paint-rate bullet is dropped (the folded entry
describes the likely-origin rate), and the 48 dp list no longer includes
the header highlight checkbox, which is 36 x 48.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GitHub reads .git-blame-ignore-revs, so blame on the release diff shows
the change that last touched a line instead of the reformat.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cleanly

On Dart 3.8 the async closure made the chain a Future<Null>, and the
analyzer reported invalid_return_type_for_catch_error for the void error
handler, which failed the 3.32.8 sidecar CI job. The chain is now an
explicit Future<void>. Analyze and all 653 sidecar tests pass on Dart
3.8.1 (Flutter 3.32.8) and on Flutter 3.47.6.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Harrys76 Harrys76 self-assigned this Oct 6, 2026
@Harrys76 Harrys76 added bug Something isn't working enhancement New feature or request labels Oct 6, 2026
Harrys76 and others added 7 commits October 6, 2026 17:59
- Retake the dark and light overlay screenshots on an iPhone 12 (profile,
  Chat App demo) so they show the 0.37 overlay.
- Both READMEs: a --no-dds session is checked with vmConnected, since
  connectionMode stays basic until the first jank frame gets a VM-tier
  verdict.
- Root README: test badge 4,296, Flutter badge 3.32+, sleuth_mcp link to
  pub.dev.
- sleuth_mcp README: measured VM poll cost in place of "negligible",
  sleuth link to pub.dev.
- pubspec screenshot captions: no em dashes; the overlay follows the
  platform brightness, not the host app theme.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
/tool/ holds the capture-wrapping CLI and the local VM-service helper,
which need the repo's test captures and docs. packages/ stays in: pub
applies the root .pubignore when publishing packages/sleuth_mcp too, so
excluding it here would empty the sleuth_mcp archive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The README keeps one paragraph that links to doc/accessibility.md, which
holds the screen reader, text size, touch target, contrast, high contrast,
reduced motion and keyboard notes unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Setup, options, one line per tool, reading results and errors,
attaching, connection modes, the CI gate and limitations stay; argument,
error-code and process details point to doc/mcp_tool_schema.md, which
already covers them. Adds that attach_app(device:) runs flutter attach in
the sidecar's working directory.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The README keeps a short Why Sleuth, the quick start (now with the
install line and --no-dds), what Sleuth finds, how it works, the debug
and profile table, reaching full mode, common configuration, AI chat
setup, MCP, custom detectors, sessions and export, confidence and
ranking, and limitations.

Moved, not removed:
- doc/configuration.md: every option, suppressing issues, the state
  store, platform-channel profiling, debug callbacks, theming.
- doc/overlay.md: the FPS number, severity filter, hiding cards,
  keep-alive ids, card order, system back and Escape.
- doc/ai_chat.md: replies, timeouts, failure reasons, what is sent.
- doc/internals.md: VM connection (reconnect ladder, DDS, launch
  commands) and route sessions.

The sidecar README links the launch commands in internals, and the
recurrence badge comment points at doc/internals.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dark: the Chat App demo with eight issues across severities and
confidence levels. Light: the same dashboard with one card expanded to
its measured detail, route, evidence and causes. Captured on an iPhone 12
in profile mode with --no-dds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nked

Each changelog section now lists breaking and behavior changes first,
then what was added and fixed. The previous detailed text moves
unchanged to doc/release_notes/0.37.0.md and
packages/sleuth_mcp/doc/release_notes/0.8.0.md, linked from each section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Harrys76
Harrys76 merged commit 4f4e3c5 into main Oct 6, 2026
5 checks passed
@Harrys76
Harrys76 deleted the wp14/mcp-sidecar-hardening branch October 6, 2026 13:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant