[PR #870] [MERGED] fix(artifacts): read keyed archive dictionaries keyed UID as dictionaries #2305

Closed
opened 2026-10-16 21:17:03 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/870
Author: @kaoru0822-kitauji
Created: 10/7/2026
Status: ✅ Merged
Merged: 10/7/2026
Merged by: @kaoru0822-kitauji

Base: main ← Head: fix/keyed-archive-uid-named-keys


📝 Commits (1)

  • 35c82b9 fix(artifacts): read keyed archive dictionaries keyed UID as dictionaries

📊 Changes

4 files changed (+87 additions, -11 deletions)

View changed files

📝 scripts/verify-keyed-archive.mjs (+34 -1)
📝 src/artifacts/KeyedArchiveReader.test.ts (+35 -0)
📝 src/domain/keyedArchive.ts (+11 -10)
➕ tests/conformance/native/keyed-archive-uid-root.swift (+7 -0)

📄 Description

Summary

inspect_keyed_archive / rea inspect-keyed-archive treated every dictionary with exactly one UID or CF$UID key as a reference marker, whatever its value. Real Foundation output contains such dictionaries that are not references. NSKeyedArchiver.encode(_:forKey: "UID") produces:

"$top" => { "UID" => <CFKeyedArchiverUID>{value = 1} }

Before this change, the binary and XML forms both reported the whole $top as one malformed reference and lost the actual root link:

{"references":[{"source":null,"path":[],"target":null,"status":"malformed","raw":{"UID":{"UID":1}}}]}

After it, the root reference resolves:

{"references":[{"source":null,"path":["UID"],"target":1,"status":"resolved","raw":{"UID":1}}]}

A one-key dictionary now counts as a UID only when its value is a number. That matches the plist binary decoder's UID shape ({UID: n}) and Foundation's XML rule, which reads a CF$UID dictionary as a UID only when its value is an integer. A dictionary with any other value is walked as an ordinary dictionary. Numeric markers that are negative, fractional, or beyond the safe-integer range are still reported as malformed, as before.

No schema or catalog change.

Verification

  • src/artifacts/KeyedArchiveReader.test.ts: a new case resolves binary and XML roots named UID and CF$UID, including --root UID selection. It fails on main.
  • npm run verify:keyed-archive (real Foundation via xcrun swift, CLI plus stdio MCP) now also archives a root under the key UID (tests/conformance/native/keyed-archive-uid-root.swift). It checks the binary output and the plutil -convert xml1 output, and asserts that the root reference resolves. That assertion fails on main with status: 'malformed'. The existing XML golden graph is unchanged.
  • npm run check:changed, npm run docs:check, and tests/boundary/providers/native/keyedArchiveEncoding.test.ts pass.

No Hopper/Ghidra/IDA verification is needed.

🤖 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/870 **Author:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Created:** 10/7/2026 **Status:** ✅ Merged **Merged:** 10/7/2026 **Merged by:** [@kaoru0822-kitauji](https://github.com/kaoru0822-kitauji) **Base:** `main` ← **Head:** `fix/keyed-archive-uid-named-keys` --- ### 📝 Commits (1) - [`35c82b9`](https://github.com/morluto/rea/commit/35c82b93eb2579687bb446c3a8a2a9f1a7563d28) fix(artifacts): read keyed archive dictionaries keyed UID as dictionaries ### 📊 Changes **4 files changed** (+87 additions, -11 deletions) <details> <summary>View changed files</summary> 📝 `scripts/verify-keyed-archive.mjs` (+34 -1) 📝 `src/artifacts/KeyedArchiveReader.test.ts` (+35 -0) 📝 `src/domain/keyedArchive.ts` (+11 -10) ➕ `tests/conformance/native/keyed-archive-uid-root.swift` (+7 -0) </details> ### 📄 Description ## Summary `inspect_keyed_archive` / `rea inspect-keyed-archive` treated every dictionary with exactly one `UID` or `CF$UID` key as a reference marker, whatever its value. Real Foundation output contains such dictionaries that are not references. `NSKeyedArchiver.encode(_:forKey: "UID")` produces: ``` "$top" => { "UID" => <CFKeyedArchiverUID>{value = 1} } ``` Before this change, the binary and XML forms both reported the whole `$top` as one malformed reference and lost the actual root link: ```json {"references":[{"source":null,"path":[],"target":null,"status":"malformed","raw":{"UID":{"UID":1}}}]} ``` After it, the root reference resolves: ```json {"references":[{"source":null,"path":["UID"],"target":1,"status":"resolved","raw":{"UID":1}}]} ``` A one-key dictionary now counts as a UID only when its value is a number. That matches the `plist` binary decoder's UID shape (`{UID: n}`) and Foundation's XML rule, which reads a `CF$UID` dictionary as a UID only when its value is an integer. A dictionary with any other value is walked as an ordinary dictionary. Numeric markers that are negative, fractional, or beyond the safe-integer range are still reported as `malformed`, as before. No schema or catalog change. ## Verification - `src/artifacts/KeyedArchiveReader.test.ts`: a new case resolves binary and XML roots named `UID` and `CF$UID`, including `--root UID` selection. It fails on `main`. - `npm run verify:keyed-archive` (real Foundation via `xcrun swift`, CLI plus stdio MCP) now also archives a root under the key `UID` (`tests/conformance/native/keyed-archive-uid-root.swift`). It checks the binary output and the `plutil -convert xml1` output, and asserts that the root reference resolves. That assertion fails on `main` with `status: 'malformed'`. The existing XML golden graph is unchanged. - `npm run check:changed`, `npm run docs:check`, and `tests/boundary/providers/native/keyedArchiveEncoding.test.ts` pass. No Hopper/Ghidra/IDA verification is needed. 🤖 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-16 21:17:03 +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#2305
No description provided.