[PR #2684] [CLOSED] perf(artifacts): add opt-in Interface Builder summary delivery and pages #5310

Closed
opened 2026-10-31 01:05:37 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/2684
Author: @kaoru0822-kitauji
Created: 10/13/2026
Status: ❌ Closed

Base: main ← Head: perf/interface-builder-summary


📝 Commits (7)

  • f993d33 perf(artifacts): add opt-in Interface Builder summary delivery and pages
  • da49ea2 fix(artifacts): describe incomplete Interface Builder graphs accurately
  • a92b960 fix(mcp): validate delivery detail before removing it
  • 7b9ab77 fix(mcp): reject invalid delivery selections through typed preflight
  • 94e360c test(artifacts): assert SDK argument rejection at its boundary
  • f3cd103 Merge remote-tracking branch 'origin/main' into HEAD
  • 95bcaa0 Merge remote-tracking branch 'origin/main' into HEAD

📊 Changes

3 files changed (+21 additions, -15 deletions)

View changed files

📝 .agents/skills/reverse-engineer-anything/references/native-and-artifacts.md (+5 -0)
📝 src/domain/analysisView/webNetworkCaptureView.ts (+4 -15)
📝 tests/boundary/mcp/interfaceBuilderSummaryMcp.test.ts (+12 -0)

📄 Description

Summary

Over MCP, decode_interface_builder currently fails on ordinary apps. The complete graph for XLD.app is 6.7 MB (1,980,857 o200k tokens) and for Transmission.app 6.3 MB. The text and structuredContent copies together exceed the default 10 MiB response budget, so the caller gets resource_constraint ("its complete MCP response exceeds the stdio response budget") instead of an answer. A caller who only wants the windows, outlets or actions of one nib had no way to ask for less.

This PR adds the same opt-in delivery #2634 added for inspect_macho, which WASM, EVM, managed, Android, Dart AOT and pcap already have. Refs #2016, #1065.

Problem and expected behavior

Smallest trigger: open_binary /Applications/Transmission.app, then decode_interface_builder {} returns resource_constraint. Expected: a first call can return a bounded answer while the complete Evidence stays retained for exact pages.

Change and scope

  • src/domain/analysisView/interfaceBuilderView.ts (new) owns Interface Builder views.

    • Summary: returns every decoded document row (bounded at 64), the provider, available_counts, tallies by node kind, edge relation and coverage status, and decoder truncation.
    • kind: "interface-builder" pages: cover documents, nodes, edges or coverage in original order. For nodes and edges, an optional document keeps rows whose recorded evidence[].artifact_path equals that exact documents[].relative_path. That's the producer's own attribution; nothing is reparsed from IDs. An undecoded path is refused instead of returning an empty page. Every page carries source_truncated.
    • Identity check: the parent subject digest and graph.target_sha256 must both equal target_sha256.
  • decode_interface_builder gets an optional detail and a complete-or-summary output schema. Delivery detail is stripped before execution and from Evidence parameters, so the summary's parent_evidence_id equals a complete call's Evidence ID. The preflight refuses summary before decoding when the server keeps no Evidence (the fix from #2634).

  • Related cleanup: the new view would have been the ninth copy of three patterns, pushing jscpd to 3.02% (threshold 3.0%). Each now has one owner:

    • parseAnalysisViewResult (analysisViewParent.ts) parses a parent's normalized result and maps issues into source.normalized_result. It replaces the identical blocks in the WASM, EVM, managed, Android, Dart AOT, web capture, Mach-O and IB views.
    • retainedSummaryDelivery / withoutDeliveryDetail (retainedSummaryDelivery.ts) own the preflight and summary hooks and the shared registration options type used by the artifact, native and managed registrations.
    • openProductionTarget (tests/support/mcp/productionSession.ts) owns the "production session plus open_binary" setup in five MCP tests.

    Duplication is now 2.98%. Behavior of the existing views and registrations is unchanged; their suites pass.

  • Docs: docs/mcp-contracts.md, docs/native-investigation.md, the skill reference, and the inspect_analysis_view description.

Not included: changing the producer's representation. Nodes repeat the document path in id, name and evidence, and limitations list each max_documents omission; that's a contract question. The default stays complete, and the CLI is unchanged (inspect-analysis-view with inline Evidence already supports the new kind).

Contribution scope: not applicable. This is the established opt-in delivery pattern with no new execution, mutation or authority.

Contract and boundary impact

  • Semantic owner and earliest changed stage: projection of retained decode_interface_builder Evidence; MCP delivery selection in registerArtifactTools.

  • Contribution scope fit and linked maintainer decision: not applicable.

  • CLI and MCP/tool-catalog contract: additive. The new optional detail and summary output variant, and a new interface-builder view request/result. Omitted detail keeps the old result and Evidence identity.

  • Provider, bridge, target-format, or platform compatibility: none. The decoder receives the same parameters.

  • Evidence, artifact, provenance, or reconstruction contract: the complete Evidence and its ID are unchanged. Views are derived Evidence linked to the retained parent.

  • Generated metadata, package, or installation impact: catalog regenerated at build; docs:check passes.

  • Read existing files or captured data.

Evidence and regression coverage

  • src/domain/analysisView/interfaceBuilderView.test.ts (any platform) covers:
    • tallies and documents without rows
    • a document-filtered node page with offset
    • visible truncation
    • refusals for an unknown document, the wrong view kind, and a mismatched subject digest
  • tests/boundary/mcp/interfaceBuilderSummaryMcp.test.ts (any platform; production session, real UIKitOutlet.xml nib archives in a two-document .app) checks:
    • Omitted detail records no detail.
    • The summary documents and counts equal the complete result.
    • parent_evidence_id equals the complete Evidence ID.
    • All edges reassemble from 2-row pages.
    • A document-filtered node read equals the complete nodes attributed to that nib (and is a strict subset).
    • An unknown document is refused.

Real applications (macOS, real MCP stdio, this branch)

App complete over MCP summary 20 edges of one document
XLD.app (64 decoded nibs, 6,528 nodes) resource_constraint; CLI JSON 6,734,711 B / 1,980,857 tok 35,497 B / 10,090 tok 6,989 tok
Transmission.app (5,560 nodes) resource_constraint; CLI JSON 6,313,752 B / 1,948,182 tok 12,106 B / 3,762 tok 5,034 tok

For both apps, the summary's parent equals the CLI complete Evidence ID, and paging every node 500 at a time reproduces all nodes exactly. Decoding takes 0.5–1.5 s for complete and summary alike (same analysis); each page takes about 30–40 ms. Tokens are o200k_base via tiktoken. CPU and peak memory weren't measured separately, because only delivery differs.

About 7 KB of each XLD response is the producer's 69 limitations, and they appear twice (normalized result and Evidence envelope), as in every view. I left that envelope repetition alone.

Catalog cost: tools/list grows from 687,395 to 690,367 o200k tokens (+2,972, +0.43%). decode_interface_builder adds 862 and inspect_analysis_view adds 2,110. Each page's rows use the existing strict graph schemas, so the union can't strip fields (the #2634 Greptile finding).

Validation performed

  • npx vitest run src — 5,127 passed. One failure, src/ida/IdaWorkspaceThinning.test.ts "copies exactly the selected slice when later slices follow it across read boundaries", fails identically on unmodified main on this host.
  • npm run test:focused -- with these files passes: interfaceBuilderSummaryMcp, nativeMachoSummaryMcp, nativeDemangleMcp, keyedArchivePrototypeKeyMcp, keyedArchiveNumberMetadataMcp, artifactMcp.inlineInventory, analysisSummaryDetailMcp, toolSchemaValidity, serverIdentity, managedArtifactSummaryMcp, wasmArtifactMcp, evmInterfaceMcp, androidPackageSummaryMcp, dartAotSummaryMcp, pcapRetainedView, analysisViewCli, analysisViewMcp, sazWebCapture, qlogCapture, retainedApplicationEvidenceMcp, binaryDiagnosticsMcp, interfaceBuilderUIKitKeyedArchive, dylibResolutionMcp, enhancedTools.01, keyedArchiveSelection, targetContentProvenance.
  • npm run check:fast, npm run typecheck, npm run format:check, npm run docs:check, npm run knip, npm run jscpd (2.98%), npm run verify:architecture-guards — pass.

Compatibility, safety, and release

  • Breaking changes or migration steps: none.
  • Real Hopper/Ghidra, browser, or OS coverage: macOS real apps (XLD, Transmission). The new tests use committed fixture archives and run on all platforms.
  • Package or release metadata impact: none beyond the regenerated catalog.
  • Security, privacy, process, or containment review: views read only retained Evidence; no new process, file or network effects.

Before merge

  • This PR addresses a concrete problem or an agreed enhancement.
  • Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🤖 Generated with Claude Code


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/2684 **Author:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Created:** 10/13/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `perf/interface-builder-summary` --- ### 📝 Commits (7) - [`f993d33`](https://github.com/morluto/rea/commit/f993d330281e05253d17e9822d3dd3c1ece95fae) perf(artifacts): add opt-in Interface Builder summary delivery and pages - [`da49ea2`](https://github.com/morluto/rea/commit/da49ea26928e49ee22dc45ceb690720a522661cb) fix(artifacts): describe incomplete Interface Builder graphs accurately - [`a92b960`](https://github.com/morluto/rea/commit/a92b960f6f1e19c2a9fae356b9fb41e2bb776fd6) fix(mcp): validate delivery detail before removing it - [`7b9ab77`](https://github.com/morluto/rea/commit/7b9ab778a1f5c4f9110ece1963bb9ccb63ac9aa8) fix(mcp): reject invalid delivery selections through typed preflight - [`94e360c`](https://github.com/morluto/rea/commit/94e360c11b7bd9af0320842d47c972fe24c8d418) test(artifacts): assert SDK argument rejection at its boundary - [`f3cd103`](https://github.com/morluto/rea/commit/f3cd103b313fcf9ccd3298251aec22ca6b6ec714) Merge remote-tracking branch 'origin/main' into HEAD - [`95bcaa0`](https://github.com/morluto/rea/commit/95bcaa07ef5a92764153357882c34f348f829b2a) Merge remote-tracking branch 'origin/main' into HEAD ### 📊 Changes **3 files changed** (+21 additions, -15 deletions) <details> <summary>View changed files</summary> 📝 `.agents/skills/reverse-engineer-anything/references/native-and-artifacts.md` (+5 -0) 📝 `src/domain/analysisView/webNetworkCaptureView.ts` (+4 -15) 📝 `tests/boundary/mcp/interfaceBuilderSummaryMcp.test.ts` (+12 -0) </details> ### 📄 Description ## Summary Over MCP, `decode_interface_builder` currently fails on ordinary apps. The complete graph for XLD.app is 6.7 MB (1,980,857 o200k tokens) and for Transmission.app 6.3 MB. The text and `structuredContent` copies together exceed the default 10 MiB response budget, so the caller gets `resource_constraint` ("its complete MCP response exceeds the stdio response budget") instead of an answer. A caller who only wants the windows, outlets or actions of one nib had no way to ask for less. This PR adds the same opt-in delivery #2634 added for `inspect_macho`, which WASM, EVM, managed, Android, Dart AOT and pcap already have. Refs #2016, #1065. ## Problem and expected behavior Smallest trigger: `open_binary /Applications/Transmission.app`, then `decode_interface_builder {}` returns `resource_constraint`. Expected: a first call can return a bounded answer while the complete Evidence stays retained for exact pages. ## Change and scope - `src/domain/analysisView/interfaceBuilderView.ts` (new) owns Interface Builder views. - **Summary:** returns every decoded document row (bounded at 64), the provider, `available_counts`, tallies by node kind, edge relation and coverage status, and decoder truncation. - **`kind: "interface-builder"` pages:** cover `documents`, `nodes`, `edges` or `coverage` in original order. For nodes and edges, an optional `document` keeps rows whose recorded `evidence[].artifact_path` equals that exact `documents[].relative_path`. That's the producer's own attribution; nothing is reparsed from IDs. An undecoded path is refused instead of returning an empty page. Every page carries `source_truncated`. - **Identity check:** the parent subject digest and `graph.target_sha256` must both equal `target_sha256`. - `decode_interface_builder` gets an optional `detail` and a complete-or-summary output schema. Delivery detail is stripped before execution and from Evidence parameters, so the summary's `parent_evidence_id` equals a complete call's Evidence ID. The preflight refuses `summary` before decoding when the server keeps no Evidence (the fix from #2634). - **Related cleanup:** the new view would have been the ninth copy of three patterns, pushing jscpd to 3.02% (threshold 3.0%). Each now has one owner: - `parseAnalysisViewResult` (`analysisViewParent.ts`) parses a parent's normalized result and maps issues into `source.normalized_result`. It replaces the identical blocks in the WASM, EVM, managed, Android, Dart AOT, web capture, Mach-O and IB views. - `retainedSummaryDelivery` / `withoutDeliveryDetail` (`retainedSummaryDelivery.ts`) own the preflight and summary hooks and the shared registration options type used by the artifact, native and managed registrations. - `openProductionTarget` (`tests/support/mcp/productionSession.ts`) owns the "production session plus `open_binary`" setup in five MCP tests. Duplication is now 2.98%. Behavior of the existing views and registrations is unchanged; their suites pass. - Docs: `docs/mcp-contracts.md`, `docs/native-investigation.md`, the skill reference, and the `inspect_analysis_view` description. Not included: changing the producer's representation. Nodes repeat the document path in `id`, `name` and evidence, and limitations list each `max_documents` omission; that's a contract question. The default stays complete, and the CLI is unchanged (`inspect-analysis-view` with inline Evidence already supports the new kind). Contribution scope: not applicable. This is the established opt-in delivery pattern with no new execution, mutation or authority. ## Contract and boundary impact - Semantic owner and earliest changed stage: projection of retained `decode_interface_builder` Evidence; MCP delivery selection in `registerArtifactTools`. - Contribution scope fit and linked maintainer decision: not applicable. - CLI and MCP/tool-catalog contract: additive. The new optional `detail` and summary output variant, and a new `interface-builder` view request/result. Omitted detail keeps the old result and Evidence identity. - Provider, bridge, target-format, or platform compatibility: none. The decoder receives the same parameters. - Evidence, artifact, provenance, or reconstruction contract: the complete Evidence and its ID are unchanged. Views are derived Evidence linked to the retained parent. - Generated metadata, package, or installation impact: catalog regenerated at build; `docs:check` passes. - [x] Read existing files or captured data. ## Evidence and regression coverage - `src/domain/analysisView/interfaceBuilderView.test.ts` (any platform) covers: - tallies and documents without rows - a document-filtered node page with offset - visible truncation - refusals for an unknown document, the wrong view kind, and a mismatched subject digest - `tests/boundary/mcp/interfaceBuilderSummaryMcp.test.ts` (any platform; production session, real `UIKitOutlet.xml` nib archives in a two-document `.app`) checks: - Omitted detail records no `detail`. - The summary documents and counts equal the complete result. - `parent_evidence_id` equals the complete Evidence ID. - All edges reassemble from 2-row pages. - A `document`-filtered node read equals the complete nodes attributed to that nib (and is a strict subset). - An unknown document is refused. ### Real applications (macOS, real MCP stdio, this branch) | App | complete over MCP | summary | 20 edges of one document | | --- | --- | --- | --- | | XLD.app (64 decoded nibs, 6,528 nodes) | `resource_constraint`; CLI JSON 6,734,711 B / 1,980,857 tok | 35,497 B / **10,090** tok | 6,989 tok | | Transmission.app (5,560 nodes) | `resource_constraint`; CLI JSON 6,313,752 B / 1,948,182 tok | 12,106 B / **3,762** tok | 5,034 tok | For both apps, the summary's parent equals the CLI complete Evidence ID, and paging every node 500 at a time reproduces all nodes exactly. Decoding takes 0.5–1.5 s for complete and summary alike (same analysis); each page takes about 30–40 ms. Tokens are o200k_base via tiktoken. CPU and peak memory weren't measured separately, because only delivery differs. About 7 KB of each XLD response is the producer's 69 limitations, and they appear twice (normalized result and Evidence envelope), as in every view. I left that envelope repetition alone. Catalog cost: `tools/list` grows from 687,395 to 690,367 o200k tokens (+2,972, +0.43%). `decode_interface_builder` adds 862 and `inspect_analysis_view` adds 2,110. Each page's rows use the existing strict graph schemas, so the union can't strip fields (the #2634 Greptile finding). ## Validation performed - `npx vitest run src` — 5,127 passed. One failure, `src/ida/IdaWorkspaceThinning.test.ts` "copies exactly the selected slice when later slices follow it across read boundaries", fails identically on unmodified main on this host. - `npm run test:focused --` with these files passes: `interfaceBuilderSummaryMcp`, `nativeMachoSummaryMcp`, `nativeDemangleMcp`, `keyedArchivePrototypeKeyMcp`, `keyedArchiveNumberMetadataMcp`, `artifactMcp.inlineInventory`, `analysisSummaryDetailMcp`, `toolSchemaValidity`, `serverIdentity`, `managedArtifactSummaryMcp`, `wasmArtifactMcp`, `evmInterfaceMcp`, `androidPackageSummaryMcp`, `dartAotSummaryMcp`, `pcapRetainedView`, `analysisViewCli`, `analysisViewMcp`, `sazWebCapture`, `qlogCapture`, `retainedApplicationEvidenceMcp`, `binaryDiagnosticsMcp`, `interfaceBuilderUIKitKeyedArchive`, `dylibResolutionMcp`, `enhancedTools.01`, `keyedArchiveSelection`, `targetContentProvenance`. - `npm run check:fast`, `npm run typecheck`, `npm run format:check`, `npm run docs:check`, `npm run knip`, `npm run jscpd` (2.98%), `npm run verify:architecture-guards` — pass. ## Compatibility, safety, and release - Breaking changes or migration steps: none. - Real Hopper/Ghidra, browser, or OS coverage: macOS real apps (XLD, Transmission). The new tests use committed fixture archives and run on all platforms. - Package or release metadata impact: none beyond the regenerated catalog. - Security, privacy, process, or containment review: views read only retained Evidence; no new process, file or network effects. ## Before merge - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] Material scope and authority questions are resolved, and any required maintainer scope decision covers the final diff. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 01:05:37 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#5310
No description provided.