[GH-ISSUE #7689] [Bug] Apple IPS inspection omits unknown key names inside thread, frame and image rows #4611

Open
opened 2026-10-31 00:51:18 +00:00 by bsakaguchi · 0 comments
Owner

Originally created by @coygeek on GitHub (Oct 28, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/7689

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Evidence, artifacts, or reconstruction

Observed behavior

node scripts/rea.mjs inspect-apple-ips "$d/nested.ips" --json succeeds for a valid synthetic 309 crash report, but the returned Evidence contains neither unknownThreadKey, unknownFrameKey nor unknownImageKey, although those members exist on an examined thread, frame and image row. unlisted_body_keys is empty and coverage is complete.

Moving the same unknownThreadKey name to the body itself or to metadata records its name in the corresponding unlisted-key array. Those controls also return complete coverage. Unknown values are absent in every case; this report concerns the missing nested key names.

Reproduction

  1. From the already-built baseline checkout, with Node v24.22.1, create a reduced fixture and two controls:
d="$(mktemp -d)"
node --input-type=module - "$d" <<'JS'
import { writeFileSync } from 'node:fs';
const directory = process.argv[2];
const metadata = { bug_type: '309', name: 'ips-key-fixture' };
const body = {
  procName: 'ips-key-fixture', faultingThread: 0,
  threads: [{ id: 1, triggered: true, unknownThreadKey: 'VERIFY_THREAD_VALUE',
    frames: [{ imageIndex: 0, imageOffset: 8, symbol: 'fixture_fault',
      symbolLocation: 0, unknownFrameKey: 'VERIFY_FRAME_VALUE' }] }],
  usedImages: [{ source: 'P', arch: 'arm64', base: 4294967296, size: 16384,
    uuid: 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', name: 'ips-key-fixture',
    unknownImageKey: 'VERIFY_IMAGE_VALUE' }]
};
for (const mode of ['nested', 'top-control', 'metadata-control']) {
  const m = structuredClone(metadata), b = structuredClone(body);
  if (mode === 'top-control') b.unknownThreadKey = 'VERIFY_TOP_CONTROL_VALUE';
  if (mode === 'metadata-control') m.unknownThreadKey = 'VERIFY_METADATA_CONTROL_VALUE';
  writeFileSync(`${directory}/${mode}.ips`, JSON.stringify(m) + '\n' + JSON.stringify(b));
}
JS
  1. Run each through the public CLI:
node scripts/rea.mjs inspect-apple-ips "$d/nested.ips" --json
node scripts/rea.mjs inspect-apple-ips "$d/top-control.ips" --json
node scripts/rea.mjs inspect-apple-ips "$d/metadata-control.ips" --json
  1. Inspect the entire serialized Evidence for the three key names and the VERIFY_* values. The nested fixture has none of them. The body control has unlisted_body_keys: ["unknownThreadKey"]; the metadata control has metadata.unlisted_keys: ["unknownThreadKey"]. Every run returns complete coverage with one thread, one frame, one image and zero registers.

The reduced nested fixture reproduced three times in three runs; each control was run once. A fuller fixture generated from the repository's ReportCrash fixture reproduced twice, with the same control behavior. The verifier isolated HOME/XDG and put refusing npx/npm/bun fixtures first on PATH during all REA runs. No package manager was needed.

Expected behavior

Retain the names of unknown immediate members on examined thread, frame and image rows in the returned unlisted-key information. The documented promise applies without a restriction to direct body members; the relevant documentation and implementation locators are below. This does not require retaining unknown values or recursively examining uninterpreted subtrees. A coverage-status change is not asserted as necessary.

Impact and scope

P2: consumers of the returned Evidence cannot discover that an examined row contained these additional producer keys, despite the documented name-retention promise. The known crash facts still parse, and the original input remains intact. A safe workaround is to inspect the original JSON's immediate row keys directly, which was possible for both generated fixtures. The observed scope is the three injected member locations through CLI on macOS; real-world occurrence rates, other nested objects, other platforms and MCP were not tested.

REA version

Exact node scripts/rea.mjs --version stdout: 6.8.0.
Source baseline: 65f1c447344a423fa2785847dbcea1e9a9e2454a.

Runtime and platform

Node v24.22.1; macOS 27.0.1 (26A434); arm64. No analysis provider was required.

Target and artifact context

Synthetic two-object Apple IPS crash report with string bug_type 309, one valid faulting-thread reference, one frame and one arm64 image. The fixture is fully inline above and requires no target execution.

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

All five reduced-fixture CLI runs exited 0 with empty stderr. The following fields came from normalized_result for the nested fixture:

{"coverage":{"status":"complete","reason":null,"threads":1,"frames":1,"images":1,"registers":0,"type_mismatches":[]},"unlisted_body_keys":[],"metadata_unlisted_keys":[]}

Here metadata_unlisted_keys summarizes metadata.unlisted_keys; it is not a separate output field. Searching the complete serialized Evidence returned false for each of unknownThreadKey, unknownFrameKey, unknownImageKey, VERIFY_THREAD_VALUE, VERIFY_FRAME_VALUE and VERIFY_IMAGE_VALUE.

The controls retain unknownThreadKey by name only, in the body and metadata arrays respectively. Neither control retains its marker value, and both report complete coverage.

Contract: docs/apple-ips.md:63-64 promises retention of unlisted key names without specifying an object-depth restriction. Lines 94-100 describe bounded projection and syntax-checking of uninterpreted values. These statements support preserving immediate names on examined report rows while skipping their values.

Source at the stated baseline: src/native/apple/AppleIpsJsonShape.ts:70-113 and :182-196 define thread/frame/image projections without beforeUnlisted; src/native/apple/losslessJson.ts:176-185 retains names only when that callback exists. src/native/apple/AppleIpsParser.ts:453 copies the body's own unlisted list. The row output schemas at src/domain/native/appleIps.ts:160-207 have no unlisted-key member. Existing tests at src/native/apple/AppleIpsParser.test.ts:918-925 expect complete coverage while retaining an uninterpreted top-level member's name.

Analysis or suspected cause

Source-derived explanation: the nested row projections skip unknown values without collecting their names, and the result schemas have no row-level unlisted list. The runtime controls show that name collection already works for direct body and metadata members. The current documentation gives no exception for examined nested rows.

Additional context

Duplicate searches covered open and closed issues, all-state PRs, and issue comments using IPS, unlisted, unknown, nested, unlisted_body_keys and the injected key names. Related closed issues #7060 and #7078, with merged PRs #7059 and #7079, restore specific documented values rather than generic unknown names. PR #6990 addresses Unicode validation. PR #6511 introduced the parser. Issue #4297 remains open for Mach-O/dSYM joins and symbol resolution according to its owner comment; its outstanding outcome differs from this defect. No matching report was found.

Originally created by @coygeek on GitHub (Oct 28, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7689 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Evidence, artifacts, or reconstruction ### Observed behavior `node scripts/rea.mjs inspect-apple-ips "$d/nested.ips" --json` succeeds for a valid synthetic 309 crash report, but the returned Evidence contains neither `unknownThreadKey`, `unknownFrameKey` nor `unknownImageKey`, although those members exist on an examined thread, frame and image row. `unlisted_body_keys` is empty and coverage is `complete`. Moving the same `unknownThreadKey` name to the body itself or to metadata records its name in the corresponding unlisted-key array. Those controls also return complete coverage. Unknown values are absent in every case; this report concerns the missing nested key names. ### Reproduction 1. From the already-built baseline checkout, with Node v24.22.1, create a reduced fixture and two controls: ```sh d="$(mktemp -d)" node --input-type=module - "$d" <<'JS' import { writeFileSync } from 'node:fs'; const directory = process.argv[2]; const metadata = { bug_type: '309', name: 'ips-key-fixture' }; const body = { procName: 'ips-key-fixture', faultingThread: 0, threads: [{ id: 1, triggered: true, unknownThreadKey: 'VERIFY_THREAD_VALUE', frames: [{ imageIndex: 0, imageOffset: 8, symbol: 'fixture_fault', symbolLocation: 0, unknownFrameKey: 'VERIFY_FRAME_VALUE' }] }], usedImages: [{ source: 'P', arch: 'arm64', base: 4294967296, size: 16384, uuid: 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', name: 'ips-key-fixture', unknownImageKey: 'VERIFY_IMAGE_VALUE' }] }; for (const mode of ['nested', 'top-control', 'metadata-control']) { const m = structuredClone(metadata), b = structuredClone(body); if (mode === 'top-control') b.unknownThreadKey = 'VERIFY_TOP_CONTROL_VALUE'; if (mode === 'metadata-control') m.unknownThreadKey = 'VERIFY_METADATA_CONTROL_VALUE'; writeFileSync(`${directory}/${mode}.ips`, JSON.stringify(m) + '\n' + JSON.stringify(b)); } JS ``` 2. Run each through the public CLI: ```sh node scripts/rea.mjs inspect-apple-ips "$d/nested.ips" --json node scripts/rea.mjs inspect-apple-ips "$d/top-control.ips" --json node scripts/rea.mjs inspect-apple-ips "$d/metadata-control.ips" --json ``` 3. Inspect the entire serialized Evidence for the three key names and the `VERIFY_*` values. The nested fixture has none of them. The body control has `unlisted_body_keys: ["unknownThreadKey"]`; the metadata control has `metadata.unlisted_keys: ["unknownThreadKey"]`. Every run returns complete coverage with one thread, one frame, one image and zero registers. The reduced nested fixture reproduced three times in three runs; each control was run once. A fuller fixture generated from the repository's ReportCrash fixture reproduced twice, with the same control behavior. The verifier isolated HOME/XDG and put refusing npx/npm/bun fixtures first on PATH during all REA runs. No package manager was needed. ### Expected behavior Retain the names of unknown immediate members on examined thread, frame and image rows in the returned unlisted-key information. The documented promise applies without a restriction to direct body members; the relevant documentation and implementation locators are below. This does not require retaining unknown values or recursively examining uninterpreted subtrees. A coverage-status change is not asserted as necessary. ### Impact and scope P2: consumers of the returned Evidence cannot discover that an examined row contained these additional producer keys, despite the documented name-retention promise. The known crash facts still parse, and the original input remains intact. A safe workaround is to inspect the original JSON's immediate row keys directly, which was possible for both generated fixtures. The observed scope is the three injected member locations through CLI on macOS; real-world occurrence rates, other nested objects, other platforms and MCP were not tested. ### REA version Exact `node scripts/rea.mjs --version` stdout: `6.8.0`. Source baseline: `65f1c447344a423fa2785847dbcea1e9a9e2454a`. ### Runtime and platform Node v24.22.1; macOS 27.0.1 (26A434); arm64. No analysis provider was required. ### Target and artifact context Synthetic two-object Apple IPS crash report with string bug_type 309, one valid faulting-thread reference, one frame and one arm64 image. The fixture is fully inline above and requires no target execution. ### Interface CLI ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence All five reduced-fixture CLI runs exited 0 with empty stderr. The following fields came from `normalized_result` for the nested fixture: ```json {"coverage":{"status":"complete","reason":null,"threads":1,"frames":1,"images":1,"registers":0,"type_mismatches":[]},"unlisted_body_keys":[],"metadata_unlisted_keys":[]} ``` Here `metadata_unlisted_keys` summarizes `metadata.unlisted_keys`; it is not a separate output field. Searching the complete serialized Evidence returned false for each of `unknownThreadKey`, `unknownFrameKey`, `unknownImageKey`, `VERIFY_THREAD_VALUE`, `VERIFY_FRAME_VALUE` and `VERIFY_IMAGE_VALUE`. The controls retain `unknownThreadKey` by name only, in the body and metadata arrays respectively. Neither control retains its marker value, and both report complete coverage. Contract: `docs/apple-ips.md:63-64` promises retention of unlisted key names without specifying an object-depth restriction. Lines 94-100 describe bounded projection and syntax-checking of uninterpreted values. These statements support preserving immediate names on examined report rows while skipping their values. Source at the stated baseline: `src/native/apple/AppleIpsJsonShape.ts:70-113` and `:182-196` define thread/frame/image projections without `beforeUnlisted`; `src/native/apple/losslessJson.ts:176-185` retains names only when that callback exists. `src/native/apple/AppleIpsParser.ts:453` copies the body's own unlisted list. The row output schemas at `src/domain/native/appleIps.ts:160-207` have no unlisted-key member. Existing tests at `src/native/apple/AppleIpsParser.test.ts:918-925` expect complete coverage while retaining an uninterpreted top-level member's name. ### Analysis or suspected cause Source-derived explanation: the nested row projections skip unknown values without collecting their names, and the result schemas have no row-level unlisted list. The runtime controls show that name collection already works for direct body and metadata members. The current documentation gives no exception for examined nested rows. ### Additional context Duplicate searches covered open and closed issues, all-state PRs, and issue comments using IPS, unlisted, unknown, nested, unlisted_body_keys and the injected key names. Related closed issues #7060 and #7078, with merged PRs #7059 and #7079, restore specific documented values rather than generic unknown names. PR #6990 addresses Unicode validation. PR #6511 introduced the parser. Issue #4297 remains open for Mach-O/dSYM joins and symbol resolution according to its owner comment; its outstanding outcome differs from this defect. No matching report was found.
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#4611
No description provided.