feat: --auto-spindump + multi-kind cluster sidecar (HangBuster PR 2/3)#92
Merged
Conversation
Adds spindump capture alongside --auto-sample, and fixes a latent gap where auto-samples stashed during capture never made it into summary.json. Storage: read_auto_samples returns dict[str, list[dict]] (write-order preserved) so a fingerprint can carry both a simctl-sample and a spindump record. Worker uses parallel dedup sets so each kind fires at most once per fingerprint. Pipeline: Cluster gains auto_samples: list[dict] | None alongside the legacy auto_sample (kept for backward compat with old summary.json files). SummaryBuilder.build() now takes auto_samples_by_fp and attaches matching captures to clusters. SessionStore.build_summary passes it through automatically. format_cluster_detail iterates and renders each kind with its own label; also fixes a bug where the old format treated stack as a list when PR 1 made it text — now splits by lines correctly. CLI: new --auto-spindump flag, parallel to --auto-sample. Updated --resample to use the new auto_samples list shape. Tests: 8 new units covering spindump subprocess paths, multi-kind storage round-trip, SummaryBuilder attachment by fingerprint, multi- kind format rendering, and legacy auto_sample backward compat.
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.
Context
Building on PR #91 (which wired
--auto-sampletoxcrun simctl spawn sample), this PR:xcrun simctl spawn spindumpbehind--auto-spindump.summary.json. The worker writes toauto_samples.jsonl, butSummaryBuilder.buildnever read it back — so--get-detailson a stopped session showed no stack. Only the--resamplepath (which re-firessampleat inspection time) worked. Bundling the fix here because PR 2 has to touch the same code paths anyway.This is PR 2 of 3 in the stack-enrichment plan. PR 3 will add
atospost-processing on the captured stacks for source-line symbolication.Changes
Storage (
hang_sessions.py):read_auto_samplesreturn type:dict[str, dict]→dict[str, list[dict]], preserving write order. Callers disambiguate via thekindfield on each payload.build_summarynow reads auto_samples and passes them toSummaryBuilder.buildso they survive intosummary.json.Pipeline (
hang_pipeline.py):Cluster.auto_samples: list[dict] | Nonealongside existingauto_sample(kept for backward compat with old summary.json files; rehydrates from either).SummaryBuilder.buildtakesauto_samples_by_fpand attaches matching captures to clusters at build time.format_cluster_detailiterates samples, renders each kind under its own header (simctl-sample stack (top 10):/spindump stack (top 10):). Also fixes a latent bug from PR 1:stack[:10]sliced 10 chars when stack became a string; now splits to lines correctly.Watcher (
hang_watcher.py):--auto-spindumpCLI flag, parallel to--auto-sample._attempt_auto_spindump(udid, pid)shelling toxcrun simctl spawn <udid> spindump <pid> 1 -file -with a 10s timeout (spindump is heavier than sample).spindumped_fingerprintsdedup set so each kind captures at most once per fingerprint.--resamplepopulates the newauto_sampleslist slot.Tests
8 new units in
test_auto_sample.py/test_hang_pipeline.py/test_hang_sessions.pycovering:SummaryBuilder.buildattaches by matching fingerprint, ignores non-matchingformat_cluster_detailrenders both kinds with labels, falls back to legacyauto_sample, reports failure reasonsVerification
pytest tests/— covered.python scripts/hang_watcher.py --start --auto-sample --auto-spindump --bundle-id <id>, reproduce a hang, then--stopand--get-details --cluster 1should now show both asimctl-sample stackblock and aspindump stackblock in the cluster detail. Without--auto-spindumpthe existing PR 1 behaviour is unchanged (single sample block). (Not run as part of CI — sim-coupled.)