[PR #2256] [CLOSED] fix(apple): preserve NIBArchive resource keys in catalog joins #5123

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

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/2256
Author: @thangldw
Created: 10/12/2026
Status: ❌ Closed

Base: main ← Head: codex/fix-nib-resource-keys


📝 Commits (1)

  • 7772c02 fix(apple): preserve NIBArchive resource keys in catalog joins

📊 Changes

5 files changed (+235 additions, -32 deletions)

View changed files

📝 src/artifacts/apple/AppleAssetCatalogAnalysis.test.ts (+58 -0)
📝 src/artifacts/apple/AppleAssetCatalogAnalysis.ts (+10 -26)
📝 src/artifacts/apple/InterfaceBuilderAnalysis.ts (+16 -6)
📝 src/domain/apple/appleAssetCatalog.ts (+23 -0)
➕ tests/acceptance/applications/assetCatalogResourceKeys.test.ts (+128 -0)

📄 Description

Summary

Fixes #2176.

Asset catalog inspection dropped recognized resource keys from decoded NIBArchive objects. Normalize those keys at the NIBArchive producer so CLI and MCP retain the resource-key join, including its source node, archive path and digest.

Problem and expected behavior

A rooted NIBArchive containing an NSImage with NSImageName: "Toolbar" was decoded correctly, but inspect-asset-catalog returned resource_key_matches: []. With no catalog, the result must instead contain an unmatched NSImageName / Toolbar row with no renditions. One matching rendition is matched; multiple matching renditions are ambiguous and retained.

Change and scope

Share the existing recognized-field allowlist and nonempty scalar predicate in the domain layer. The NIBArchive producer exposes those fields directly while preserving the original nibValues representation and charging added property/string occurrences to the decode budget. The catalog consumer continues to inspect direct fields; it does not reinterpret a keyed archive's authored nested dictionary named nibValues.

Related open PRs discovered during the final update: #2248 and #2249 also address #2176. This implementation normalizes only the disjoint recognized scalar allowlist at the actual NIBArchive producer, rather than identifying format by the presence of an authored nibValues dictionary. The public keyed nested-dictionary negative control covers the resulting distinction; original nested data is retained.

Contract and boundary impact

  • Semantic owner and earliest changed stage: NIBArchive field projection, before Interface Builder graph construction and catalog resource joins.
  • Contribution scope fit and linked maintainer decision: ordinary static-analysis correctness fix within existing boundaries; a new authority/provider scope decision is not applicable.
  • CLI and MCP/tool-catalog contract: unchanged schemas and tools; additive normalized direct attributes and restored resource-key rows.
  • Provider, bridge, target-format, or platform compatibility: existing NIBArchive and keyed-archive paths; no engine protocol changes.
  • Evidence, artifact, provenance, or reconstruction contract: original nibValues, source node, archive path/hash and input bytes remain preserved. Corrected output changes derived Evidence identity.
  • Target selection, authority, upstream behavior, and cleanup details: unchanged existing read-only workflow; target applications are not executed.
  • Generated metadata, package, or installation impact: no dependency/version change or committed generated output.

Expected effects:

  • Read existing files or captured data.
  • Launch or attach to a process. Existing catalog inspection invokes assetutil when catalogs are present; this patch adds no process or target-execution authority.
  • Inject instrumentation or run scripts/code.
  • Change process memory, registers, files, or configuration.
  • Contact network services.
  • Recover protected code or work around protections.
  • Documentation or usability only; no target interaction.
  • Not sure yet; investigation or maintainer guidance needed.

Evidence and regression coverage

  • Added compiled CLI/real stdio MCP regression using the exact inert NIBArchive fixture from #2176, with recognized alias, unrecognized title, keyed direct-field and keyed nested-dictionary controls. Assert exact source node/path/hash and adapter parity.

  • Original regression failed on main 59be866 because the expected unmatched row was absent. The keyed nested-dictionary control also failed against the initial consumer-only repair; producer normalization resolves that false interpretation.

  • Supplied assetutil metadata integration controls cover matched and ambiguous joins. Scalar-type, empty-value and arbitrary nested-field controls remain conservative.

  • Independent subagent review found the nested keyed-dictionary risk; after repair, independent re-review reported no actionable findings.

  • Remaining proof gaps: new resource-key fixtures are synthetic inert format bytes. Supplied metadata does not establish validity of a real Assets.car or native assetutil behavior for this fixture.

  • Observed, derived, and inferred claims remain distinguishable.

  • Artifact identity, source provenance, and failed attempts remain preserved.

  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

Node 24.18.0 / npm 11.16.0, macOS arm64, updated onto main d96550f without conflicts:

  • Focused regression, catalog workflow/projection, native artifact goldens, NIBArchive and Interface Builder bundle suites: 55 tests passed across 6 files. This includes actual Xcode-compiled storyboard NIB and Foundation-produced archive controls.
  • npm run check: passed typecheck, lint, formatting, knip, metadata, module boundaries and architecture guards.
  • npm run docs:check: passed generated-document checks and README consistency tests.
  • npm run verify:test-discovery: all 947 test files discovered exactly once.
  • git diff --check: passed.

Compatibility, safety, and release

  • Breaking changes or migration steps: none; original nested values retained, normalized fields added within existing attribute schema.
  • Real Hopper/Ghidra, browser, or OS coverage: CLI/MCP and Xcode/Foundation archive controls on macOS arm64; no Linux/Windows run. The public catalog regression is macOS-only because the production tool requires macOS.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: direct recognized fields only; no arbitrary nested-key inference, target execution, extraction or new authority. Added representation is accounted for in existing decode budgets.

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.

🔄 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/2256 **Author:** [@thangldw](https://github.com/thangldw) **Created:** 10/12/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `codex/fix-nib-resource-keys` --- ### 📝 Commits (1) - [`7772c02`](https://github.com/morluto/rea/commit/7772c021877b8f75685b42a2b85a952bd6156d46) fix(apple): preserve NIBArchive resource keys in catalog joins ### 📊 Changes **5 files changed** (+235 additions, -32 deletions) <details> <summary>View changed files</summary> 📝 `src/artifacts/apple/AppleAssetCatalogAnalysis.test.ts` (+58 -0) 📝 `src/artifacts/apple/AppleAssetCatalogAnalysis.ts` (+10 -26) 📝 `src/artifacts/apple/InterfaceBuilderAnalysis.ts` (+16 -6) 📝 `src/domain/apple/appleAssetCatalog.ts` (+23 -0) ➕ `tests/acceptance/applications/assetCatalogResourceKeys.test.ts` (+128 -0) </details> ### 📄 Description ## Summary Fixes #2176. Asset catalog inspection dropped recognized resource keys from decoded NIBArchive objects. Normalize those keys at the NIBArchive producer so CLI and MCP retain the resource-key join, including its source node, archive path and digest. ## Problem and expected behavior A rooted NIBArchive containing an NSImage with `NSImageName: "Toolbar"` was decoded correctly, but `inspect-asset-catalog` returned `resource_key_matches: []`. With no catalog, the result must instead contain an unmatched `NSImageName` / `Toolbar` row with no renditions. One matching rendition is matched; multiple matching renditions are ambiguous and retained. ## Change and scope Share the existing recognized-field allowlist and nonempty scalar predicate in the domain layer. The NIBArchive producer exposes those fields directly while preserving the original `nibValues` representation and charging added property/string occurrences to the decode budget. The catalog consumer continues to inspect direct fields; it does not reinterpret a keyed archive's authored nested dictionary named `nibValues`. Related open PRs discovered during the final update: #2248 and #2249 also address #2176. This implementation normalizes only the disjoint recognized scalar allowlist at the actual NIBArchive producer, rather than identifying format by the presence of an authored `nibValues` dictionary. The public keyed nested-dictionary negative control covers the resulting distinction; original nested data is retained. ## Contract and boundary impact - Semantic owner and earliest changed stage: NIBArchive field projection, before Interface Builder graph construction and catalog resource joins. - Contribution scope fit and linked maintainer decision: ordinary static-analysis correctness fix within existing boundaries; a new authority/provider scope decision is not applicable. - CLI and MCP/tool-catalog contract: unchanged schemas and tools; additive normalized direct attributes and restored resource-key rows. - Provider, bridge, target-format, or platform compatibility: existing NIBArchive and keyed-archive paths; no engine protocol changes. - Evidence, artifact, provenance, or reconstruction contract: original nibValues, source node, archive path/hash and input bytes remain preserved. Corrected output changes derived Evidence identity. - Target selection, authority, upstream behavior, and cleanup details: unchanged existing read-only workflow; target applications are not executed. - Generated metadata, package, or installation impact: no dependency/version change or committed generated output. Expected effects: - [x] Read existing files or captured data. - [x] Launch or attach to a process. Existing catalog inspection invokes assetutil when catalogs are present; this patch adds no process or target-execution authority. - [ ] Inject instrumentation or run scripts/code. - [ ] Change process memory, registers, files, or configuration. - [ ] Contact network services. - [ ] Recover protected code or work around protections. - [ ] Documentation or usability only; no target interaction. - [ ] Not sure yet; investigation or maintainer guidance needed. ## Evidence and regression coverage - Added compiled CLI/real stdio MCP regression using the exact inert NIBArchive fixture from #2176, with recognized alias, unrecognized title, keyed direct-field and keyed nested-dictionary controls. Assert exact source node/path/hash and adapter parity. - Original regression failed on main `59be866` because the expected unmatched row was absent. The keyed nested-dictionary control also failed against the initial consumer-only repair; producer normalization resolves that false interpretation. - Supplied assetutil metadata integration controls cover matched and ambiguous joins. Scalar-type, empty-value and arbitrary nested-field controls remain conservative. - Independent subagent review found the nested keyed-dictionary risk; after repair, independent re-review reported no actionable findings. - Remaining proof gaps: new resource-key fixtures are synthetic inert format bytes. Supplied metadata does not establish validity of a real Assets.car or native assetutil behavior for this fixture. - [x] Observed, derived, and inferred claims remain distinguishable. - [x] Artifact identity, source provenance, and failed attempts remain preserved. - [x] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed Node 24.18.0 / npm 11.16.0, macOS arm64, updated onto main `d96550f` without conflicts: - Focused regression, catalog workflow/projection, native artifact goldens, NIBArchive and Interface Builder bundle suites: 55 tests passed across 6 files. This includes actual Xcode-compiled storyboard NIB and Foundation-produced archive controls. - `npm run check`: passed typecheck, lint, formatting, knip, metadata, module boundaries and architecture guards. - `npm run docs:check`: passed generated-document checks and README consistency tests. - `npm run verify:test-discovery`: all 947 test files discovered exactly once. - `git diff --check`: passed. ## Compatibility, safety, and release - Breaking changes or migration steps: none; original nested values retained, normalized fields added within existing attribute schema. - Real Hopper/Ghidra, browser, or OS coverage: CLI/MCP and Xcode/Foundation archive controls on macOS arm64; no Linux/Windows run. The public catalog regression is macOS-only because the production tool requires macOS. - Package or release metadata impact: none. - Security, privacy, process, or containment review: direct recognized fields only; no arbitrary nested-key inference, target execution, extraction or new authority. Added representation is accounted for in existing decode budgets. ## 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. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 01:04:09 +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#5123
No description provided.