Skip to content

Releases: carloshpdoc/memorydetective

v1.18.2: /investigate-metrickit prompt + 7th MCP prompt

24 May 03:19

Choose a tag to compare

Post-v1.18.1 follow-up. Adds the /investigate-metrickit MCP prompt (the 7th, completing the prompt surface for the v1.18 MetricKit lane) and syncs the README prompt count which had drifted (stale at 5, actual 7 including /summarize-trace and the new MetricKit prompt). No tool API changes. 757 -> 758 tests (+1).

Added

  • /investigate-metrickit MCP prompt (7th prompt). Bespoke render (not playbook-backed). Takes a payloadPath argument and produces a ready-to-execute brief: 4 read-priority sections (crashCluster, hangHotspots, cpuExceptions, diskWriteExceptions), suggestedNextCalls chain hints into findCycles / analyzeHangs, and explicit constraints (no symbolication, no direct fix from raw .mxdiagnostic, payloadCount: 0 is a valid state). Surfaces in Claude Code as /investigate-metrickit. Prompt count goes from 6 to 7. Asserted via bespoke = ["summarize-trace", "investigate-metrickit"] filter in the playbook-backed coverage test.

Changed

  • README prompt count synced. The README listed 5 prompts (stale snapshot from v1.16) when actual count is 7. Updated to enumerate all 7 prompts, including /summarize-trace (v1.17) and the new /investigate-metrickit.

v1.18.1: docs-only patch syncing README + USAGE with v1.18 MetricKit surface

18 May 01:59

Choose a tag to compare

Docs-only patch. Syncs the npm README + USAGE with the v1.18 surface notes that landed on GitHub right after v1.18.0 was published. No code changes.

Changed

  • README "What's new" block leads with v1.18 (MetricKit 42nd tool + audit-close trio). New Examples block "Analyze MetricKit payloads from real-user crashes" with a concrete TestFlight directory aggregation example. New "Production diagnostics (1, v1.18)" API section with full analyzeMetricKitPayload surface description. API "Read & analyze" prefaced with the v1.18 D-02 AnalyzeTraceOptions hint. summarizeTrace row gains the D-02 wall-clock-win sentence.
  • USAGE follow-up requests table adds a "Production diagnostics" sub-section with 4 prompt examples covering analyzeMetricKitPayload (single payload, directory aggregation, groupBy variants, hang ranking). New end-to-end example "MetricKit production post-mortem" walks through a 47-payload TestFlight investigation mirroring the shape of the existing memgraph example, so the agent flow is consistent across lanes.

v1.18.0: MetricKit (42nd tool) + audit-close trio (D-01 + D-02 + D-03)

18 May 01:46

Choose a tag to compare

Audit-close + MetricKit bet. v1.17 was reliability tightening on the existing surface. v1.18 ships the 42nd MCP toolanalyzeMetricKitPayload, the post-mortem production-diagnostics lane — alongside three audit-close items deferred from v1.17 (open-enum SupportStatusKind, schemaDiscovery cache, real-Apple integration tests). The MCP ecosystem has zero coverage for MetricKit today; this release opens that lane. 701 → 757 tests (+56). 41 → 42 MCP tools.

