[GH-ISSUE #6542] [Bug] CLI output filters discard earlier fields selected through the same array slice #3932

Closed
opened 2026-10-31 00:45:20 +00:00 by bsakaguchi · 0 comments
Owner

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

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

The production CLI output boundary silently drops the first requested field in --filter-output 'capabilities[0,1].provider.id,capabilities[0,1].provider.name'. The output contains only provider.name. Reversing the paths returns only provider.id. This was executed against source from the latest published release and current main with a controlled successful result; no public executable or external provider was run.

Reproduction

With locked dependencies already installed in either checkout, save the following as filter-sibling-slices.mjs, then run node --import tsx filter-sibling-slices.mjs CHECKOUT, replacing CHECKOUT with that checkout. I ran this program once per revision. It calls the actual production createCliResultOutput boundary and supplies a small in-memory provider-shaped success result.

import { Writable } from 'node:stream';
import { pathToFileURL } from 'node:url';
import { resolve } from 'node:path';
const checkout = resolve(process.argv[2]);
const { createCliResultOutput } = await import(pathToFileURL(resolve(checkout, 'src/cli/cliResultOutput.ts')));
const fixture = { capabilities: [{ provider: { id: 'fixture', name: 'Fixture provider' } }] };
for (const filter of [
  'capabilities[0,1].provider.id,capabilities[0,1].provider.name',
  'capabilities[0,1].provider.name,capabilities[0,1].provider.id',
  'capabilities[0,1].provider',
]) {
  let stdout = '';
  const sink = new Writable({ write(chunk, encoding, callback) { stdout += chunk.toString(); callback(); } });
  const output = createCliResultOutput(['providers', '--json', '--filter-output', filter], sink);
  const handled = await output.write(fixture, { command: 'providers', duration: '0ms', format: 'json' });
  console.log(JSON.stringify({filter, handled, output: JSON.parse(stdout)}));
}

A public command that reaches the same boundary is rea providers --json --filter-output 'capabilities[0,1].provider.id,capabilities[0,1].provider.name'; that public-command reproduction is source-derived and was not executed.

Expected behavior

Comma-separated selected paths should retain both requested fields in the sliced row, producing {"capabilities":[{"provider":{"id":"fixture","name":"Fixture provider"}}]} independently of path order. The existing multiple-path and array-slice CLI test establishes support for combining comma-separated fields with slices. The CLI guide advertises these output controls for JSON consumers.

Impact and scope

P2: valid compact-output requests lose selected facts without an error. The observed failure is deterministic for both field orders in the controlled fixture on both revisions. The source result is not modified; the loss occurs in its emitted projection. A verified workaround is selecting their common parent, capabilities[0,1].provider, which retains both fields in the same fixture; removing the filter also avoids the affected selection path. Downstream consumer impact and other output formats were not tested.

REA version

Latest published rea-agents-6.7.0, source 27dc42d10249f0410904a75c0997842eb03b931c; current main source 1635eadfcc49bbb80178838ab74667c2981de383. Both pin Incur 0.6.1.

Runtime and platform

Node.js v26.12.1; Linux x86_64; source loaded with the repository's locked tsx dependency. No Hopper, Ghidra, browser, or target process was involved.

Target and artifact context

In-memory successful JSON result containing one capability provider with the two ordinary string fields id and name.

Interface

CLI

Earliest failure stage

Transport or result projection

Relevant output or evidence

Both revision runs emitted the same three records:

{"filter":"capabilities[0,1].provider.id,capabilities[0,1].provider.name","handled":true,"output":{"capabilities":[{"provider":{"name":"Fixture provider"}}]}}
{"filter":"capabilities[0,1].provider.name,capabilities[0,1].provider.id","handled":true,"output":{"capabilities":[{"provider":{"id":"fixture"}}]}}
{"filter":"capabilities[0,1].provider","handled":true,"output":{"capabilities":[{"provider":{"id":"fixture","name":"Fixture provider"}}]}}

Source reachability: providers and capabilities command registration returns session status. Its capability projection supplies provider identities. The production output boundary calls Filter.apply directly in the release and main, so this valid filter and successful provider-shaped result reach the observed failing transformation without a target-specific guard.

Analysis or suspected cause

Source-derived: locked Incur 0.6.1's Filter.merge assigns a newly mapped slice to target[segment.key] for each selected path. A later path through the same array replaces the slice created by the earlier path rather than merging the selected fields. REA forwards that filtered object to its JSON writer without detecting the omitted selection. This is a projection defect, not the missing-array-entry serialization failure reported in #4938 or failure-diagnostic filtering in #5448.

Additional context

Deduplication inspected the open-issue snapshot and searched all open/closed issues for "filter-output" "array", "filter-output" "slice", "filter-output" "multiple", and "filter" "overwrites". No report of sibling slice selections overwriting earlier selections was found. NOT_ENOUGH_INFO: no last-known-good release was established, and no end-to-end provider execution was performed.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: The executed production output-boundary probe loses an explicitly selected field for ordinary valid successful JSON on both inspected revisions, without reporting a failure.
  • Workaround status: available
  • Workaround basis: Selecting the common parent capabilities[0,1].provider retained both fields in the executed probe on each revision; it returns a broader result while preserving the required facts.
Originally created by @coygeek on GitHub (Oct 23, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/6542 ### 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 The production CLI output boundary silently drops the first requested field in `--filter-output 'capabilities[0,1].provider.id,capabilities[0,1].provider.name'`. The output contains only `provider.name`. Reversing the paths returns only `provider.id`. This was executed against source from the latest published release and current main with a controlled successful result; no public executable or external provider was run. ### Reproduction With locked dependencies already installed in either checkout, save the following as `filter-sibling-slices.mjs`, then run `node --import tsx filter-sibling-slices.mjs CHECKOUT`, replacing `CHECKOUT` with that checkout. I ran this program once per revision. It calls the actual production `createCliResultOutput` boundary and supplies a small in-memory provider-shaped success result. ```js import { Writable } from 'node:stream'; import { pathToFileURL } from 'node:url'; import { resolve } from 'node:path'; const checkout = resolve(process.argv[2]); const { createCliResultOutput } = await import(pathToFileURL(resolve(checkout, 'src/cli/cliResultOutput.ts'))); const fixture = { capabilities: [{ provider: { id: 'fixture', name: 'Fixture provider' } }] }; for (const filter of [ 'capabilities[0,1].provider.id,capabilities[0,1].provider.name', 'capabilities[0,1].provider.name,capabilities[0,1].provider.id', 'capabilities[0,1].provider', ]) { let stdout = ''; const sink = new Writable({ write(chunk, encoding, callback) { stdout += chunk.toString(); callback(); } }); const output = createCliResultOutput(['providers', '--json', '--filter-output', filter], sink); const handled = await output.write(fixture, { command: 'providers', duration: '0ms', format: 'json' }); console.log(JSON.stringify({filter, handled, output: JSON.parse(stdout)})); } ``` A public command that reaches the same boundary is `rea providers --json --filter-output 'capabilities[0,1].provider.id,capabilities[0,1].provider.name'`; that public-command reproduction is source-derived and was not executed. ### Expected behavior Comma-separated selected paths should retain both requested fields in the sliced row, producing `{"capabilities":[{"provider":{"id":"fixture","name":"Fixture provider"}}]}` independently of path order. The existing [multiple-path and array-slice CLI test](https://github.com/morluto/rea/blob/27dc42d10249f0410904a75c0997842eb03b931c/tests/boundary/cli/cliOutput.test.ts#L199) establishes support for combining comma-separated fields with slices. The [CLI guide](https://github.com/morluto/rea/blob/27dc42d10249f0410904a75c0997842eb03b931c/docs/cli.md#L323) advertises these output controls for JSON consumers. ### Impact and scope P2: valid compact-output requests lose selected facts without an error. The observed failure is deterministic for both field orders in the controlled fixture on both revisions. The source result is not modified; the loss occurs in its emitted projection. A verified workaround is selecting their common parent, `capabilities[0,1].provider`, which retains both fields in the same fixture; removing the filter also avoids the affected selection path. Downstream consumer impact and other output formats were not tested. ### REA version Latest published `rea-agents-6.7.0`, source `27dc42d10249f0410904a75c0997842eb03b931c`; current main source `1635eadfcc49bbb80178838ab74667c2981de383`. Both pin Incur 0.6.1. ### Runtime and platform Node.js v26.12.1; Linux x86_64; source loaded with the repository's locked tsx dependency. No Hopper, Ghidra, browser, or target process was involved. ### Target and artifact context In-memory successful JSON result containing one capability provider with the two ordinary string fields `id` and `name`. ### Interface CLI ### Earliest failure stage Transport or result projection ### Relevant output or evidence Both revision runs emitted the same three records: ```jsonl {"filter":"capabilities[0,1].provider.id,capabilities[0,1].provider.name","handled":true,"output":{"capabilities":[{"provider":{"name":"Fixture provider"}}]}} {"filter":"capabilities[0,1].provider.name,capabilities[0,1].provider.id","handled":true,"output":{"capabilities":[{"provider":{"id":"fixture"}}]}} {"filter":"capabilities[0,1].provider","handled":true,"output":{"capabilities":[{"provider":{"id":"fixture","name":"Fixture provider"}}]}} ``` Source reachability: [`providers` and `capabilities` command registration](https://github.com/morluto/rea/blob/27dc42d10249f0410904a75c0997842eb03b931c/src/cli/utilityCommands.ts#L154) returns session status. Its capability projection supplies provider identities. The production output boundary calls `Filter.apply` directly in [the release](https://github.com/morluto/rea/blob/27dc42d10249f0410904a75c0997842eb03b931c/src/cli/cliResultOutput.ts#L229) and [main](https://github.com/morluto/rea/blob/1635eadfcc49bbb80178838ab74667c2981de383/src/cli/cliResultOutput.ts#L229), so this valid filter and successful provider-shaped result reach the observed failing transformation without a target-specific guard. ### Analysis or suspected cause Source-derived: locked Incur 0.6.1's `Filter.merge` assigns a newly mapped slice to `target[segment.key]` for each selected path. A later path through the same array replaces the slice created by the earlier path rather than merging the selected fields. REA forwards that filtered object to its JSON writer without detecting the omitted selection. This is a projection defect, not the missing-array-entry serialization failure reported in #4938 or failure-diagnostic filtering in #5448. ### Additional context Deduplication inspected the open-issue snapshot and searched all open/closed issues for `"filter-output" "array"`, `"filter-output" "slice"`, `"filter-output" "multiple"`, and `"filter" "overwrites"`. No report of sibling slice selections overwriting earlier selections was found. NOT_ENOUGH_INFO: no last-known-good release was established, and no end-to-end provider execution was performed. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: The executed production output-boundary probe loses an explicitly selected field for ordinary valid successful JSON on both inspected revisions, without reporting a failure. - Workaround status: available - Workaround basis: Selecting the common parent `capabilities[0,1].provider` retained both fields in the executed probe on each revision; it returns a broader result while preserving the required facts.
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#3932
No description provided.