[GH-ISSUE #2606] fix(targets): WASM bytes named .hop receive a database identity #923

Closed
opened 2026-10-15 18:29:36 +00:00 by bsakaguchi · 1 comment
Owner

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

Summary

Automatic target admission treats a readable WebAssembly v1 module named module.hop as an analysis database. The same bytes named module.wasm receive the documented static-inspection constraint. A filename alone therefore changes the recognized module's target identity and removes the expected recovery guidance.

Steps to reproduce

Use the source checkout and installed lockfile dependencies described under Runtime or environment. Create src/application/target-admission.probe.test.ts with this disposable-fixture test, then run the focused command below. The file contains only the complete eight-byte empty WebAssembly v1 module header.

import { mkdtemp, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { expect, it } from "vitest";
import { parseBinaryTarget } from "./BinaryTargetResolver.js";

it("recognizes WASM bytes before automatic database inference", async () => {
  const directory = await mkdtemp(join(tmpdir(), "rea-wasm-admission-"));
  try {
    const bytes = Buffer.from([0, 0x61, 0x73, 0x6d, 1, 0, 0, 0]);
    const hop = join(directory, "module.hop");
    const named = join(directory, "module.wasm");
    await writeFile(hop, bytes);
    await writeFile(named, bytes);
    const control = await parseBinaryTarget(named);
    expect(control.ok).toBe(false);
    if (!control.ok) {
      expect(Reflect.get(control.error, "constraint"))
        .toBe("wasm_requires_static_inspection");
    }
    const result = await parseBinaryTarget(hop);
    console.log(result.ok
      ? { ok: true, kind: result.value.kind, format: result.value.format }
      : { ok: false, constraint: Reflect.get(result.error, "constraint") });
    expect(result.ok).toBe(false);
    if (!result.ok) {
      expect(Reflect.get(result.error, "constraint"))
        .toBe("wasm_requires_static_inspection");
    }
  } finally {
    await rm(directory, { recursive: true, force: true });
  }
});
npm run test:focused -- src/application/target-admission.probe.test.ts

The independent local replay exercised this input and three separate controls. Remove the probe after the check. The public MCP equivalent is open_binary with only the fixture's absolute path; its path through the tested resolver was checked from source, rather than through a running MCP server.

Expected behavior

When the caller supplies this readable file without choosing an explicit interpretation, its recognized WebAssembly v1 header should produce wasm_requires_static_inspection. The public opening route should present target_unavailable with category unsupported_target and point to inspect_wasm_artifact with the selected path. Header recognition does not promise validation of a complete module or availability of WABT.

Actual behavior

The local replay returned success with target kind database and format analysis-database for module.hop. The expected refusal assertion failed. Identical bytes named module.wasm returned the required constraint. Explicit database selection for the .hop module and a non-WASM .hop file both retained their existing database classification.

The abbreviated result below shows only the classification fields. The full target also contains path, canonical source path and SHA-256 identity. No native provider was started, so downstream provider behavior and actual CLI/MCP responses are not claimed as executed observations.

{"ok":true,"kind":"database","format":"analysis-database"}

Evidence

  • Expected source: docs/wasm-artifacts.md:7-14 defines the recognized-header refusal and static recovery; src/contracts/sessionLifecycleInputs.ts:33-76 accepts path-only opening and specifies header-based detection when format is omitted.
  • Failure source: src/application/BinaryTargetResolver.ts:163-174 returns an inferred database before the recognized-header check at 283-291; the independent focused replay observed the contrary classification with the exact bytes above.
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete

The independent check ran four cases: the automatic .hop refusal assertion failed and all three controls passed. The test command exited 1. Runtime reachability was inspected through src/server/registerSessionTools.ts:189-218, src/application/binary/BinarySession.ts:205-219, and src/application/binary/BinarySessionOpen.ts:67-87. Path-only opening supplies no target-kind override, and resolution calls the parser before selecting a provider. The readable regular-file fixture passed filesystem checks and supplied no explicit format, architecture or entry point.

Related issue #1852 is closed after broader native-admission recovery work. Merged PR #1872 requires recognition independently of filename and preserves explicit interpretation choices. The tested checkout contains that change but still infers a database before checking this header. These are related references; neither identifies this remaining .hop reproduction as resolved.

Restoration check

Repeat the eight-byte fixture under both filenames. Automatic admission should return the same wasm_requires_static_inspection constraint for each, and the public opening diagnostic should retain the selected path in its static-inspection guidance. Explicit database selection and non-WASM .hop suffix inference must retain their current classifications. Preserve explicit raw-binary and DOS COM interpretations as required by the existing opening contract; those two overrides were not exercised in this replay.

Runtime or environment

Failure verified at a2d8b94dd50dab8d966239dd63ab84718aa8b4b4 and still present at 8b181716aca2cb467be499cba226abfb5ae19141, package rea-agents 6.4.0, Node v26.10.0, npm 11.19.1, Vitest 5.0.3, macOS arm64, and installed lockfile dependencies. Verification used source tests with no provider process or WABT execution.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: Automatic opening gives these recognized modules the wrong target kind and loses the documented refusal and recovery route. The observed failure is bounded to filename inference; no downstream provider incident or data loss was observed.
  • Workaround status: available
  • Workaround basis: Renaming the fixture to .wasm preserves its bytes and demonstrably restores the expected static-inspection constraint. Successful WABT inspection is outside this replay's evidence.
Originally created by @coygeek on GitHub (Oct 13, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2606 ## Summary Automatic target admission treats a readable WebAssembly v1 module named `module.hop` as an analysis database. The same bytes named `module.wasm` receive the documented static-inspection constraint. A filename alone therefore changes the recognized module's target identity and removes the expected recovery guidance. ## Steps to reproduce Use the source checkout and installed lockfile dependencies described under Runtime or environment. Create `src/application/target-admission.probe.test.ts` with this disposable-fixture test, then run the focused command below. The file contains only the complete eight-byte empty WebAssembly v1 module header. ```ts import { mkdtemp, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { expect, it } from "vitest"; import { parseBinaryTarget } from "./BinaryTargetResolver.js"; it("recognizes WASM bytes before automatic database inference", async () => { const directory = await mkdtemp(join(tmpdir(), "rea-wasm-admission-")); try { const bytes = Buffer.from([0, 0x61, 0x73, 0x6d, 1, 0, 0, 0]); const hop = join(directory, "module.hop"); const named = join(directory, "module.wasm"); await writeFile(hop, bytes); await writeFile(named, bytes); const control = await parseBinaryTarget(named); expect(control.ok).toBe(false); if (!control.ok) { expect(Reflect.get(control.error, "constraint")) .toBe("wasm_requires_static_inspection"); } const result = await parseBinaryTarget(hop); console.log(result.ok ? { ok: true, kind: result.value.kind, format: result.value.format } : { ok: false, constraint: Reflect.get(result.error, "constraint") }); expect(result.ok).toBe(false); if (!result.ok) { expect(Reflect.get(result.error, "constraint")) .toBe("wasm_requires_static_inspection"); } } finally { await rm(directory, { recursive: true, force: true }); } }); ``` ```bash npm run test:focused -- src/application/target-admission.probe.test.ts ``` The independent local replay exercised this input and three separate controls. Remove the probe after the check. The public MCP equivalent is `open_binary` with only the fixture's absolute path; its path through the tested resolver was checked from source, rather than through a running MCP server. ## Expected behavior When the caller supplies this readable file without choosing an explicit interpretation, its recognized WebAssembly v1 header should produce `wasm_requires_static_inspection`. The public opening route should present `target_unavailable` with category `unsupported_target` and point to `inspect_wasm_artifact` with the selected path. Header recognition does not promise validation of a complete module or availability of WABT. ## Actual behavior The local replay returned success with target kind `database` and format `analysis-database` for `module.hop`. The expected refusal assertion failed. Identical bytes named `module.wasm` returned the required constraint. Explicit database selection for the `.hop` module and a non-WASM `.hop` file both retained their existing database classification. The abbreviated result below shows only the classification fields. The full target also contains path, canonical source path and SHA-256 identity. No native provider was started, so downstream provider behavior and actual CLI/MCP responses are not claimed as executed observations. ```json {"ok":true,"kind":"database","format":"analysis-database"} ``` ## Evidence - Expected source: `docs/wasm-artifacts.md:7-14` defines the recognized-header refusal and static recovery; `src/contracts/sessionLifecycleInputs.ts:33-76` accepts path-only opening and specifies header-based detection when format is omitted. - Failure source: `src/application/BinaryTargetResolver.ts:163-174` returns an inferred database before the recognized-header check at `283-291`; the independent focused replay observed the contrary classification with the exact bytes above. - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete The independent check ran four cases: the automatic `.hop` refusal assertion failed and all three controls passed. The test command exited 1. Runtime reachability was inspected through `src/server/registerSessionTools.ts:189-218`, `src/application/binary/BinarySession.ts:205-219`, and `src/application/binary/BinarySessionOpen.ts:67-87`. Path-only opening supplies no target-kind override, and resolution calls the parser before selecting a provider. The readable regular-file fixture passed filesystem checks and supplied no explicit format, architecture or entry point. Related [issue #1852](https://github.com/morluto/rea/issues/1852) is closed after broader native-admission recovery work. Merged [PR #1872](https://github.com/morluto/rea/pull/1872) requires recognition independently of filename and preserves explicit interpretation choices. The tested checkout contains that change but still infers a database before checking this header. These are related references; neither identifies this remaining `.hop` reproduction as resolved. ## Restoration check Repeat the eight-byte fixture under both filenames. Automatic admission should return the same `wasm_requires_static_inspection` constraint for each, and the public opening diagnostic should retain the selected path in its static-inspection guidance. Explicit database selection and non-WASM `.hop` suffix inference must retain their current classifications. Preserve explicit raw-binary and DOS COM interpretations as required by the existing opening contract; those two overrides were not exercised in this replay. ## Runtime or environment Failure verified at `a2d8b94dd50dab8d966239dd63ab84718aa8b4b4` and still present at `8b181716aca2cb467be499cba226abfb5ae19141`, package `rea-agents` 6.4.0, Node v26.10.0, npm 11.19.1, Vitest 5.0.3, macOS arm64, and installed lockfile dependencies. Verification used source tests with no provider process or WABT execution. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: Automatic opening gives these recognized modules the wrong target kind and loses the documented refusal and recovery route. The observed failure is bounded to filename inference; no downstream provider incident or data loss was observed. - Workaround status: available - Workaround basis: Renaming the fixture to `.wasm` preserves its bytes and demonstrably restores the expected static-inspection constraint. Successful WABT inspection is outside this replay's evidence.
bsakaguchi 2026-10-15 18:29:36 +00:00
Author
Owner

@morluto commented on GitHub (Oct 14, 2026):

Verified the reported defect is addressed on main by 168bfe5060.

Root cause and resolution: Format probing rejects WASM magic before suffix-only .hop inference can assign analysis-database identity.

Validation: tests/boundary/filesystem/targetDiagnostics.test.ts and tests/boundary/mcp/wasmArtifactMcp.test.ts — Diagnostics identify WASM v1 bytes named .hop; MCP refuses native WASM opening with .hop and directs to static tooling; ordinary .hop database routing remains a control.

Evidence: CI run 500e: owner unchanged and assertions passed.

Verification scope: Static routing/diagnostics only; no Hopper database engine claim.

Current main CI has separate failures under repair; this closure does not claim the complete main workflow is green.

<!-- gh-comment-id:6162510459 --> @morluto commented on GitHub (Oct 14, 2026): Verified the reported defect is addressed on main by 168bfe50604b3a435c05f2db9f8a0cf47230c660. Root cause and resolution: Format probing rejects WASM magic before suffix-only .hop inference can assign analysis-database identity. Validation: `tests/boundary/filesystem/targetDiagnostics.test.ts and tests/boundary/mcp/wasmArtifactMcp.test.ts` — Diagnostics identify WASM v1 bytes named `.hop`; MCP refuses native WASM opening with `.hop` and directs to static tooling; ordinary `.hop` database routing remains a control. Evidence: CI run 500e: owner unchanged and assertions passed. Verification scope: Static routing/diagnostics only; no Hopper database engine claim. Current main CI has separate failures under repair; this closure does not claim the complete main workflow is green.
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#923
No description provided.