Added

  • analyzeMetricKitPayload MCP tool (42nd, [mg.production]). Ingests Apple MetricKit .mxdiagnostic JSON payloads from real-device TestFlight / App Store builds. Three input forms (single file, directory glob with cross-payload aggregation, raw JSON string). Three actionable outputs: crashCluster (groups by exception type / binary / top frame with configurable groupBy), hangHotspots (sorted by hangDurationMs with localized-string handling for "5.4 sec" / "20秒" / etc. — Apple ships localized values), cpuExceptions + diskWriteExceptions (long tail). Each entry includes raw binaryUUID + offsetIntoBinaryTextSegment + binaryName for downstream dSYM lookup. Cross-tool chain hints: _objc_release-style top frame surfaces a findCycles suggestion, libsqlite3.dylib top frame surfaces an analyzeHangs chain hint with the main-thread-violation classifier. No symbolication in v1analyzeMemgraph evolved through the same staging pattern; dSYM lookup is its own future tool. Simulator does not generate MetricKit payloads (Apple-side limitation); framed as post-mortem analyzer, not live capture. Adds 4 new SupportStatusKind values (crash-diagnostics, hang-diagnostics, cpu-exception-diagnostics, disk-write-exception-diagnostics).
  • AnalyzeTraceOptions interface in src/types.ts. New optional second argument shared by every trace-side analyzer carrying discoveredSchemas?: Partial<Record<string, string>>. Direct callers leave it unset and pay the one-shot TOC fetch as before; orchestrators (summarizeTrace) populate it once up front so the 6 fan-out analyzers skip their own TOC calls.
  • resolveSchemasForAnalyzer helper in src/parsers/schemaDiscovery.ts. Cache-aware schema name resolution: reads the optional cached map when provided (no runner call), falls back to the cold path (fetchDiscoveredSchemas) otherwise, fills gaps with canonical names per family. Same shape as the existing single-family fetchDiscoveredSchemas, drop-in for the 9 trace analyzers that adopted it.
  • Local-only integration test suite against real Apple .trace bundles (src/tools/realApple.integration.test.ts). Reads MEMORYDETECTIVE_INTEGRATION_TRACES env var; tests skip silently when unset or fixture missing. 12 tests cover inspectTrace (TOC + metadata + suggestedNextCalls), analyzeHangs (pre + post fix verdicts), analyzeTimeProfile (v1.14 item O regression guard — symbols must be real function names, not the weight column), compareTracesByPattern, and summarizeTrace end-to-end (also exercises the D-02 cache). Documentation in tests/INTEGRATION.md. Fixtures live locally on the maintainer's machine; never committed to git, never shipped via npm.

Changed

  • SupportStatusKind is now an open enum. Pre-v1.18 it was a closed TypeScript literal union (10 kinds). Adding a kind forced a breaking type change for downstream consumers branching exhaustively. v1.18 switches to the KnownSupportStatusKind | (string & {}) pattern: inline literals still get autocomplete + typo detection internally (via KnownSupportStatusKind), external strings (e.g. the 4 new MetricKit kinds) now type-check without us shipping a new union. Exported runtime constant SUPPORT_STATUS_KINDS (readonly tuple of the 10 strings) so callers can iterate / validate. Existing call sites unchanged. Unblocks analyzeMetricKitPayload.
  • summarizeTrace runs schema discovery once up front. Pre-v1.18 each of the 6 analyzers it fans out to ran its own xctrace export --toc. Wall-clock penalty: +600-3000ms on real Apple traces, dominated by xctrace cold-start. v1.18 runs fetchDiscoveredSchemasWithStatus once at the top with all 7 families needed and passes the cache to every analyzer call via { discoveredSchemas }. Measured win against the wishlist-tti-device.trace (37 MB Time Profiler) in integration tests: end-to-end summarizeTrace went from ~28s to ~15s per call.
  • All 9 trace analyzers (analyzeHangs, analyzeAnimationHitches, analyzeAllocations, analyzeAppLaunch, analyzeTimeProfile, analyzeNetworkActivity, analyzeMemoryFootprint, analyzeEnergyImpact, analyzeLeakTimeline) accept the new optional AnalyzeTraceOptions second argument. Backwards-compatible default: when omitted, behavior is identical to v1.17 (cold-path TOC fetch). No breaking change for any direct caller.

Notes

  • The integration test suite is local-only and never runs in CI. CI on Linux continues to skip the 12 tests entirely. To activate locally: MEMORYDETECTIVE_INTEGRATION_TRACES=~/Desktop npm test. Expected fixtures and the workflow are documented in tests/INTEGRATION.md.
  • The 4 v1.15+ trace analyzers (analyzeNetworkActivity, analyzeMemoryFootprint, analyzeEnergyImpact, analyzeLeakTimeline) are still synthetic-only at integration level. Add coverage when matching template recordings land in the integration directory.
  • MetricKit delivery on iOS 18+ has a documented 24-48h delay and a "new bundle id probation" window (Apple Forums thread 766016). The tool surfaces payloadCount: 0 honestly when the directory is empty; do not oversell coverage to users.
  • The deferred items (D-01 / D-02 / D-03) from ~/Desktop/internal/v1.17-bugs-and-debt.md are all closed in v1.18. Remaining backlog (Phase 8 v1.9 dSYM symbolication, cross-payload trend analysis on MetricKit, /investigate-metrickit MCP prompt) tracked in ~/Desktop/internal/v1.18-roadmap.md § "Out of scope".

