[GH-ISSUE #7558] [Bug] JSONL output refusal discards the receipt of an already-published Evidence bundle #4500

Closed
opened 2026-10-31 00:50:18 +00:00 by bsakaguchi · 0 comments
Owner

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

Before submitting

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

Area

CLI

Observed behavior

A supported match-native-functions request.json --evidence_output out.json --format jsonl invocation returns invalid_request and exits 1 because its summary is not a JSON Lines record collection. Before reporting that refusal, it creates the requested Evidence bundle. The error omits the committed destination and byte count entirely. An identical retry exits 1 because the destination already exists.

With the same request and a fresh destination, --format json exits 0 and returns the bundle's {path, bytes} receipt. The JSONL-created bundle is byte-identical to that successful control and imports successfully. The shape refusal itself is expected; the defect is losing the receipt after publication.

Reproduction

  1. Use Node.js 24.22.1 and a built checkout at the revision below. From the checkout root, run this fixture and the public CLI commands. The fixture represents two authenticated synthetic function inventories; no provider or target executable is needed.
REA="$PWD"
WORK="$(mktemp -d "${TMPDIR:-.}/rea-receipt.XXXXXX")"
mkdir -p "$WORK"/{home,config,data,cache,state}
export HOME="$WORK/home" XDG_CONFIG_HOME="$WORK/config"
export XDG_DATA_HOME="$WORK/data" XDG_CACHE_HOME="$WORK/cache"
export XDG_STATE_HOME="$WORK/state"
cd "$WORK"
cat > request.json <<'JSON'
{"left":{"evidence_id":"ev_5ac6aca3659e761a36875ec934af81686617a0ccd7008d5e996dffb43449a229","subject":{"name":"matching-1.elf","digest":{"sha256":"1111111111111111111111111111111111111111111111111111111111111111"},"local_path":"fixtures/matching-1.elf","format":"elf","architecture":"x86_64"},"provider":{"id":"matching-fixture","name":"Synthetic facts","version":"1"},"analysis_profile":null,"predicate_type":"rea.analysis","operation":"list_procedures","parameters":{},"raw_result":null,"normalized_result":[{"address":"0x10","value":"main","symbol":{"primary":true,"dynamic":false,"external":false,"type":"function","source":"imported"}},{"address":"0x20","value":"old_name","symbol":{"primary":true,"dynamic":false,"external":false,"type":"function","source":"imported"}}],"confidence":"observed","authority":"shipped-artifact","environment":null,"limitations":[],"relationship_coverage":null,"locations":[],"evidence_links":[]},"right":{"evidence_id":"ev_647c374d38c5301eceb85914c38a3a95409669f90b6a320caa925380139d6d4e","subject":{"name":"matching-2.elf","digest":{"sha256":"2222222222222222222222222222222222222222222222222222222222222222"},"local_path":"fixtures/matching-2.elf","format":"elf","architecture":"x86_64"},"provider":{"id":"matching-fixture","name":"Synthetic facts","version":"1"},"analysis_profile":null,"predicate_type":"rea.analysis","operation":"list_procedures","parameters":{},"raw_result":null,"normalized_result":[{"address":"0x30","value":"main","symbol":{"primary":true,"dynamic":false,"external":false,"type":"function","source":"imported"}},{"address":"0x40","value":"new_name","symbol":{"primary":true,"dynamic":false,"external":false,"type":"function","source":"imported"}}],"confidence":"observed","authority":"shipped-artifact","environment":null,"limitations":[],"relationship_coverage":null,"locations":[],"evidence_links":[]},"detail":"summary"}
JSON
node "$REA/scripts/rea.mjs" match-native-functions request.json --evidence_output out.json --format jsonl
printf 'first exit=%s\n' "$?"
node -e 'const fs=require("node:fs"); const s=fs.statSync("out.json"); console.log({bytes:s.size,mode:(s.mode&511).toString(8)})'
node "$REA/scripts/rea.mjs" match-native-functions request.json --evidence_output out.json --format jsonl
printf 'retry exit=%s\n' "$?"
node "$REA/scripts/rea.mjs" match-native-functions request.json --evidence_output control.json --format json > control-result.json
printf 'JSON control exit=%s\n' "$?"
node -e 'const fs=require("node:fs"); console.log(JSON.parse(fs.readFileSync("control-result.json","utf8")).evidence_bundle); console.log({identical:fs.readFileSync("out.json").equals(fs.readFileSync("control.json"))})'
node "$REA/scripts/rea.mjs" evidence-import out.json --format json
printf 'readback exit=%s\n' "$?"

  1. Observe first exit=1, a JSONL invalid_request error without a publication receipt, and out.json present with 8,219 bytes and mode 600. Observe retry exit=1 with the existing-file refusal. The JSON control exits 0, prints a receipt with bytes: 8219, and prints { identical: true }. Readback exits 0 with three imported records.

The independent verification ran one initial summary refusal, its identical retry, one JSON control and one complete-detail refusal. To exercise the latter, change detail to complete and use a fresh evidence destination; it also exits 1 while creating the same bundle. The inline shell procedure was also replayed successfully after report assembly. No timing hook or injected failure is involved.

Expected behavior

When the output formatter refuses a selection after Evidence publication has committed, preserve the committed destination and byte count in the typed error. Refusing the selection before committing the file would also avoid an undisclosed publication. Keep the existing JSONL admission rules and caller-error classification.

The documented lifecycle invariant requires preserving any committed output's publication receipt. The CLI documentation also describes atomic Evidence publication and retention of receipts through cancellation and cleanup failures. Its statement that JSONL refuses unsupported shapes before writing a record concerns JSONL records; it does not by itself promise that an explicitly requested Evidence file remains absent.

Impact and scope

P2: callers relying on the failure response lose the fact that a durable output was committed. Retrying the same destination is then blocked by the never-overwrite rule. This is a bounded recovery defect: the destination was supplied by the caller, the file remains usable, and no corruption or loss was observed.

A safe recovery was demonstrated with evidence-import out.json --format json, which authenticated all three records. A successful alternative was demonstrated with --format json and a fresh destination. Summary and complete matching delivery were exercised on macOS; other command families, platforms and live providers were not exercised. JSONL is a CLI output mode; this report makes no MCP reproduction claim.

REA version

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

Runtime and platform

Node.js v24.22.1; macOS 27.0.1, arm64. No external analysis provider was started.

Target and artifact context

Two synthetic list_procedures Evidence inventories with ELF/x86_64 metadata. Their subject paths are identity metadata and are not opened by this matching workflow. The saved bundle contains the two inventories and the derived function-matching record.

Interface

CLI

Earliest failure stage

Transport or result projection

Relevant output or evidence

Selected fields from independently captured CLI output and filesystem readback:

summary JSONL: exit 1; result.code=invalid_request; result.category=invalid_input
message: The command result is not a JSON Lines record collection: the result is an object. ...
publication receipt in failure: absent
out.json: 8219 bytes, mode 0600
identical retry: exit 1; details.reason=exists
message: Evidence file already exists. Choose another output path.
summary JSON control: exit 0; evidence_bundle.bytes=8219; evidence_bundle.path identifies control.json
out.json and control.json: byte-identical
complete JSONL: exit 1; complete.json is byte-identical to out.json

Successful public CLI readback of the JSONL-created file:

{"imported":3,"unknowns_added":0,"total":3}

The original JSONL refusal includes only output-selection diagnostics; neither its destination nor an Evidence publication receipt occurs anywhere in the response. The three bundle operations are list_procedures, list_procedures, match_native_functions.

Expected-source locators at the stated baseline: docs/tool-design.md:195-196 requires preserving a committed output's publication receipt; docs/cli.md:73-83 establishes intentional JSONL refusals, and docs/cli.md:1061-1067 documents atomic Evidence delivery and cancellation/cleanup receipt fields.

Failure-source locators: src/cli/nativeFunctionMatchingCommands.ts:55-105 reaches the publication helper through the public CLI; src/cli/analysisEvidenceDelivery.ts:203-232 commits the bundle and returns its summary receipt; src/cli/jsonLinesOutput.ts:54-75 replaces that successful value with an output-selection error. The no-unreported-bundle rationale is explicit at src/cli/analysisEvidenceDelivery.ts:184-185.

Typed outcome or recovery expected

Retain invalid_request / invalid_input and the format-selection remediation. If the bundle has committed, also retain its actual {path, bytes} receipt, for example under details.diagnostics.evidence_bundle, so callers can distinguish completed publication from a pre-publication refusal.

Analysis or suspected cause

Source-derived explanation: publication finishes inside the command before the JSONL writer checks the returned object's shape. Summary delivery has already constructed evidence_bundle, but the formatter projects its new input error without carrying that receipt forward. This ordering explains the observed file and error; no runtime instrumentation of the internal call sequence was performed.

Additional context

Duplicate search covered open and closed issues, all PR states and issue/PR comments. Closed #7110 and merged PR #7124 intentionally preserve JSONL boundary rules while correcting refusal classification; they do not address a committed Evidence file's receipt.

Closed #6095 and merged PR #6221 concern receipt preservation after cancellation or staging cleanup failure. This deterministic formatter refusal runs without cancellation or cleanup failure and discards the receipt at a later owner. Open #7427 concerns a different MCP snapshot/provider-close failure. No exact duplicate was found, and no regression range is claimed.

Originally created by @coygeek on GitHub (Oct 27, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7558 ### 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 CLI ### Observed behavior A supported `match-native-functions request.json --evidence_output out.json --format jsonl` invocation returns `invalid_request` and exits 1 because its summary is not a JSON Lines record collection. Before reporting that refusal, it creates the requested Evidence bundle. The error omits the committed destination and byte count entirely. An identical retry exits 1 because the destination already exists. With the same request and a fresh destination, `--format json` exits 0 and returns the bundle's `{path, bytes}` receipt. The JSONL-created bundle is byte-identical to that successful control and imports successfully. The shape refusal itself is expected; the defect is losing the receipt after publication. ### Reproduction 1. Use Node.js 24.22.1 and a built checkout at the revision below. From the checkout root, run this fixture and the public CLI commands. The fixture represents two authenticated synthetic function inventories; no provider or target executable is needed. ```sh REA="$PWD" WORK="$(mktemp -d "${TMPDIR:-.}/rea-receipt.XXXXXX")" mkdir -p "$WORK"/{home,config,data,cache,state} export HOME="$WORK/home" XDG_CONFIG_HOME="$WORK/config" export XDG_DATA_HOME="$WORK/data" XDG_CACHE_HOME="$WORK/cache" export XDG_STATE_HOME="$WORK/state" cd "$WORK" cat > request.json <<'JSON' {"left":{"evidence_id":"ev_5ac6aca3659e761a36875ec934af81686617a0ccd7008d5e996dffb43449a229","subject":{"name":"matching-1.elf","digest":{"sha256":"1111111111111111111111111111111111111111111111111111111111111111"},"local_path":"fixtures/matching-1.elf","format":"elf","architecture":"x86_64"},"provider":{"id":"matching-fixture","name":"Synthetic facts","version":"1"},"analysis_profile":null,"predicate_type":"rea.analysis","operation":"list_procedures","parameters":{},"raw_result":null,"normalized_result":[{"address":"0x10","value":"main","symbol":{"primary":true,"dynamic":false,"external":false,"type":"function","source":"imported"}},{"address":"0x20","value":"old_name","symbol":{"primary":true,"dynamic":false,"external":false,"type":"function","source":"imported"}}],"confidence":"observed","authority":"shipped-artifact","environment":null,"limitations":[],"relationship_coverage":null,"locations":[],"evidence_links":[]},"right":{"evidence_id":"ev_647c374d38c5301eceb85914c38a3a95409669f90b6a320caa925380139d6d4e","subject":{"name":"matching-2.elf","digest":{"sha256":"2222222222222222222222222222222222222222222222222222222222222222"},"local_path":"fixtures/matching-2.elf","format":"elf","architecture":"x86_64"},"provider":{"id":"matching-fixture","name":"Synthetic facts","version":"1"},"analysis_profile":null,"predicate_type":"rea.analysis","operation":"list_procedures","parameters":{},"raw_result":null,"normalized_result":[{"address":"0x30","value":"main","symbol":{"primary":true,"dynamic":false,"external":false,"type":"function","source":"imported"}},{"address":"0x40","value":"new_name","symbol":{"primary":true,"dynamic":false,"external":false,"type":"function","source":"imported"}}],"confidence":"observed","authority":"shipped-artifact","environment":null,"limitations":[],"relationship_coverage":null,"locations":[],"evidence_links":[]},"detail":"summary"} JSON node "$REA/scripts/rea.mjs" match-native-functions request.json --evidence_output out.json --format jsonl printf 'first exit=%s\n' "$?" node -e 'const fs=require("node:fs"); const s=fs.statSync("out.json"); console.log({bytes:s.size,mode:(s.mode&511).toString(8)})' node "$REA/scripts/rea.mjs" match-native-functions request.json --evidence_output out.json --format jsonl printf 'retry exit=%s\n' "$?" node "$REA/scripts/rea.mjs" match-native-functions request.json --evidence_output control.json --format json > control-result.json printf 'JSON control exit=%s\n' "$?" node -e 'const fs=require("node:fs"); console.log(JSON.parse(fs.readFileSync("control-result.json","utf8")).evidence_bundle); console.log({identical:fs.readFileSync("out.json").equals(fs.readFileSync("control.json"))})' node "$REA/scripts/rea.mjs" evidence-import out.json --format json printf 'readback exit=%s\n' "$?" ``` 2. Observe `first exit=1`, a JSONL `invalid_request` error without a publication receipt, and `out.json` present with 8,219 bytes and mode `600`. Observe `retry exit=1` with the existing-file refusal. The JSON control exits 0, prints a receipt with `bytes: 8219`, and prints `{ identical: true }`. Readback exits 0 with three imported records. The independent verification ran one initial summary refusal, its identical retry, one JSON control and one complete-detail refusal. To exercise the latter, change `detail` to `complete` and use a fresh evidence destination; it also exits 1 while creating the same bundle. The inline shell procedure was also replayed successfully after report assembly. No timing hook or injected failure is involved. ### Expected behavior When the output formatter refuses a selection after Evidence publication has committed, preserve the committed destination and byte count in the typed error. Refusing the selection before committing the file would also avoid an undisclosed publication. Keep the existing JSONL admission rules and caller-error classification. The documented lifecycle invariant requires preserving any committed output's publication receipt. The CLI documentation also describes atomic Evidence publication and retention of receipts through cancellation and cleanup failures. Its statement that JSONL refuses unsupported shapes before writing a record concerns JSONL records; it does not by itself promise that an explicitly requested Evidence file remains absent. ### Impact and scope P2: callers relying on the failure response lose the fact that a durable output was committed. Retrying the same destination is then blocked by the never-overwrite rule. This is a bounded recovery defect: the destination was supplied by the caller, the file remains usable, and no corruption or loss was observed. A safe recovery was demonstrated with `evidence-import out.json --format json`, which authenticated all three records. A successful alternative was demonstrated with `--format json` and a fresh destination. Summary and complete matching delivery were exercised on macOS; other command families, platforms and live providers were not exercised. JSONL is a CLI output mode; this report makes no MCP reproduction claim. ### REA version Exact `node scripts/rea.mjs --version` output: `6.8.0`. Source baseline: `65f1c447344a423fa2785847dbcea1e9a9e2454a`. ### Runtime and platform Node.js `v24.22.1`; macOS `27.0.1`, arm64. No external analysis provider was started. ### Target and artifact context Two synthetic `list_procedures` Evidence inventories with ELF/x86_64 metadata. Their subject paths are identity metadata and are not opened by this matching workflow. The saved bundle contains the two inventories and the derived function-matching record. ### Interface CLI ### Earliest failure stage Transport or result projection ### Relevant output or evidence Selected fields from independently captured CLI output and filesystem readback: ```text summary JSONL: exit 1; result.code=invalid_request; result.category=invalid_input message: The command result is not a JSON Lines record collection: the result is an object. ... publication receipt in failure: absent out.json: 8219 bytes, mode 0600 identical retry: exit 1; details.reason=exists message: Evidence file already exists. Choose another output path. summary JSON control: exit 0; evidence_bundle.bytes=8219; evidence_bundle.path identifies control.json out.json and control.json: byte-identical complete JSONL: exit 1; complete.json is byte-identical to out.json ``` Successful public CLI readback of the JSONL-created file: ```json {"imported":3,"unknowns_added":0,"total":3} ``` The original JSONL refusal includes only output-selection diagnostics; neither its destination nor an Evidence publication receipt occurs anywhere in the response. The three bundle operations are `list_procedures`, `list_procedures`, `match_native_functions`. Expected-source locators at the stated baseline: `docs/tool-design.md:195-196` requires preserving a committed output's publication receipt; `docs/cli.md:73-83` establishes intentional JSONL refusals, and `docs/cli.md:1061-1067` documents atomic Evidence delivery and cancellation/cleanup receipt fields. Failure-source locators: `src/cli/nativeFunctionMatchingCommands.ts:55-105` reaches the publication helper through the public CLI; `src/cli/analysisEvidenceDelivery.ts:203-232` commits the bundle and returns its summary receipt; `src/cli/jsonLinesOutput.ts:54-75` replaces that successful value with an output-selection error. The no-unreported-bundle rationale is explicit at `src/cli/analysisEvidenceDelivery.ts:184-185`. ### Typed outcome or recovery expected Retain `invalid_request` / `invalid_input` and the format-selection remediation. If the bundle has committed, also retain its actual `{path, bytes}` receipt, for example under `details.diagnostics.evidence_bundle`, so callers can distinguish completed publication from a pre-publication refusal. ### Analysis or suspected cause Source-derived explanation: publication finishes inside the command before the JSONL writer checks the returned object's shape. Summary delivery has already constructed `evidence_bundle`, but the formatter projects its new input error without carrying that receipt forward. This ordering explains the observed file and error; no runtime instrumentation of the internal call sequence was performed. ### Additional context Duplicate search covered open and closed issues, all PR states and issue/PR comments. [Closed #7110](https://github.com/morluto/rea/issues/7110) and [merged PR #7124](https://github.com/morluto/rea/pull/7124) intentionally preserve JSONL boundary rules while correcting refusal classification; they do not address a committed Evidence file's receipt. [Closed #6095](https://github.com/morluto/rea/issues/6095) and [merged PR #6221](https://github.com/morluto/rea/pull/6221) concern receipt preservation after cancellation or staging cleanup failure. This deterministic formatter refusal runs without cancellation or cleanup failure and discards the receipt at a later owner. [Open #7427](https://github.com/morluto/rea/issues/7427) concerns a different MCP snapshot/provider-close failure. No exact duplicate was found, and no regression range is claimed.
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#4500
No description provided.