[GH-ISSUE #7425] [Bug] Empty outline-depth silently removes every source-summary outline entry #4431

Closed
opened 2026-10-31 00:49:44 +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/7425

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

import-reference-source ROOT --detail summary --outline-depth= --json exits 0 and returns depth 0 with no outline entries. Omitting the flag on the same synthetic tree returns the default depth 2 with three entries. An empty script variable therefore silently selects the documented omit-all presentation instead of producing an input error.

Reproduction

Use Node.js 24.22.1 at the source revision below. A fresh checkout needs npm ci && npm run build:cached. Verification reused installed locked dependencies, confirmed the lockfile was unchanged, and ran npm run build:cached. From the repository root, run without exit-on-error because the malformed control should fail:

WORK=$(mktemp -d)
mkdir -p "$WORK"/{home,config,data,cache,state,temp,source/alpha/beta/gamma}
printf 'export const deep = 1;\n' > "$WORK/source/alpha/beta/gamma/deep.ts"
printf 'export const top = 2;\n' > "$WORK/source/alpha/top.ts"
NODE_BIN=$(node -p 'process.execPath')
rea_cli() {
  env -i PATH="$(dirname "$NODE_BIN"):/usr/bin:/bin" \
    HOME="$WORK/home" XDG_CONFIG_HOME="$WORK/config" \
    XDG_DATA_HOME="$WORK/data" XDG_CACHE_HOME="$WORK/cache" \
    XDG_STATE_HOME="$WORK/state" TMPDIR="$WORK/temp" \
    REA_LOG_LEVEL=silent NO_COLOR=1 "$NODE_BIN" scripts/rea.mjs \
    import-reference-source "$WORK/source" --detail summary "$@" --json
}
for name in omitted empty zero malformed; do
  case "$name" in
    omitted) args=();;
    empty) args=(--outline-depth=);;
    zero) args=(--outline-depth=0);;
    malformed) args=(--outline-depth=2_0);;
  esac
  rea_cli "${args[@]}" > "$WORK/$name.json"
  echo "$name exit=$?"
  "$NODE_BIN" -e 'const fs=require("node:fs"); const r=JSON.parse(fs.readFileSync(process.argv[1],"utf8")); console.log(JSON.stringify(r.outline ? {depth:r.outline.depth,entries:r.outline.entries.length,omitted_entry_count:r.outline.omitted_entry_count} : r));' "$WORK/$name.json"
done

Each shown case ran once, within a larger run that also exercised whitespace, negative zero, hexadecimal, plus-sign, decimal-point and exponent spellings. The block retains the failure and three discriminating controls.

Expected behavior

Refuse an explicitly empty outline-depth value with a nonzero exit and a validation error naming outlineDepth. Preserve omission as default depth 2 and explicit numeric zero as the documented omit-all choice. docs/cli.md:618-621 requires a nonnegative safe integer and defines those depth behaviors. src/cli/options.ts:16-21 and tests/boundary/cli/cliIntegerArguments.test.ts:6-18 establish the existing decimal-token parsing convention for other integer CLI fields; those tests do not cover this option.

Impact and scope

P2: callers passing an empty variable receive a successful summary with all five inventoried entries omitted from its outline. This affects presentation; no imported-file loss or changed inventory was observed. Omitting the flag is a demonstrated safe workaround when the default depth is wanted. Observation covers one synthetic tree on macOS; no security boundary crossing was observed.

REA version

Exact node scripts/rea.mjs --version output: 6.8.0. Source commit: f2277454b8c5356abbe311ad6dbb1dd3a3e334a5.

Runtime and platform

Node.js v24.22.1; macOS 27.0.1; Darwin arm64.

Target and artifact context

Synthetic local TypeScript source tree with two files and three directories below the selected root. Historical-source import only; no native provider, device, target execution or external service.

Interface

CLI

Earliest failure stage

Request parsing or validation

Relevant output or evidence

Observed public CLI output, reduced to the relevant fields:

omitted exit=0
{"depth":2,"entries":3,"omitted_entry_count":2}
empty exit=0
{"depth":0,"entries":0,"omitted_entry_count":5}
zero exit=0
{"depth":0,"entries":0,"omitted_entry_count":5}
malformed exit=1
code: VALIDATION_ERROR
fieldErrors[0].path: outlineDepth
fieldErrors[0].received: NaN

All invocation stderr was empty. Whitespace-only and -0 values also produced depth 0; 0x2, +2, 2.0 and 2e0 produced depth 2, each with exit 0. These are supporting observations of the same coercion path, not evidence that all invalid numbers bypass validation.

Typed outcome or recovery expected

A field-specific validation failure before import for empty text. Proposed restoration checks should retain the observed omitted-flag and explicit-zero controls; no repaired build was tested.

Analysis or suspected cause

Source-derived: src/cli/utilityCommands.ts:291-301 declares an optional numeric schema. The locked Incur parser calls Number(value) for numeric fields (node_modules/incur/src/Parser.ts:322-330), converting empty text to zero before integer validation. At src/cli/utilityCommands.ts:338, the defined zero bypasses the default depth. Existing source-summary boundary tests cover negative, fractional and unsafe numeric depths, but not empty tokens.

Additional context

Open #7376 concerns empty/non-decimal byte-entropy window options; open #7093 concerns listener flags. They share a coercion class but different options and acceptance criteria. Closed #3211 and closed PR #3233 concern the advertised negative minimum for outlineDepth, a separate behavior. The first affected version is unknown.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: Empty option text silently returns successful omit-all outline presentation; no data loss or severe downstream incident was observed.
  • Workaround status: available
  • Workaround basis: Omitting the option returned default depth 2 with three outline entries on the same fixture.