v1.17.1: docs-only patch syncing npm README with the v1.17 surface notes

16 May 19:25

Choose a tag to compare

Docs-only patch. Syncs the npm README + USAGE with the v1.17 surface notes shipped to GitHub right after v1.17.0 was published. No code changes.

Changed

  • README leads with the v1.17 reliability headlines; env-var table prefaced with the strtobool truthy parsing rule; macOS 26.x callout cites the new bundleStatus field on recordTimeProfile, the savedOutsideWatchDir field on recordViaInstrumentsApp, and the fault-tolerant inspectTrace fallback. Capture / record section renumbered from (3) to (4) with the previously-missing recordViaInstrumentsApp row. verifyFix + countAlive + inspectTrace + recordTimeProfile rows annotated with their v1.17 surface additions.
  • USAGE.md follow-up prompts table gained a verifyFix example using { pattern, mode: "exact" }. Troubleshooting recovery list for the macOS 26.x recording wedge documents the savedOutsideWatchDir AppleScript fallback.

v1.17.0: reliability pass: 14 bug fixes, strtobool env parsing, whitelist match modes, fault-tolerant inspectTrace

16 May 19:04

Choose a tag to compare

Reliability pass. v1.16 closed the macOS 26.x recording gap with recordViaInstrumentsApp. v1.17 sweeps the audit punch list that surfaced after dogfooding: 14 bugs across three tiers, 3 known limitations documented, 3 tech-debt items deferred. The headlines are env-var truthy parsing (every MEMORYDETECTIVE_* boolean now accepts 1 / true / yes / on, was 1-only), a verifyFix whitelist that supports exact / substring / regex modes (was substring-only), the recordViaInstrumentsApp watcher catching saves outside the watch dir, and the inspectTrace fault-tolerant fallback so a wedged 52K bundle no longer throws. 41 MCP tools, 701 tests (+24 vs v1.16).

Fixed

Tier 1 (user-visible)

  • recordViaInstrumentsApp watcher misses saves outside watchDir (B-01). Pre-v1.17 the tool only watched the filesystem path; users who hit Save in Instruments.app and accepted the default Desktop location would time out even though the trace was on disk. Now queries the running Instruments.app via AppleScript every poll for any document whose file path was set after the tool started; on first match outside watchDir returns the path with savedOutsideWatchDir: true. Uses the documented Instruments.sdef file of document accessor only (no unsupported verbs).
  • verifyFix.expectedAliveClasses supports per-entry mode (B-02). Pre-v1.17 every whitelist entry was matched as a case-insensitive substring. Caller wanting "match exactly UIRemoteKeyboardWindow, do not match MyUIRemoteKeyboardWindowWrapper" had no way to express it. Schema now accepts string (defaults to substring for backwards compat) or { pattern: string, mode: "exact" | "substring" | "regex" }. ESLint and Jest both use single-mode matching, but their users have asked for the inverse in tracked issues; we picked the opposite trade-off.
  • MEMORYDETECTIVE_* env booleans accept the strtobool truthy set (B-03). Pre-v1.17 only the literal string 1 turned a gate on. Users exporting MEMORYDETECTIVE_ALLOW_LAUNCH=true or =yes saw silent no-op behavior. v1.17 normalizes the five booleans through parseBooleanEnv, which accepts 1 / true / t / yes / y / on (truthy) and 0 / false / f / no / n / off (falsy), case-insensitive. Unrecognized values emit a one-time stderr warning per var so the operator knows the setting was ignored. Mirrors envalid's bool() semantics without taking the dependency.
  • maybeOpenInInstruments checks bundle viability before opening (B-04). Pre-v1.17 the auto-open path would launch a wedged 52K macOS 26.x stub bundle in Instruments.app, where it presents a Document Missing Template Error dialog the operator has to dismiss. Now probes Trace1.run/MANIFEST.plist before calling open; on missing manifest, skips the open and surfaces the bundle status to the caller. The exported classifyBundleOnDisk(tracePath) helper returns "unknown" | "salvageable" | "wedged" for reuse.

