[GH-ISSUE #1234] fix(artifacts): byte-identical files erase JavaScript path classifications #433

Closed
opened 2026-10-15 18:25:01 +00:00 by bsakaguchi · 2 comments
Owner

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

Summary

Artifact inspection assigns one file's path-specific classification to every byte-identical file sharing its content-addressed node. An Apple application ZIP containing a JavaScript file and an identical text resource consequently loses its JavaScript component and runtime-family hint, despite reporting complete inventory coverage. Changing the text resource's name changes which classification wins; a fixture containing native code also loses or gains incorrect JavaScript/native bridge candidates. The failure concerns path-specific observations, not the legitimate sharing of byte identity.

Runtime or environment

Reproduced on npm rea-agents@6.1.0 and a locally built main checkout at f0da05f67fff1411cf2f7a48a752ee7b348c71ff, with Node v26.10.0, macOS 27.0.1 (26A434), arm64. The ZIP reproduction requires Python and REA; it needs no Hopper, Ghidra, IDA or native compiler.

Steps to reproduce

In a disposable working directory, create three ZIPs whose text resources differ only in presence or ordering:

python3 - <<'PY'
import zipfile
for name, paths in [('later-text', ['a.js', 'z.txt']), ('earlier-text', ['0.txt', 'a.js']), ('solo-script', ['a.js'])]:
    with zipfile.ZipFile(name + '.zip', 'w') as archive:
        archive.writestr('Demo.app/Contents/Info.plist', '<?xml version="1.0"?><plist version="1.0"><dict><key>CFBundleName</key><string>Demo</string></dict></plist>')
        for path in paths:
            archive.writestr('Demo.app/Contents/Resources/' + path, 'console.log("hello");\n')
PY
for name in later-text earlier-text solo-script; do
  npx -y rea-agents@6.1.0 inspect-artifact "$name.zip" --json > "$name-inspection.json"
  input="$(python3 -c 'import json,sys; x=json.load(open(sys.argv[1])); print(json.dumps({"inventory_evidence":[x["normalized_result"]["substeps"][0]["evidence"]]}))' "$name-inspection.json")"
  npx -y rea-agents@6.1.0 project-apple-application-graph "$input" --json > "$name-projection.json"
done
python3 - <<'PY'
import json
for name in ['later-text', 'earlier-text', 'solo-script']:
    x = json.load(open(name + '-projection.json'))['normalized_result']
    print(name, {'javascript': [v['path'] for v in x['components']['javascript']], 'runtime_families': x['runtime_families'], 'coverage': x['coverage']})
PY

Both tested builds were exercised with these exact ZIP contents through their CLI entry points. The solo-script ZIP is the control; the other two preserve that script and add a byte-identical resource. No target code is executed.

Expected behavior

The Apple projection promises exact paths, detected formats, runtime-family hints, and every component in each inventory category. a.js should remain a JavaScript component regardless of the other resource's name or archive position. A .txt path should not acquire JavaScript classification solely because its bytes equal an inventoried .js file. Shared content identity must preserve the different per-path facts, or explicitly report unavailable classification rather than silently asserting a complete absence.

Actual behavior

Every inventory and projection command exits 0 on both tested builds. The projections contain:

later-text:
  components.javascript = []
  runtime_families = []
earlier-text:
  components.javascript = ["Demo.app/Contents/Resources/0.txt", "Demo.app/Contents/Resources/a.js"]
  runtime_families = ["javascript"]
solo-script:
  components.javascript = ["Demo.app/Contents/Resources/a.js"]
  runtime_families = ["javascript"]
all three:
  coverage = {"status":"complete-within-inventory","inventory_complete":true}

Both resources have SHA-256 f9444510dc7403e41049deb133f6892aa6a63c05591b2b59e4ee5b234d7bbd99. Their shared node is kind: resource, format: file in later-text and kind: javascript, format: javascript-bundle in earlier-text. The solo-script control keeps the latter classification. A separately executed valid .app fixture containing these resources and a harmless compiled Mach-O also returned zero JavaScript/native bridge candidates for later text, two candidates including the .txt path for earlier text, and the correct single candidate for the solo-script control.

Evidence

  • Expected source: docs/apple-application-analysis.md:3 promises exact paths, detected formats and runtime-family hints; line 23 promises every category component. src/artifacts/inventory/ArtifactGraphConstruction.ts:291 classifies .js paths as JavaScript, and src/domain/apple/appleApplication.ts:261 selects JavaScript components by their observed format.
  • Failure source: The executed inventory and Apple projection results for the three inline ZIP fixtures, with the meaningful result fields quoted under Actual behavior.
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete

The primary violation is the executed CLI projection output on both tested builds, including the solo-script control and alternate resource ordering. Source inspection was used separately to trace its representation.

Source inspection shows src/artifacts/inventory/scanReader.ts:148 replacing an existing content-addressed node for each duplicate digest. That node's kind, format and executable flag come from the current entry at lines 224–231. The Apple projection then copies the single shared node's format to every occurrence at src/domain/apple/appleApplication.ts:120. These are diagnostic breadcrumbs, not a prescribed implementation.

Open and closed upstream issues were searched for related artifact, byte-identical-content and deduplication reports; no matching report was found in those searches.

Restoration check

Run all three ZIP cases. Both duplicate-resource cases must retain Demo.app/Contents/Resources/a.js as a JavaScript component without classifying the .txt path as JavaScript solely because it shares the script's bytes. The JavaScript runtime-family hint must remain present. The solo-script result must stay correct. A shared digest node may remain shared; per-path role observations must remain accurate or explicitly unknown. In the native-containing variant, JavaScript/native bridge candidates must reflect the actual JavaScript path rather than disappearing or including the duplicate text resource.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: Byte-identical paths with different classifications produce incorrect static application components, runtime-family hints and bridge candidates while claiming complete inventory coverage. The demonstrated scope is bounded to colliding content identities; target bytes are not modified and no downstream runtime failure was observed.
  • Workaround status: unverified
  • Workaround basis: Removing the duplicate resource from an authored copy restored the script classification, but that loses part of the caller-selected artifact. A safe practical workaround preserving the complete original artifact and its path-specific observations was not established.
Originally created by @coygeek on GitHub (Oct 9, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/1234 ## Summary Artifact inspection assigns one file's path-specific classification to every byte-identical file sharing its content-addressed node. An Apple application ZIP containing a JavaScript file and an identical text resource consequently loses its JavaScript component and runtime-family hint, despite reporting complete inventory coverage. Changing the text resource's name changes which classification wins; a fixture containing native code also loses or gains incorrect JavaScript/native bridge candidates. The failure concerns path-specific observations, not the legitimate sharing of byte identity. ## Runtime or environment Reproduced on npm `rea-agents@6.1.0` and a locally built `main` checkout at `f0da05f67fff1411cf2f7a48a752ee7b348c71ff`, with Node v26.10.0, macOS 27.0.1 (26A434), arm64. The ZIP reproduction requires Python and REA; it needs no Hopper, Ghidra, IDA or native compiler. ## Steps to reproduce In a disposable working directory, create three ZIPs whose text resources differ only in presence or ordering: ```sh python3 - <<'PY' import zipfile for name, paths in [('later-text', ['a.js', 'z.txt']), ('earlier-text', ['0.txt', 'a.js']), ('solo-script', ['a.js'])]: with zipfile.ZipFile(name + '.zip', 'w') as archive: archive.writestr('Demo.app/Contents/Info.plist', '<?xml version="1.0"?><plist version="1.0"><dict><key>CFBundleName</key><string>Demo</string></dict></plist>') for path in paths: archive.writestr('Demo.app/Contents/Resources/' + path, 'console.log("hello");\n') PY for name in later-text earlier-text solo-script; do npx -y rea-agents@6.1.0 inspect-artifact "$name.zip" --json > "$name-inspection.json" input="$(python3 -c 'import json,sys; x=json.load(open(sys.argv[1])); print(json.dumps({"inventory_evidence":[x["normalized_result"]["substeps"][0]["evidence"]]}))' "$name-inspection.json")" npx -y rea-agents@6.1.0 project-apple-application-graph "$input" --json > "$name-projection.json" done python3 - <<'PY' import json for name in ['later-text', 'earlier-text', 'solo-script']: x = json.load(open(name + '-projection.json'))['normalized_result'] print(name, {'javascript': [v['path'] for v in x['components']['javascript']], 'runtime_families': x['runtime_families'], 'coverage': x['coverage']}) PY ``` Both tested builds were exercised with these exact ZIP contents through their CLI entry points. The `solo-script` ZIP is the control; the other two preserve that script and add a byte-identical resource. No target code is executed. ## Expected behavior The Apple projection promises exact paths, detected formats, runtime-family hints, and every component in each inventory category. `a.js` should remain a JavaScript component regardless of the other resource's name or archive position. A `.txt` path should not acquire JavaScript classification solely because its bytes equal an inventoried `.js` file. Shared content identity must preserve the different per-path facts, or explicitly report unavailable classification rather than silently asserting a complete absence. ## Actual behavior Every inventory and projection command exits 0 on both tested builds. The projections contain: ```text later-text: components.javascript = [] runtime_families = [] earlier-text: components.javascript = ["Demo.app/Contents/Resources/0.txt", "Demo.app/Contents/Resources/a.js"] runtime_families = ["javascript"] solo-script: components.javascript = ["Demo.app/Contents/Resources/a.js"] runtime_families = ["javascript"] all three: coverage = {"status":"complete-within-inventory","inventory_complete":true} ``` Both resources have SHA-256 `f9444510dc7403e41049deb133f6892aa6a63c05591b2b59e4ee5b234d7bbd99`. Their shared node is `kind: resource, format: file` in `later-text` and `kind: javascript, format: javascript-bundle` in `earlier-text`. The solo-script control keeps the latter classification. A separately executed valid `.app` fixture containing these resources and a harmless compiled Mach-O also returned zero JavaScript/native bridge candidates for later text, two candidates including the `.txt` path for earlier text, and the correct single candidate for the solo-script control. ## Evidence - Expected source: `docs/apple-application-analysis.md:3` promises exact paths, detected formats and runtime-family hints; line 23 promises every category component. `src/artifacts/inventory/ArtifactGraphConstruction.ts:291` classifies `.js` paths as JavaScript, and `src/domain/apple/appleApplication.ts:261` selects JavaScript components by their observed format. - Failure source: The executed inventory and Apple projection results for the three inline ZIP fixtures, with the meaningful result fields quoted under Actual behavior. - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete The primary violation is the executed CLI projection output on both tested builds, including the solo-script control and alternate resource ordering. Source inspection was used separately to trace its representation. Source inspection shows `src/artifacts/inventory/scanReader.ts:148` replacing an existing content-addressed node for each duplicate digest. That node's kind, format and executable flag come from the current entry at lines 224–231. The Apple projection then copies the single shared node's format to every occurrence at `src/domain/apple/appleApplication.ts:120`. These are diagnostic breadcrumbs, not a prescribed implementation. Open and closed upstream issues were searched for related artifact, byte-identical-content and deduplication reports; no matching report was found in those searches. ## Restoration check Run all three ZIP cases. Both duplicate-resource cases must retain `Demo.app/Contents/Resources/a.js` as a JavaScript component without classifying the `.txt` path as JavaScript solely because it shares the script's bytes. The JavaScript runtime-family hint must remain present. The solo-script result must stay correct. A shared digest node may remain shared; per-path role observations must remain accurate or explicitly unknown. In the native-containing variant, JavaScript/native bridge candidates must reflect the actual JavaScript path rather than disappearing or including the duplicate text resource. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: Byte-identical paths with different classifications produce incorrect static application components, runtime-family hints and bridge candidates while claiming complete inventory coverage. The demonstrated scope is bounded to colliding content identities; target bytes are not modified and no downstream runtime failure was observed. - Workaround status: unverified - Workaround basis: Removing the duplicate resource from an authored copy restored the script classification, but that loses part of the caller-selected artifact. A safe practical workaround preserving the complete original artifact and its path-specific observations was not established.
bsakaguchi 2026-10-15 18:25:01 +00:00
Author
Owner

@N0zoM1z0 commented on GitHub (Oct 9, 2026):

Resolved by 63bf9140: byte-addressed nodes retain content format/identity, while each occurrence retains its own artifact_kind, artifact_format and permissions.

Independently replayed all three reported ZIP cases (a.js + z.txt, 0.txt + a.js, and a.js alone) through the compiled CLI and actual stdio MCP inventory/Apple projection. Each reports only a.js as JavaScript and preserves the JavaScript runtime family. Identical bytes keep one content ID while .txt remains a resource. The existing order/role/permission regression covers the underlying distinction. Closing this now that the existing fix is verified.

<!-- gh-comment-id:6083089609 --> @N0zoM1z0 commented on GitHub (Oct 9, 2026): Resolved by [63bf9140](https://github.com/morluto/rea/commit/63bf91405cf97b114a84f337fb1272d98a267999): byte-addressed nodes retain content format/identity, while each occurrence retains its own `artifact_kind`, `artifact_format` and permissions. Independently replayed all three reported ZIP cases (`a.js` + `z.txt`, `0.txt` + `a.js`, and `a.js` alone) through the compiled CLI and actual stdio MCP inventory/Apple projection. Each reports only `a.js` as JavaScript and preserves the JavaScript runtime family. Identical bytes keep one content ID while `.txt` remains a resource. [The existing order/role/permission regression](https://github.com/morluto/rea/blob/63bf91405cf97b114a84f337fb1272d98a267999/src/artifacts/inventory/ArtifactOccurrenceIdentity.test.ts) covers the underlying distinction. Closing this now that the existing fix is verified.
Author
Owner

@kaoru0822-kitauji commented on GitHub (Oct 9, 2026):

#1298 adds regression tests for the three ZIP shapes through inventoryArtifact → projectAppleApplication. They fail at f0da05f6 with the reported [] and two-component results, and pass on main. The native .app variant also checks out on main (one bridge candidate, Contents/Resources/a.js → Contents/MacOS/demo).

<!-- gh-comment-id:6083150650 --> @kaoru0822-kitauji commented on GitHub (Oct 9, 2026): #1298 adds regression tests for the three ZIP shapes through `inventoryArtifact` → `projectAppleApplication`. They fail at f0da05f6 with the reported `[]` and two-component results, and pass on `main`. The native `.app` variant also checks out on `main` (one bridge candidate, `Contents/Resources/a.js` → `Contents/MacOS/demo`).
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#433
No description provided.