[PR #2327] [MERGED] fix(artifacts): distinguish JVM classes from universal Mach-O files #5165

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

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/2327
Author: @jeonjw85
Created: 10/12/2026
Status: ✅ Merged
Merged: 10/13/2026
Merged by: @morluto

Base: main ← Head: fix/artifact-fat-classification


📝 Commits (3)

  • 906575e test(artifacts): reproduce JVM class inventory misclassification
  • 8ccb9af fix(artifacts): validate FAT declarations before classifying executables
  • 6abd4a2 fix(artifacts): reconcile FAT classification through the shared parser

📊 Changes

3 files changed (+219 additions, -0 deletions)

View changed files

➕ src/artifacts/inventory/ArtifactGraphConstruction.test.ts (+103 -0)
📝 src/domain/apple/machoContainer.ts (+5 -0)
➕ tests/acceptance/artifactClassification.test.ts (+111 -0)

📄 Description

Summary

Fixes #2317.

Require a complete FAT architecture table and valid slice declarations before
inventory labels CAFEBABE bytes as a universal Mach-O executable. JVM classes
now remain unknown in both occurrences and content nodes.

Root cause and scope

classifyArtifactBytes previously trusted the four-byte signature shared by FAT
containers and JVM classes. The correction lives at that content-classification
boundary and reuses readFatSliceDeclarations / validateFatSlice, the existing
owners of FAT table and range interpretation.

Parsing is bounded by the retained classification prefix before allocating slice
declarations. Truncated tables, invalid ranges/alignment, unsafe FAT64 integers,
and contradictory file sizes remain unknown. Valid FAT32/FAT64 in both byte orders
are recognized without relying on filenames or host-supported CPU types.

This is an existing static-inventory bug fix; a separate maintainer scope decision
is not applicable. The runtime effect is reading existing artifact bytes. The
classification uses existing Evidence fields and introduces no schema, dependency,
installation, or release-metadata change. No migration is required.

Regression evidence

The first commit contains the regression; the following commit fixes it.
On base f611d8ce722cd36345e9ff83b9669ef2e7fe57a9:

  • Both compiled-CLI cases fail for the 57-byte and 4,060-byte classes, including a
    renamed copy, in JAR and ZIP inventories. The larger class fits its apparent
    65-record FAT table, so table length alone cannot satisfy the regression.
  • All four FAT magic/byte-order controls pass before the class assertions fail.
  • The narrow prefix/range suite has 16 expected failures and one passing CPU
    compatibility control before the fix.

Repeated the original fixtures through the fixed CLI, with the host's real
universal /bin/ls in the mixed ZIP:

Hello.class  executable / mach-o-universal -> unknown / unknown
Big.class    executable / mach-o-universal -> unknown / unknown
ls           executable / mach-o-universal -> executable / mach-o-universal

Content identities, SHA-256 values and sizes are preserved. The real native
control retains an empty occurrence-limitations list.

Validation

  • Focused CLI, inventory, MCP and Mach-O suites: 57 passed across 8 files,
    no skips. Includes the new CLI regression and narrow malformed/prefix cases,
    existing MZ, directory, archive, universal-extraction and artifact-MCP coverage.
  • npm run check: passed typecheck, lint, formatting, knip, metadata, module
    boundaries and architecture guards. Lint reported 0 errors / 950 warnings;
    the build also reported two ineffective-dynamic-import warnings.
  • npm run verify:test-discovery: 973 files discovered exactly once.
  • git diff --check: passed.
  • Host: macOS, Node 24.18.0, npm 11.16.0. Linux/Windows and external decompiler
    engines were not exercised; this change is static archive classification.

Representative costs

Same fixtures and CLI commands, using the unchanged base runtime versus the fix.
Values are before → after:

Workflow Cache Wall ms CPU ms Sampled peak family MiB Estimated stdout tokens
JAR inventory Cold 540 → 490 660 → 690 382.92 → 355.20 2329 → 2313
JAR inventory Warm 360 → 370 550 → 540 391.11 → 386.39 2329 → 2313
Mixed ZIP inventory Cold 510 → 490 710 → 670 352.06 → 355.38 2332 → 2316
Mixed ZIP inventory Warm 370 → 380 550 → 570 391.95 → 393.59 2332 → 2316

Cold means one fresh process with an empty Node compile cache; filesystem caches
were not flushed. Warm timings are medians of three fresh processes with populated
compile caches. Memory is the maximum sampled process-family RSS, including the
timing wrapper, and may miss peaks. Tokens are stdout-only tokenx@1.3.0 estimates;
agent input, reasoning and conversation costs are unmeasured. These small local
samples do not establish a performance improvement.


🔄 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/2327 **Author:** [@jeonjw85](https://github.com/jeonjw85) **Created:** 10/12/2026 **Status:** ✅ Merged **Merged:** 10/13/2026 **Merged by:** [@morluto](https://github.com/morluto) **Base:** `main` ← **Head:** `fix/artifact-fat-classification` --- ### 📝 Commits (3) - [`906575e`](https://github.com/morluto/rea/commit/906575eb46aefb0e9711e3fed71ee91808c5cd54) test(artifacts): reproduce JVM class inventory misclassification - [`8ccb9af`](https://github.com/morluto/rea/commit/8ccb9af18ede41737e9414c60ab402a24918f54e) fix(artifacts): validate FAT declarations before classifying executables - [`6abd4a2`](https://github.com/morluto/rea/commit/6abd4a20b6ea05e8a5a65588c3ba33dfc055ec33) fix(artifacts): reconcile FAT classification through the shared parser ### 📊 Changes **3 files changed** (+219 additions, -0 deletions) <details> <summary>View changed files</summary> ➕ `src/artifacts/inventory/ArtifactGraphConstruction.test.ts` (+103 -0) 📝 `src/domain/apple/machoContainer.ts` (+5 -0) ➕ `tests/acceptance/artifactClassification.test.ts` (+111 -0) </details> ### 📄 Description ## Summary Fixes #2317. Require a complete FAT architecture table and valid slice declarations before inventory labels `CAFEBABE` bytes as a universal Mach-O executable. JVM classes now remain `unknown` in both occurrences and content nodes. ## Root cause and scope `classifyArtifactBytes` previously trusted the four-byte signature shared by FAT containers and JVM classes. The correction lives at that content-classification boundary and reuses `readFatSliceDeclarations` / `validateFatSlice`, the existing owners of FAT table and range interpretation. Parsing is bounded by the retained classification prefix before allocating slice declarations. Truncated tables, invalid ranges/alignment, unsafe FAT64 integers, and contradictory file sizes remain unknown. Valid FAT32/FAT64 in both byte orders are recognized without relying on filenames or host-supported CPU types. This is an existing static-inventory bug fix; a separate maintainer scope decision is not applicable. The runtime effect is reading existing artifact bytes. The classification uses existing Evidence fields and introduces no schema, dependency, installation, or release-metadata change. No migration is required. ## Regression evidence The first commit contains the regression; the following commit fixes it. On base `f611d8ce722cd36345e9ff83b9669ef2e7fe57a9`: - Both compiled-CLI cases fail for the 57-byte and 4,060-byte classes, including a renamed copy, in JAR and ZIP inventories. The larger class fits its apparent 65-record FAT table, so table length alone cannot satisfy the regression. - All four FAT magic/byte-order controls pass before the class assertions fail. - The narrow prefix/range suite has 16 expected failures and one passing CPU compatibility control before the fix. Repeated the original fixtures through the fixed CLI, with the host's real universal `/bin/ls` in the mixed ZIP: ```text Hello.class executable / mach-o-universal -> unknown / unknown Big.class executable / mach-o-universal -> unknown / unknown ls executable / mach-o-universal -> executable / mach-o-universal ``` Content identities, SHA-256 values and sizes are preserved. The real native control retains an empty occurrence-limitations list. ## Validation - Focused CLI, inventory, MCP and Mach-O suites: **57 passed across 8 files**, no skips. Includes the new CLI regression and narrow malformed/prefix cases, existing MZ, directory, archive, universal-extraction and artifact-MCP coverage. - `npm run check`: passed typecheck, lint, formatting, knip, metadata, module boundaries and architecture guards. Lint reported 0 errors / 950 warnings; the build also reported two ineffective-dynamic-import warnings. - `npm run verify:test-discovery`: **973 files** discovered exactly once. - `git diff --check`: passed. - Host: macOS, Node 24.18.0, npm 11.16.0. Linux/Windows and external decompiler engines were not exercised; this change is static archive classification. ## Representative costs Same fixtures and CLI commands, using the unchanged base runtime versus the fix. Values are **before → after**: | Workflow | Cache | Wall ms | CPU ms | Sampled peak family MiB | Estimated stdout tokens | | --- | --- | ---: | ---: | ---: | ---: | | JAR inventory | Cold | 540 → 490 | 660 → 690 | 382.92 → 355.20 | 2329 → 2313 | | JAR inventory | Warm | 360 → 370 | 550 → 540 | 391.11 → 386.39 | 2329 → 2313 | | Mixed ZIP inventory | Cold | 510 → 490 | 710 → 670 | 352.06 → 355.38 | 2332 → 2316 | | Mixed ZIP inventory | Warm | 370 → 380 | 550 → 570 | 391.95 → 393.59 | 2332 → 2316 | Cold means one fresh process with an empty Node compile cache; filesystem caches were not flushed. Warm timings are medians of three fresh processes with populated compile caches. Memory is the maximum sampled process-family RSS, including the timing wrapper, and may miss peaks. Tokens are stdout-only `tokenx@1.3.0` estimates; agent input, reasoning and conversation costs are unmeasured. These small local samples do not establish a performance improvement. --- <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:28 +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#5165
No description provided.