Tier 2 (silently sub-optimal)

  • inspectTrace fault-tolerant fallback when xctrace export --toc fails (B-05). Pre-v1.17 a failed TOC export threw, which broke the entire MCP call. Now returns ok: true with schemas: [], rowCounts: {}, suggestedNextCalls: [], and a diagnosis string naming the 52K macOS 26.x stub pattern so callers can self-diagnose. Throwing is reserved for missing trace paths.
  • schemaDiscovery.fetchDiscoveredSchemasWithStatus surfaces failures (B-06). New sibling of fetchDiscoveredSchemas returns { schemas, status: "ok" | "failed", reason? } so trace analyzers can include a discovery-failure entry in supportStatus[] instead of silently using canonical schema names against a renamed-schema trace. Emits a one-time stderr warning per tracePath:reason, gated on MEMORYDETECTIVE_SUPPRESS_PLATFORM_ADVISORY. Legacy fetchDiscoveredSchemas keeps its silent-fallback contract.
  • countByClassWithBytes reports min/max/median for variable-size classes (B-07). Pre-v1.17 we returned the first observed instanceSize as canonical for every class. Misled callers inspecting NSData, NSString, CFData whose per-instance size is payload-dependent. Now: fixed-size classes return a single instanceSizeBytes value as before; variable-size classes return { instanceSizeBytes: median, instanceSizeBytesMin, instanceSizeBytesMax, instanceSizeBytesMedian }. totalBytes unchanged. CountAliveEntry propagates the spread through per-class and topN paths.
  • analyzeHangs.supportStatus[] always includes both schema entries (B-08). Pre-v1.17 a caller without hangRisksXml saw a single entry, a caller with it saw two. Agent code branching on supportStatus.find(s => s.kind === "hang-risks") could not distinguish "I did not ask" from "schema absent". Both entries are now always present; the missing-XML path returns status: "not_present" with reason "caller did not provide hangRisksXml".
  • recordTimeProfile.bundleStatus reflects on-disk reality (B-09). New bundleStatus: "unknown" | "salvageable" | "wedged" field on the response. The timeout path now probes MANIFEST.plist via classifyBundleOnDisk so callers branching on tracePath ? "have trace" : "no trace" get an honest signal.
  • countAlive framework-noise filter is configurable (B-10). New inputs: excludeFrameworkNoise: boolean (default true), additionalNoisePatterns?: string[], unsuppressClassPatterns?: string[], noiseAuditMode: boolean. The curated noise list (calibrated for the v1.5 notelet investigation) remains the default. Audit mode returns a noiseAudit[] array listing every filtered class with reason 'default-list', 'additional-pattern', or 'kept-by-unsuppress'. User-supplied regex strings compile with a literal-escape fallback on syntax errors.

Tier 3 (edge case / cosmetic)

  • extractHost parses IPv6 bracket form (B-11). analyzeNetworkActivity was misreporting hosts like [::1]:443 as the empty string. Now strips brackets and splits the port correctly.
  • normalizeBucket priority fix (B-12). analyzeEnergyImpact was matching "high" before "foreground" in xctrace's varying-case bucket strings. Reordered to check the named buckets first.
  • Redundant t.schema === "memory-footprint" equality removed (B-13). analyzeMemoryFootprint was double-checking after discoverSchemas already resolved the family name.
  • analyzeLeakTimeline handles column-drift gracefully (B-14). When every row is skipped due to missing className, returns status: "partial" with a reason naming the column drift instead of silently emitting an empty timeline.

