Seam flag inputs not validated: bad --attempt / --reqs / scalar config degrade with a misleading error #45

Closed
opened 2026-07-23 14:50:24 +00:00 by crenshawdev · 0 comments
crenshawdev commented 2026-07-23 14:50:24 +00:00 (Migrated from github.com)

Severity: low · Area: planning-seam / config · surfaced in the post-v1.2.0 cross-model review sweep (bundled: three instances of one root — unvalidated flag/input types produce a misleading error rather than a clean usage error). Related to #42 (the medium cursor set --total case in the same family).

Each degrades within contract (nothing is misdirected), but each misreports a usage error as something else, which wastes debugging time.

1. phase-done --reqs as a bare flag throws "internal"

cadence-core/bin/planning.mjs:224-225: const ids = opts.reqs ? opts.reqs.split(',')... : .... Passing --reqs immediately before another flag parses it as boolean true; true.split throws and is caught as {ok:false, reason:"internal"} — a usage error mislabelled internal.

2. resolve --attempt abc reports "unresolved" instead of a bad argument

cadence-core/bin/route.mjs:157: o.attempt = parseInt(a[++i], 10) yields NaN for abc. In auto mode the NaN flows through the escalation math and indexes the profile order with NaN, so the resolver answers {ok:false, reason:"unresolved"} (caller safely falls back to the base model) rather than flagging the bad --attempt.

3. config validate passes a non-object config

cadence-core/bin/config.mjs:100-108: flatten(cfg, '', {}) over a scalar yields zero leaves, so a file whose entire content is 42 validates clean ({ok:true, checked:0}). mergeLayers then returns 42 as the whole config while reporting source:"repo" (see also #39). The "no invalid value is written" gate has a hole for non-object JSON.

Fix direction

Validate flag/input types before use: reject a non-numeric --attempt and a valueless --reqs with a usage/bad-args result, and require the validated config to be a top-level object. A small shared seam-flag validator could cover these and #42 together.

**Severity:** low · **Area:** planning-seam / config · surfaced in the post-v1.2.0 cross-model review sweep (bundled: three instances of one root — unvalidated flag/input types produce a misleading error rather than a clean usage error). Related to #42 (the medium `cursor set --total` case in the same family). Each degrades within contract (nothing is misdirected), but each misreports a usage error as something else, which wastes debugging time. ## 1. `phase-done --reqs` as a bare flag throws "internal" `cadence-core/bin/planning.mjs:224-225`: `const ids = opts.reqs ? opts.reqs.split(',')... : ...`. Passing `--reqs` immediately before another flag parses it as boolean `true`; `true.split` throws and is caught as `{ok:false, reason:"internal"}` — a usage error mislabelled internal. ## 2. `resolve --attempt abc` reports "unresolved" instead of a bad argument `cadence-core/bin/route.mjs:157`: `o.attempt = parseInt(a[++i], 10)` yields `NaN` for `abc`. In `auto` mode the NaN flows through the escalation math and indexes the profile order with `NaN`, so the resolver answers `{ok:false, reason:"unresolved"}` (caller safely falls back to the base model) rather than flagging the bad `--attempt`. ## 3. `config validate` passes a non-object config `cadence-core/bin/config.mjs:100-108`: `flatten(cfg, '', {})` over a scalar yields zero leaves, so a file whose entire content is `42` validates clean (`{ok:true, checked:0}`). `mergeLayers` then returns `42` as the whole config while reporting `source:"repo"` (see also #39). The "no invalid value is written" gate has a hole for non-object JSON. ## Fix direction Validate flag/input types before use: reject a non-numeric `--attempt` and a valueless `--reqs` with a `usage`/`bad-args` result, and require the validated config to be a top-level object. A small shared seam-flag validator could cover these and #42 together.
Sign in to join this conversation.
No description provided.