Originally created by @coygeek on GitHub (Oct 27, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7425 ## 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 `import-reference-source ROOT --detail summary --outline-depth= --json` exits 0 and returns depth 0 with no outline entries. Omitting the flag on the same synthetic tree returns the default depth 2 with three entries. An empty script variable therefore silently selects the documented omit-all presentation instead of producing an input error. ## Reproduction Use Node.js 24.22.1 at the source revision below. A fresh checkout needs `npm ci && npm run build:cached`. Verification reused installed locked dependencies, confirmed the lockfile was unchanged, and ran `npm run build:cached`. From the repository root, run without exit-on-error because the malformed control should fail: ```bash WORK=$(mktemp -d) mkdir -p "$WORK"/{home,config,data,cache,state,temp,source/alpha/beta/gamma} printf 'export const deep = 1;\n' > "$WORK/source/alpha/beta/gamma/deep.ts" printf 'export const top = 2;\n' > "$WORK/source/alpha/top.ts" NODE_BIN=$(node -p 'process.execPath') rea_cli() { env -i PATH="$(dirname "$NODE_BIN"):/usr/bin:/bin" \ HOME="$WORK/home" XDG_CONFIG_HOME="$WORK/config" \ XDG_DATA_HOME="$WORK/data" XDG_CACHE_HOME="$WORK/cache" \ XDG_STATE_HOME="$WORK/state" TMPDIR="$WORK/temp" \ REA_LOG_LEVEL=silent NO_COLOR=1 "$NODE_BIN" scripts/rea.mjs \ import-reference-source "$WORK/source" --detail summary "$@" --json } for name in omitted empty zero malformed; do case "$name" in omitted) args=();; empty) args=(--outline-depth=);; zero) args=(--outline-depth=0);; malformed) args=(--outline-depth=2_0);; esac rea_cli "${args[@]}" > "$WORK/$name.json" echo "$name exit=$?" "$NODE_BIN" -e 'const fs=require("node:fs"); const r=JSON.parse(fs.readFileSync(process.argv[1],"utf8")); console.log(JSON.stringify(r.outline ? {depth:r.outline.depth,entries:r.outline.entries.length,omitted_entry_count:r.outline.omitted_entry_count} : r));' "$WORK/$name.json" done ``` Each shown case ran once, within a larger run that also exercised whitespace, negative zero, hexadecimal, plus-sign, decimal-point and exponent spellings. The block retains the failure and three discriminating controls. ## Expected behavior Refuse an explicitly empty outline-depth value with a nonzero exit and a validation error naming `outlineDepth`. Preserve omission as default depth 2 and explicit numeric zero as the documented omit-all choice. `docs/cli.md:618-621` requires a nonnegative safe integer and defines those depth behaviors. `src/cli/options.ts:16-21` and `tests/boundary/cli/cliIntegerArguments.test.ts:6-18` establish the existing decimal-token parsing convention for other integer CLI fields; those tests do not cover this option. ## Impact and scope P2: callers passing an empty variable receive a successful summary with all five inventoried entries omitted from its outline. This affects presentation; no imported-file loss or changed inventory was observed. Omitting the flag is a demonstrated safe workaround when the default depth is wanted. Observation covers one synthetic tree on macOS; no security boundary crossing was observed. ## REA version Exact `node scripts/rea.mjs --version` output: `6.8.0`. Source commit: `f2277454b8c5356abbe311ad6dbb1dd3a3e334a5`. ## Runtime and platform Node.js v24.22.1; macOS 27.0.1; Darwin arm64. ## Target and artifact context Synthetic local TypeScript source tree with two files and three directories below the selected root. Historical-source import only; no native provider, device, target execution or external service. ## Interface CLI ## Earliest failure stage Request parsing or validation ## Relevant output or evidence Observed public CLI output, reduced to the relevant fields: ```text omitted exit=0 {"depth":2,"entries":3,"omitted_entry_count":2} empty exit=0 {"depth":0,"entries":0,"omitted_entry_count":5} zero exit=0 {"depth":0,"entries":0,"omitted_entry_count":5} malformed exit=1 code: VALIDATION_ERROR fieldErrors[0].path: outlineDepth fieldErrors[0].received: NaN ``` All invocation stderr was empty. Whitespace-only and `-0` values also produced depth 0; `0x2`, `+2`, `2.0` and `2e0` produced depth 2, each with exit 0. These are supporting observations of the same coercion path, not evidence that all invalid numbers bypass validation. ## Typed outcome or recovery expected A field-specific validation failure before import for empty text. Proposed restoration checks should retain the observed omitted-flag and explicit-zero controls; no repaired build was tested. ## Analysis or suspected cause Source-derived: `src/cli/utilityCommands.ts:291-301` declares an optional numeric schema. The locked Incur parser calls `Number(value)` for numeric fields (`node_modules/incur/src/Parser.ts:322-330`), converting empty text to zero before integer validation. At `src/cli/utilityCommands.ts:338`, the defined zero bypasses the default depth. Existing source-summary boundary tests cover negative, fractional and unsafe numeric depths, but not empty tokens. ## Additional context Open [#7376](https://github.com/morluto/rea/issues/7376) concerns empty/non-decimal byte-entropy window options; open [#7093](https://github.com/morluto/rea/issues/7093) concerns listener flags. They share a coercion class but different options and acceptance criteria. Closed [#3211](https://github.com/morluto/rea/issues/3211) and closed [PR #3233](https://github.com/morluto/rea/pull/3233) concern the advertised negative minimum for outlineDepth, a separate behavior. The first affected version is unknown. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: Empty option text silently returns successful omit-all outline presentation; no data loss or severe downstream incident was observed. - Workaround status: available - Workaround basis: Omitting the option returned default depth 2 with three outline entries on the same fixture.
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#4431
No description provided.