Behavior changes (informational)

  • The MEMORYDETECTIVE_* boolean env vars are now case-insensitively recognized for the strtobool set. Setting =yes or =true now turns gates on; pre-v1.17 it did not. Operators who deliberately set unrecognized values will see a stderr warning but no behavioral change (unrecognized falls back to default).
  • verifyFix.expectedAliveClasses string entries continue to behave as case-insensitive substring matches for backwards compat. The new object form { pattern, mode } is opt-in.
  • The deprecated notice and status aliases on trace analyzers stay (will be removed in a future major bump).

v1.16.0: macOS 26.x recording-unblock

15 May 16:54

Choose a tag to compare

The macOS 26.x recording-unblock release. Single feature, single day.

What this fixes

`xcrun xctrace record --time-limit Ns` against iOS simulator targets is broken on macOS 26.x (documented in v1.14). The recording wedges past the time limit, exits when SIGKILL fires, and the resulting `.trace` is missing template metadata. `recordTimeProfile` returns `recordingTimedOut: true` and the auto-open-Instruments / pre-flight UX paths landed in v1.14 mitigate the user experience but the actual automated recording remained blocked.

What v1.16 ships

  • `recordViaInstrumentsApp` MCP tool (41st, `[mg.build]`). The escape hatch. Flow:

    1. Opens Instruments.app via `open -a Instruments` (fire-and-forget).
    2. Returns an `instructions[]` array telling the user which template to pick, when to hit Record / Stop / Save, and which directory to save into (configurable `watchDir`).
    3. Polls `watchDir` every 5 seconds for new `.trace` bundles.
    4. Treats a new bundle as "saved" when its mtime has been stable for 10 seconds.
    5. On detection, chains into `inspectTrace` and returns the trace path + schemas + diagnosis.
    6. Times out after `timeoutSec` (default 600s / 10 min, max 3600s).

    Why user-in-loop? Instruments.app's AppleScript surface is minimal: the `document` class exposes `name`, `modified`, `file` properties only - no verbs for start/stop recording or template selection. Documented at `Xcode.app/Contents/Applications/Instruments.app/Contents/Resources/Instruments.sdef`. Full GUI automation is impossible until Apple expands the dictionary.

README + USAGE updates

The macOS 26.x `xctrace record` callout now points at `recordViaInstrumentsApp` as recovery option #1. USAGE.md Troubleshooting list reranked: tool wrapper > older Xcode 26.0 host > manual GUI > physical device > wait for Apple.

Tests + tools

  • Suite: 666 -> 677 (+11). New tests cover `snapshotTracesInDir`, `detectNewTraces` filter + sort, `isStable` mtime check, and `buildInstructions` text generation.
  • MCP tools: 40 -> 41.

Deferred to v1.17+

  • Phase 8 v1.9: dSYM symbolication on `analyzeTimeProfile`.
  • Bet #4: `analyzeMetricKitPayload` (.mxdiagnostic ingest).
  • Marketplace submissions: PulseMCP, MCP.so.

Full diff: `v1.15.0...v1.16.0`

v1.15.0: schema coverage + verify-fix UX

15 May 16:37

Choose a tag to compare

Schema coverage + verify-fix UX release. 5 items landed on a single day. Suite 626 -> 666 (+40). MCP tools 37 -> 40.

Trace schemas covered

  • `analyzeMemoryFootprint` MCP tool (38th). Parses the `memory-footprint` schema. Peak resident / dirty / virtual bytes plus per-sample timeline. The OOM-kill discriminator on iOS. Distinct from `analyzeAllocations` (cumulative malloc bytes by category). Flags peak dirty > 200 MB as approaching jetsam territory.
  • `analyzeEnergyImpact` MCP tool (39th). Parses the `energy-impact` schema. Per-sample bucket classification (idle / passive / active / high), aggregate wakeup count, active-state ratio, top-N by energy cost. Reads the OS power-management subsystem directly. Distinct from `analyzeTimeProfile` (CPU sampling).
  • `analyzeLeakTimeline` MCP tool (40th). Parses xctrace's leaks schema (the instrument, distinct from `leaks(1)` CLI snapshot). Per-class first-seen-at timestamp, peak instance count, peak bytes, event count. Answers "when in the recording did the leak appear?" which a snapshot cannot.

