Skip to content

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

Choose a tag to compare

@carloshpdoc carloshpdoc released this 18 May 01:46
· 8 commits to main since this release

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".