Repository navigation
Overlay data for the 1.0.0 card - #22
Merged
Merged
Conversation
- FrameVerdict.relatedIssues keeps only the issues that can explain the verdict's phase: the phase's category, event_loop_stall for a start delay, none for a stall. Jank symptoms are never listed, and the JANK tag shows only while jank_detected or sustained_jank is reported. - An internal coverage report and run state for the coming status lines: which checks run, need the VM or an opt-in, the warm-up phase, and the reconnect attempt. The debug banner dismissal moves to the controller for the session. - The highlight lookup returns found, not found or pending. It matches the issue's own element first (WidgetHighlight.occurrenceId), then the widget name, and no longer outlines another widget of the same category. A not-found card unticks instead of outlining later. - Not useful marks: a session store in the controller, NotUsefulMark, and an always-on notUsefulMarks key on the snapshot and ext.sleuth.issues. The schema documents it and the issue measurement shape, with presence tests driven by a real detector emission. The sidecar lists the key in snapshotMetadataKeys. - DebugSnapshot.forcedRebuildsOf records which widget's build forced each parent-driven rebuild, framework widgets included. - leafSourceLocation reads the leaf file:line of an ancestor chain. The snapshot copy counts as Sleuth's own work and ignores a second tap. No detection decision changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The overlay builds inside the app's frames, outside Sleuth's own-work log, so extra card builds raise the app's rebuild_activity share. The benchmark pumps 20 issues, collapsed and with three expanded, through 50 scan ticks without a change and 50 with a title change, and fails when FloatingIssuesCard or IssueCard builds more often than the counts recorded before the card redesign. Build time is printed, not asserted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The selected highlight follows its own element when the scan or a rect refresh republishes highlights. Before, it moved to the first widget of the same name and detector, and to a sibling when its element left; now it clears instead. - A pending lookup selects after the first scan even without a result callback. The null-aware call skipped the lookup itself. - The debug rebuild hook keys the forced-rebuild map by Type and names the types once per snapshot. With 200 forced rebuilds a frame, frame time is within measurement noise of the hook before the map (median 1,366 vs 1,347 us over five interleaved runs). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 19, 2026
SourceLocationCache kept one location per widget type, so a type built in several places reported the first place it resolved. On an iPhone the Rebuild Hotspot screen's ValueListenableBuilder<int> showed high_level_setstate_demo.dart:75, and the card's Where row and its Copy gave that line. The cache now keeps one entry per element in an Expando. Each element reports its own call site, and entries go with their elements. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The first lookup fell back to the widget name when the issue's own element had no highlight, for instance after a scroll dropped it. With two ListViews, the crosshair on the first list's card then outlined the second list, and the outline stayed on it after the first came back. An issue with an occurrence id now takes that element's highlight or none, as the re-acquire path already does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The card tagged only the issues the latest verdict named. Late frames alternate between phases, and a raster or start-delay frame names no build issue, so on a busy screen the tag went on and off about once a second (23 changes in 30 s on FPS Stress, Galaxy A07). The controller now notes when a verdict last named each issue, and heldJankCauses returns those named within the 10 s jank window jank_detected judges, with the time until the first one leaves. The card tags the held issues while a jank symptom is reported and arms one timer for the next expiry. The hold lives in the controller, so closing and reopening the dashboard neither drops it nor restarts it, and a route change clears it, as it starts a new jank window. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Second PR of the 1.0.0 overlay stack, on top of #21. It adds the data the redesigned card and status lines will read. The overlay's look does not change yet, and no detection rule changes.
What changes
FrameVerdict.relatedIssueskeeps only the issues that can explain the verdict's phase: the issues of that category,event_loop_stallfor a start delay, none for a stall or an unknown phase. Jank symptoms are never listed. The card shows the tag only whilejank_detectedorsustained_jankis in the reported list, so the tag leaves when the jank does, even though the last verdict stays. Before, every card matched because the verdict listed every issue.CoverageReportcounts which checks run, need the VM, run in part, or need an opt-in. Default config: 11 on, 6 need the VM and 3 run in part without it; 19 on and 2 opt-ins off with it.runStateNotifiermoves from starting to warming up to running and carries the reconnect attempt (n of 7) and "stopped retrying". The debug banner dismissal now lives in the controller for the session.selectHighlightForIssuereturns found, not found or pending. It matches the issue's own element first, through the newWidgetHighlight.occurrenceIdthat the detectors stampingPerformanceIssue.occurrenceIdnow also stamp, then the widget name. The same-category fallback is gone, so a card never outlines another widget. Pending happens only before the first scan and resolves after it. A not-found card unticks, and no outline appears later.NotUsefulMark, and an always-onnotUsefulMarksenvelope key on the snapshot andext.sleuth.issues, written only when there is a mark. It is not aSnapshotSection, so 0.38 apps and older sidecars are unaffected.doc/mcp_schema.{json,md}(and the sidecar's byte-equal copy) document it and the issuemeasurementshape. The audit has presence tests driven by a realPlatformChannelDetectoremission. The sidecar'ssnapshotMetadataKeysincludes the key.DebugSnapshot.forcedRebuildsOfmaps each type a parent's build rebuilt to the types whose builds forced it, framework widgets included (debug callbacks only). It caps at 8 forcing types per type and setsforcedTypesCapped.forcedRebuildsByRootkeeps its content.leafSourceLocationreads the leaffile:lineof an ancestor chain. Copying the snapshot is logged as Sleuth's own work, so it is left out of the next frame's start delay, and a second tap during a copy is ignored.Different from the plan
RenderPipelineAnalyzer, where the phase is decided, instead of at the three controller call sites. The reason'sRelated:line then names an issue of the phase, too.pendingIssueSelectionis now read-only. The lookup's own callback replaces the old late selection.Verification
fvm flutter analyze: 0 issues. Format check clean.fvm dart doc --dry-run: 0 warnings.fvm flutter test --exclude-tags benchmark: 4,841 passed.--tags benchmark --concurrency=1): 44 passed (4 new).Review
Codex reviewed the branch twice. The first round found three defects, fixed in c6ce3b9:
Type, and the names are looked up only when a snapshot is taken. With 200 forced rebuilds a frame, frame time is within noise of the hook before the map: median 1,366 vs 1,347 µs over five interleaved runs.The second round approved with no findings.
Not in this PR
The UI that uses this data (status lines, the Not useful toggle, the Why it rebuilds block, the new card) comes in the next PRs of the stack. The device parity walk ran on the finished stack, on an iPhone 12 and a Galaxy A07; #28 has the results.
Fix from the iPhone walk
SourceLocationCachekept onefile:lineper widget type, so a type built in several places reported the first place it resolved: the Rebuild Hotspot screen'sValueListenableBuilder<int>showedhigh_level_setstate_demo.dart:75, in the Where row and its Copy. The cache now keys on the element (anExpando). The test that pinned type sharing is replaced by one with two call sites, which fails on the old cache.Fix from the final review
Jank tag hold (Galaxy follow-up)
On a Galaxy A07 the Jank tag went on and off about once a second on FPS Stress: its tag set changed 23 times in 30 s. Late frames alternate between phases, and a raster or start-delay frame names no build issue, so a tag that followed only the latest verdict blinked.
heldJankCauses()returns the issues named within the 10 s windowjank_detectedjudges, and the time until the first one leaves.FrameTimingDetector.markRouteEpoch.event_loop_stallcard itself came or went. The Rebuild Activity tag stayed on. iPhone 12, same demo: no changes in 30 s.🤖 Generated with Claude Code