Synthesis chain

  • `summarizeTrace` chains `analyzeNetworkActivity`. Sixth `buildAreaSummary` runs network in parallel. Markdown card gains a Network section + per-host aggregates. `buildHeadline` falls back to the slowest network request (>= 3s) only when hangs / launch / hitches are quiet. `focus: "network"` is a new enum value.

Verify-fix UX

  • `replayScenario` captures simulator screenshots per step. New `screenshotDir?: string` input. Each step writes one PNG via `xcrun simctl io screenshot` (no `axe` dependency). DebugSwift-inspired: "what was on screen when this happened?" context for verify-fix loops. `captureSimulatorScreenshot` helper exported. Failures non-fatal.

Type system

  • `SupportStatusKind` enum extended with `memory-footprint`, `energy-impact`, `leak-events` to back the three new analyzers.

Deferred to v1.16+

  • `recordViaInstrumentsApp` (item G from v1.14 candidates, 8-12h big feature). The AppleScript-driven Instruments.app GUI wrapper. Still the only known reliable trace-recording path on macOS 26.x simulators.
  • Phase 8 v1.9: dSYM symbolication on `analyzeTimeProfile`.
  • Bet #4: `analyzeMetricKitPayload` (`.mxdiagnostic` ingest).

Full diff: `v1.14.0...v1.15.0`

v1.14.0: trace-side reliability + breadth

15 May 16:04

Choose a tag to compare

Trace-side reliability + breadth release. Single day, 11 items landed across the trace analyzers and MCP surface. Suite 546 -> 626 (+80). MCP tools 36 -> 37.

Trace-side parser fixes

  • `inspectTrace` + `summarizeTrace` now work against real Apple traces. The old xpath `/trace-toc/run` returned empty against bundles from `xcrun xctrace record` and Instruments.app; cascaded into `summarizeTrace` reporting "no events detected" even when the trace had 35 hangs. Now uses `xctrace export --toc` + per-schema row-count queries.
  • `analyzeTimeProfile` returns real symbol names. Was returning `"1.00 ms"` (the weight column) as every symbol. Now reads the leaf frame's `@_name` from `` with fallback to the binary name for unsymbolicated hex addresses.

Schema coverage expansion

  • `analyzeNetworkActivity` MCP tool (37th). Parses the `network-connections` schema. Per-request URL / host / method / status / duration / bytes-in / bytes-out, top-N by duration + by bytes, per-host aggregates.
  • `analyzeHangs` reads the `hang-risks` schema alongside `potential-hangs`. Surfaced as `risks[]` + `risksTotals`.

Structural refactors

  • Pattern-matching schema discovery. All 5 trace analyzers resolve schema names through a regex map (SCHEMA_FAMILIES) with canonical fallback. Survives future xctrace renames without code changes.
  • Unified `supportStatus[]` surface across all 6 trace analyzers (XcodeTraceMCP-pattern). Old `status` / `notice` aliases remain for backwards compat.

macOS 26.x xctrace --time-limit regression UX

  • README + USAGE.md callout naming the bug + 4 recovery options.
  • `MEMORYDETECTIVE_PREFLIGHT_XCTRACE` env var enables a 2-second probe before the user's actual recording. Cuts failure latency from ~70s to ~8s. Auto-enabled on macOS 26.x simulator attach.
  • `MEMORYDETECTIVE_AUTO_OPEN_INSTRUMENTS` env var enables fire-and-forget `open -a Instruments ` on timeout, opening the partial trace in the Instruments.app GUI.

