[GH-ISSUE #5541] [Bug] decode-interface-builder reverses boolean values in compiled AppKit nibs #3375

Closed
opened 2026-10-31 00:39:41 +00:00 by bsakaguchi · 1 comment
Owner

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

Originally assigned to: @kaoru0822-kitauji on GitHub.

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 "$checkout/scripts/rea.mjs" decode-interface-builder "$workdir/Fixture.app" --json succeeds but reverses boolean values from a real Apple-compiled AppKit NIBArchive. For the NSButton node, attributes.nibValues.NSControlContinuous and NSControlRefusesFirstResponder are true when the source exports false, and false when a separately compiled input exports true. Both CLI decodes exit 0.

Reproduction

An independent verifier executed this complete script from the baseline checkout with dependencies installed and the runtime built using npm run build:cached. Prerequisites: macOS, Xcode with ibtool and a C compiler, Node.js, and Python 3. It creates an isolated fixture bundle and configuration, compiles two inputs, and compares the public CLI result with ibtool --export. It does not launch the fixture executable. The final script replay reproduced both polarities; broader frequency was not measured.

set -eu
checkout="$PWD"
workdir="$(mktemp -d)"
cd "$workdir"
export HOME="$workdir/home" XDG_CONFIG_HOME="$workdir/config" XDG_DATA_HOME="$workdir/data" XDG_CACHE_HOME="$workdir/cache" XDG_STATE_HOME="$workdir/state" TMPDIR="$workdir/temp"
mkdir -p "$HOME" "$XDG_CONFIG_HOME" "$XDG_DATA_HOME" "$XDG_CACHE_HOME" "$XDG_STATE_HOME" "$TMPDIR" Fixture.app/Contents/MacOS Fixture.app/Contents/Resources
cp "$checkout/tests/conformance/interface-builder/Main.xib" Main.xib
xcrun clang "$checkout/tests/conformance/interface-builder/fixture.c" -o Fixture.app/Contents/MacOS/Fixture
python3 - <<'PY'
import plistlib
from pathlib import Path
Path('Fixture.app/Contents/Info.plist').write_bytes(plistlib.dumps({'CFBundleExecutable': 'Fixture', 'CFBundleIdentifier': 'dev.rea.fixture'}))
Path('export.plist').write_bytes(plistlib.dumps({'NSControl': ['continuous', 'refusesFirstResponder']}))
Path('changes.plist').write_bytes(plistlib.dumps({'button': {'continuous': True, 'refusesFirstResponder': True}}))
PY
xcrun ibtool --import changes.plist --write Toggled.xib Main.xib
for name in Main Toggled; do
  xcrun ibtool --errors --warnings --compile Fixture.app/Contents/Resources/Main.nib "$name.xib" > "$name.compile.plist"
  xcrun ibtool --export export.plist "$name.xib" > "$name.export.plist"
  node "$checkout/scripts/rea.mjs" decode-interface-builder "$workdir/Fixture.app" --json > "$name.json"
done
python3 - <<'PY'
import json, plistlib
from pathlib import Path
for name in ['Main', 'Toggled']:
    exported = plistlib.loads(Path(name + '.export.plist').read_bytes())['com.apple.ibtool.document.export']['button']
    result = json.loads(Path(name + '.json').read_text())['normalized_result']
    button = next(n for n in result['graph']['nodes'] if n.get('attributes', {}).get('class_name') == 'NSButton')
    values = button['attributes']['nibValues']
    print(name, 'export:', exported)
    print(name, 'REA:', {k: values[k] for k in ['NSControlContinuous', 'NSControlRefusesFirstResponder', 'NSControlSize', 'NSFrame']})
PY

Expected behavior

Main must decode both named boolean fields as false, and Toggled must decode both as true, matching the respective property exports. docs/native-investigation.md:383 promises decoding compiled nib/storyboard resources into objects; src/contracts/artifactToolContracts.ts:91-99 includes NIBArchive object tables; docs/tool-design.md (Define the contract) requires returned facts and explicit unknowns. The concrete independent oracle is Apple's ibtool --export for each source used to compile the NIB. This expectation concerns serialized fields, not inferred runtime UI state.

Impact and scope

P2: callers receive incorrect control-property evidence within an otherwise usable static graph. Both directions were observed for these two fields in independently compiled AppKit inputs. NSControlSize remained integer 0 and NSFrame retained the same string in both results. Other archive forms and storyboard scenes were not executed, and this does not establish that every semantically boolean property uses the same tags. Severe workflow failure or data loss was not demonstrated. A practical workaround for compiled-only bundles was not verified; the source export oracle requires the source document.

REA version

rea-agents 6.7.0; source commit 074768901f3cdc8205b61773fb1faf6f6c7b3ca8.

Runtime and platform

Node.js v26.12.0; macOS 27.0.1; Xcode 27.1 build 27A9275; ibtool 27.1 bundle 25098. NOT_ENOUGH_INFO: the verifier's environment record does not state CPU architecture. No Hopper/Ghidra provider was used.

Target and artifact context

Isolated executable app bundle containing a real Apple-compiled AppKit NIBArchive, built from tests/conformance/interface-builder/Main.xib and fixture.c. No target application launch was performed.

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

The executed script above printed:

Main export: {'continuous': False, 'refusesFirstResponder': False}
Main REA: {'NSControlContinuous': True, 'NSControlRefusesFirstResponder': True, 'NSControlSize': 0, 'NSFrame': '{{180, 140}, {120, 32}}'}
Toggled export: {'continuous': True, 'refusesFirstResponder': True}
Toggled REA: {'NSControlContinuous': False, 'NSControlRefusesFirstResponder': False, 'NSControlSize': 0, 'NSFrame': '{{180, 140}, {120, 32}}'}

The returned fields are on the NSButton node in normalized_result.graph.nodes. Independent compiled-value-table inspection found tag 4 for both false fields in Main and tag 5 for both true fields in Toggled. Both property exports, compilations, and CLI decodes succeeded. The verifier ran the public reproduction; the submission stage checked upstream freshness and duplicates without claiming another runtime replay.

Typed outcome or recovery expected

Return the stored boolean polarity faithfully. Proposed restoration check: rerun both compiler-produced inputs through the public CLI, requiring false/false for Main and true/true for Toggled while retaining the compared integer and frame-string values. A synthetic round trip alone is insufficient when its encoder shares the decoder's assumption.

Analysis or suspected cause

Source-derived corroboration at the tested commit: src/artifacts/apple/NibArchive.ts:378-381 maps tag 4 to true and tag 5 to false, opposite the independently inspected compiler-produced values. src/artifacts/apple/InterfaceBuilderAnalysis.ts:455-457 preserves these scalars during graph projection. The synthetic encoder at src/artifacts/apple/NibArchive.fixture.ts:78 shares the reversed mapping. The shared reader supports broader inversion for actual tag-4/tag-5 fields; that broader scope was not measured with a corpus.

Additional context

Prepared with AI assistance and independently reproduced through the production CLI. MCP was not exercised. No implementation or restoration was attempted.

The upstream freshness check found no changes since the tested baseline in the cited decoder and contract files through origin/main at fa36657251a6e51c1a591146c5a7cdf5bc890d80; this was a source check, not a runtime replay on that revision. Searches covered open and closed issues and PRs using the command, boolean symptom, NIBArchive module, and exact affected field names. Related #5540 concerns object-limit diagnostics, a separate defect; #480 is the original feature request.

NOT_ENOUGH_INFO: the last known good version and regression introduction have not been established.

Originally created by @coygeek on GitHub (Oct 20, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5541 Originally assigned to: @kaoru0822-kitauji on GitHub. ### 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 "$checkout/scripts/rea.mjs" decode-interface-builder "$workdir/Fixture.app" --json` succeeds but reverses boolean values from a real Apple-compiled AppKit NIBArchive. For the NSButton node, `attributes.nibValues.NSControlContinuous` and `NSControlRefusesFirstResponder` are true when the source exports false, and false when a separately compiled input exports true. Both CLI decodes exit 0. ### Reproduction An independent verifier executed this complete script from the baseline checkout with dependencies installed and the runtime built using `npm run build:cached`. Prerequisites: macOS, Xcode with `ibtool` and a C compiler, Node.js, and Python 3. It creates an isolated fixture bundle and configuration, compiles two inputs, and compares the public CLI result with `ibtool --export`. It does not launch the fixture executable. The final script replay reproduced both polarities; broader frequency was not measured. ```sh set -eu checkout="$PWD" workdir="$(mktemp -d)" cd "$workdir" export HOME="$workdir/home" XDG_CONFIG_HOME="$workdir/config" XDG_DATA_HOME="$workdir/data" XDG_CACHE_HOME="$workdir/cache" XDG_STATE_HOME="$workdir/state" TMPDIR="$workdir/temp" mkdir -p "$HOME" "$XDG_CONFIG_HOME" "$XDG_DATA_HOME" "$XDG_CACHE_HOME" "$XDG_STATE_HOME" "$TMPDIR" Fixture.app/Contents/MacOS Fixture.app/Contents/Resources cp "$checkout/tests/conformance/interface-builder/Main.xib" Main.xib xcrun clang "$checkout/tests/conformance/interface-builder/fixture.c" -o Fixture.app/Contents/MacOS/Fixture python3 - <<'PY' import plistlib from pathlib import Path Path('Fixture.app/Contents/Info.plist').write_bytes(plistlib.dumps({'CFBundleExecutable': 'Fixture', 'CFBundleIdentifier': 'dev.rea.fixture'})) Path('export.plist').write_bytes(plistlib.dumps({'NSControl': ['continuous', 'refusesFirstResponder']})) Path('changes.plist').write_bytes(plistlib.dumps({'button': {'continuous': True, 'refusesFirstResponder': True}})) PY xcrun ibtool --import changes.plist --write Toggled.xib Main.xib for name in Main Toggled; do xcrun ibtool --errors --warnings --compile Fixture.app/Contents/Resources/Main.nib "$name.xib" > "$name.compile.plist" xcrun ibtool --export export.plist "$name.xib" > "$name.export.plist" node "$checkout/scripts/rea.mjs" decode-interface-builder "$workdir/Fixture.app" --json > "$name.json" done python3 - <<'PY' import json, plistlib from pathlib import Path for name in ['Main', 'Toggled']: exported = plistlib.loads(Path(name + '.export.plist').read_bytes())['com.apple.ibtool.document.export']['button'] result = json.loads(Path(name + '.json').read_text())['normalized_result'] button = next(n for n in result['graph']['nodes'] if n.get('attributes', {}).get('class_name') == 'NSButton') values = button['attributes']['nibValues'] print(name, 'export:', exported) print(name, 'REA:', {k: values[k] for k in ['NSControlContinuous', 'NSControlRefusesFirstResponder', 'NSControlSize', 'NSFrame']}) PY ``` ### Expected behavior Main must decode both named boolean fields as false, and Toggled must decode both as true, matching the respective property exports. `docs/native-investigation.md:383` promises decoding compiled nib/storyboard resources into objects; `src/contracts/artifactToolContracts.ts:91-99` includes NIBArchive object tables; `docs/tool-design.md` (Define the contract) requires returned facts and explicit unknowns. The concrete independent oracle is Apple's `ibtool --export` for each source used to compile the NIB. This expectation concerns serialized fields, not inferred runtime UI state. ### Impact and scope P2: callers receive incorrect control-property evidence within an otherwise usable static graph. Both directions were observed for these two fields in independently compiled AppKit inputs. `NSControlSize` remained integer 0 and `NSFrame` retained the same string in both results. Other archive forms and storyboard scenes were not executed, and this does not establish that every semantically boolean property uses the same tags. Severe workflow failure or data loss was not demonstrated. A practical workaround for compiled-only bundles was not verified; the source export oracle requires the source document. ### REA version rea-agents 6.7.0; source commit `074768901f3cdc8205b61773fb1faf6f6c7b3ca8`. ### Runtime and platform Node.js v26.12.0; macOS 27.0.1; Xcode 27.1 build 27A9275; ibtool 27.1 bundle 25098. NOT_ENOUGH_INFO: the verifier's environment record does not state CPU architecture. No Hopper/Ghidra provider was used. ### Target and artifact context Isolated executable app bundle containing a real Apple-compiled AppKit NIBArchive, built from `tests/conformance/interface-builder/Main.xib` and `fixture.c`. No target application launch was performed. ### Interface CLI ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence The executed script above printed: ```text Main export: {'continuous': False, 'refusesFirstResponder': False} Main REA: {'NSControlContinuous': True, 'NSControlRefusesFirstResponder': True, 'NSControlSize': 0, 'NSFrame': '{{180, 140}, {120, 32}}'} Toggled export: {'continuous': True, 'refusesFirstResponder': True} Toggled REA: {'NSControlContinuous': False, 'NSControlRefusesFirstResponder': False, 'NSControlSize': 0, 'NSFrame': '{{180, 140}, {120, 32}}'} ``` The returned fields are on the NSButton node in `normalized_result.graph.nodes`. Independent compiled-value-table inspection found tag 4 for both false fields in Main and tag 5 for both true fields in Toggled. Both property exports, compilations, and CLI decodes succeeded. The verifier ran the public reproduction; the submission stage checked upstream freshness and duplicates without claiming another runtime replay. ### Typed outcome or recovery expected Return the stored boolean polarity faithfully. Proposed restoration check: rerun both compiler-produced inputs through the public CLI, requiring false/false for Main and true/true for Toggled while retaining the compared integer and frame-string values. A synthetic round trip alone is insufficient when its encoder shares the decoder's assumption. ### Analysis or suspected cause Source-derived corroboration at the tested commit: `src/artifacts/apple/NibArchive.ts:378-381` maps tag 4 to true and tag 5 to false, opposite the independently inspected compiler-produced values. `src/artifacts/apple/InterfaceBuilderAnalysis.ts:455-457` preserves these scalars during graph projection. The synthetic encoder at `src/artifacts/apple/NibArchive.fixture.ts:78` shares the reversed mapping. The shared reader supports broader inversion for actual tag-4/tag-5 fields; that broader scope was not measured with a corpus. ### Additional context Prepared with AI assistance and independently reproduced through the production CLI. MCP was not exercised. No implementation or restoration was attempted. The upstream freshness check found no changes since the tested baseline in the cited decoder and contract files through `origin/main` at `fa36657251a6e51c1a591146c5a7cdf5bc890d80`; this was a source check, not a runtime replay on that revision. Searches covered open and closed issues and PRs using the command, boolean symptom, NIBArchive module, and exact affected field names. Related #5540 concerns object-limit diagnostics, a separate defect; #480 is the original feature request. NOT_ENOUGH_INFO: the last known good version and regression introduction have not been established.
Author
Owner

@matbrgz commented on GitHub (Oct 20, 2026):

Cross-referencing with canonical issue #5540 ([Bug] decode-interface-builder misattributes object-limit omissions to the connection budget). Both reports address decoding and budget/attribute accuracy in compiled AppKit/UIKit interface builder nibs. Cataloged under Cluster AX in consolidation tracker #4330.

<!-- gh-comment-id:6293042521 --> @matbrgz commented on GitHub (Oct 20, 2026): Cross-referencing with canonical issue #5540 (`[Bug] decode-interface-builder misattributes object-limit omissions to the connection budget`). Both reports address decoding and budget/attribute accuracy in compiled AppKit/UIKit interface builder nibs. Cataloged under Cluster AX in consolidation tracker #4330.
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#3375
No description provided.