Memgraph polish

  • `countAlive` returns `instanceSizeBytes` + `totalBytes` per class and accepts `sortBy: "totalBytes"`. FLEX-inspired Size view. Validated against real abandoned-memory memgraph: top by totalBytes surfaces 2 MB NSMutableDictionary, 1.3 MB CFString, actionableCounts highlight 800 KB Kernel Pointers + 460 KB CGDataProvider.
  • `verifyFix` accepts `expectedAliveClasses[]` whitelist with curated default list of system VCs / views / windows (`UICompatibilityInputViewController`, `UIPredictionViewController`, `UIRemoteKeyboardWindow`, etc.). MLeaksFinder + DebugSwift-inspired UX. Whitelist hits surface in `expectedAlive[]` for transparency without flipping the verdict.

Deferred to v1.15

  • `recordViaInstrumentsApp` (item G, 8-12h big feature)
  • screenshot during `replayScenario` (item N)
  • `summarizeTrace` network chain integration

Full diff: `v1.13.0...v1.14.0`

v1.13.0: summarizeTrace + cross-correlation + /summarize-trace prompt

15 May 02:28

Choose a tag to compare

Trace-depth synthesis differentiator. v1.11 added inspectTrace (discovery), v1.12 added cross-schema correlation inside analyzeHangs. v1.13 ties everything together: one call returns a cross-schema summary card tuned for direct presentation to the user, instead of chaining 5-6 analyzers manually and reasoning over the JSON.

Added

  • summarizeTrace MCP tool (36th tool, [mg.synthesize]). Single call that:

    1. Inspects the TOC via the existing inspectTrace path.
    2. Chains analyzeHangs (with includeStackClassification: true to auto-classify main-thread violations), analyzeAnimationHitches (with Apple's 100ms perceptible threshold), analyzeTimeProfile, analyzeAllocations, analyzeAppLaunch in parallel via Promise.all guards.
    3. Builds cross-area correlations (Phase 2: hangs+hitches timestamp overlap detection with HIGH/MEDIUM/LOW confidence tiers).
    4. Returns BOTH a structured per-area result AND a pre-rendered compact markdown card (< 10 KB at default settings, validated by a card-size guard in the unit tests).

    The card layout: H1 title, device/OS/template metadata, headline (1-2 sentences naming the biggest user-impact finding ranked by hang>=250ms > launch>1s > perceptible hitches > short hang), per-area sub-sections (suppressed when empty to reduce noise), cross-correlations section with confidence badges, suggested next calls from inspectTrace.

    Optional inputs: focus: "hangs" | "hitches" | "allocations" | "launch" | "all" to bias the summary toward one area; verbose: true to expand each section's top-N from 5 to 15+ and surface low-confidence correlations inline.

    Failed analyzers (e.g. xctrace SIGSEGV on time-profile) surface their workaround notice inline; other sections unaffected. Empty schemas don't fail the call.

  • correlateHangsAndHitches() pure cross-correlation helper. Detects hangs whose time windows overlap with animation hitches. When a user sees a hang AND a hitch in the same window, they almost certainly perceived the impact (main-thread block delayed render commits). Confidence tiers: high when both events >= 250ms AND overlap span >= 100ms; medium when at least one event >= 250ms; low when both sub-250ms but touching. Results sorted by atSec ascending so the markdown card lists correlations in trace order. Allocation-based correlations (hangs+allocations, hitches+allocations) are deferred to v1.14+ because the existing analyzeAllocations doesn't expose per-timestamp allocation rows.

  • /summarize-trace MCP prompt (6th prompt). Counterpart to the summarizeTrace tool. Unlike the existing 5 prompts (which wrap multi-step playbooks), /summarize-trace wraps a single tool call. The brief tells the agent to (1) call summarizeTrace, (2) present result.markdown verbatim instead of paraphrasing, (3) offer drill-ins via suggestedNextCalls. Surfaces the "present the result; don't re-summarize" pattern that agents often get wrong with structured data.

Changed

  • package.json + server.json: 1.12.0 → 1.13.0.

Test count

523 → 546 (+23): 14 buildHeadline/buildMarkdownCard tests in Phase 1, 9 correlation tests in Phase 2, +0 in Phase 3 (the prompts test was updated, not extended).

v1.12.0: Complete ref-tree propagation (countAlive + findRetainers + verifyFix) + analyzeHangs auto cross-schema correlation

14 May 22:42

Choose a tag to compare

Four-phase patch completing the v1.10 retro §7.2 propagation (countAlive, findRetainers, verifyFix reference-tree integrations) and internalizing the v1.9 cross-schema correlation (analyzeHangs auto-classification). The agent chain analyzeAbandonedMemoryfindRetainerscountAliveverifyFix no longer falls off a cliff after the first call.

Added

  • countAlive reference-tree integration. New includeReferenceTree: boolean input flag (default false preserves v1.11 behavior). When true, spawns leaks --referenceTree --groupByType --noContent in parallel with the existing cycle pass, merges counts by class name, and surfaces a new actionableCounts[] field filtered via isFrameworkNoise. For countAlive({ className: "AVPlayerItem", includeReferenceTree: true }) on the notelet pre-fix memgraph, returns instanceCount: 685 (substring match captures both AVPlayerItem 342 + AVPlayerItemInternal 343); for the topN path, surfaces AVCMNotificationDispatcher / __NSObserver / AVPlayerItem instead of NSMutableDictionary / CFString noise. New per-class byCycle + byReferenceTree breakdown fields when the flag is on. 3 new schema validation tests.

  • verifyFix abandoned-memory verdict fallback. v1.11 returned overallVerdict: "PASS" with empty patternResolution[] on the notelet pair (both leakCount: 0); v1.12 chains internally into analyzeAbandonedMemory when no cycle patterns fire on either side. New verdictSource: "cycle-pattern" | "abandoned-memory", freedClasses[], regressionClasses[] fields. Magnitude-dominance heuristic resolves verdict to PASS / PARTIAL / FAIL by comparing the sum of |freed delta| to |growth delta| at a 2x ratio. Notelet pair now returns verdict: PASS with diagnosis "Fix verified via abandoned-memory shrinkage: 10,386 instances freed dominates the residual 4,531-instance growth (typically Swift runtime / font cache / ObjC class table)." isFrameworkNoise extended to flag N bytes into <X 0xADDR> [size] heap-offset entries so the magnitude check doesn't get fooled by partial-allocation noise. 1 new reference-tree filter test.

  • findRetainers reference-tree chains. New includeReferenceTree: boolean input flag (default false). When true, spawns leaks --debug=stacks --debug='<className>$' and parses the per-instance allocation stack output via a new src/parsers/leaksDebugStacks.ts parser. Instances sharing the same call-stack fingerprint aggregate into one chain with instanceCount. Each chain exposes callStack[] (ordered frames from dyld root to allocation site), retainers[] (unique retainer classes with aggregate counts), exampleAddress (one representative instance), and userFrame (the deepest non-system frame, surfacing the actual line a developer would inspect). New 11-test parser file. leaks's --debug= predicate restriction documented in the schema description: ^ is rejected by leaks, only trailing $ works. MallocStackLogging caveat documented: Xcode-exported memgraphs may surface fewer chains than the total instance count because leaks --debug=stacks only emits blocks for instances whose allocation stack was recorded.

  • analyzeHangs cross-schema correlation. v1.9 added mainThreadViolations[] enrichment via the caller-supplied topFramesByHangStartNs map; v1.12 internalizes it. New includeStackClassification: boolean input flag (default false preserves v1.9 behavior). When true, exports the time-profile schema in parallel with potential-hangs, correlates samples to hang windows by timestamp (sample in [hang.startNs, hang.startNs + hang.durationNs]), picks the dominant top frame per hang by aggregate weight, and runs classifyHangFrame() on it. New pure correlateTimeProfileToHangs() helper. Caller-supplied maps still take precedence over the auto-correlation. 8 new pure correlation tests covering empty inputs both sides, in/out-of-window, weight tiebreaker, backtrace fallback, multi-hang independence, default-weight handling.

Changed

  • package.json + server.json: 1.11.0 → 1.12.0.
  • compareTracesByPattern call sites of analyzeHangs now pass includeStackClassification: false explicitly to satisfy the inferred analyzeHangs input type (cosmetic; no behavioral change).