Repository navigation
[Dream Cycle 2026-10-14] developer-experience: verify-entrypoint --cmd requiredness bypassed by a bare trailing flag + cli,tui scan #181
Description
Rotation
DATE=2026-10-14, DEEP=developer-experience, SCAN=cli,tui, SLOT=4, COMMIT=b2abcc14a632d7e0948962065a7c6c8920cf306c. No bonus deep-dive triggers (20261014 % 25 = 14, % 75 = 64).
Ledger Check
Last 14 ledger rows inspected. Three open PRs already exist on this exact surface — read in full to avoid duplication, confirmed disjoint:
- PR developer-experience: freshness stamp's --max-age silently freezes maxAgeDays:1 (issue #179) #180 —
freshness stamp --max-agenumeric coercion (Number(true)===1), different subcommand/parser path. - PR developer-experience: bare value-less CLI flags silently corrupt ledger/config state (issue #160) #161 — 9
(flags.X as string) || fallbackcall sites; explicitly disclosed this exactverify-entrypoint --cmdgap as an unclaimed follow-up and never filed it (confirmed: no PR/issue existed for it before this one). - PR developer-experience: --no-color silently defeated by a stray trailing positional (issue #140) #141 —
--no-color === truestrict-equality leak in TUI rendering, different subsystem.
Issue #149/PR #150 (shallow-clone git show oracle) is a different surface (security-adversarial), already filed/tracked across 3+ prior nights, not touched tonight.
gh gist create is blocked by this session's data-sharing policy (classified "Public Data-Sharing Upload"); recorded as GIST=LOCAL per precedent (2026-08-30, PR #54/#55) — report committed into the PR instead.
Deep Dive
packages/cli/src/index.ts's hand-rolled parseArgs (line 88) turns a flag with nothing after it — end of argv, or immediately followed by another --flag — into the boolean true, not a string. The verify-entrypoint subcommand's requiredness guard (line 465, pre-fix) was if (!label || !cmd) where cmd = flags.cmd as string | undefined — a compile-time-only cast with no runtime check. !true === false, so when --cmd is bare/trailing, the usage-error branch is skipped and the boolean true reaches io.exec(cmd) (line 486).
In the real CLI (packages/cli/src/bin.ts), io.exec wraps child_process.exec, which throws a TypeError on a non-string command. The catch-all handler there has no numeric .code on a TypeError, so it defaults to {code: 1, stdout: '', stderr: ''}. classifyEntrypointResult then reports verdict: 'blocked', reason: 'exited 1 with no stderr' — indistinguishable from a genuinely dead entrypoint. This command gates the nightly pipeline's own evaluator-liveness check (STEP 0.5's control-plane discovery, and verify-entrypoints more broadly), so a typo'd invocation silently misreports "the entrypoint is dead" instead of "you forgot --cmd's value."
Hypothesis
Given verify-entrypoint <label> --cmd invoked with --cmd as a value-less flag, when the requiredness guard is changed from truthiness (!cmd) to a real type check (typeof cmd !== 'string'), then the invocation emits the usage error (exit 1, stderr containing usage:) instead of a misleading blocked liveness verdict — with zero behavior change for live/blocked-on-a-real-command/suspicious-silent/stale-state/no-exec()/multi-word-positional-rejection.
Evaluation Receipt
Real evaluator: npx vitest run + node --test scripts/*.test.mjs.
- Baseline (post
git fetch --unshallow, which itself fixed the known shallow-clonegit showtest failures, [Dream Cycle 2026-10-03] security-adversarial: BASELINE_COMMIT git-show oracle fails opaquely (not self-healing) on a shallow clone + redblue,supply-chain scan #149/security-adversarial: BASELINE_COMMIT git-show oracle fails opaquely on a shallow clone (issue #149) #150 — unrelated, not re-filed): 809 vitest + 195 governance = 1004/1004, 0 failures. - Candidate: 811 vitest (+2 new tests) + 195 governance (unchanged) = 1006/1006, 0 regressions.
- Lint and typecheck clean.
- Live repro against the actual built
packages/cli/dist/bin.js(not just the vitest mock), pre- and post-fix:- Pre-fix:
node packages/cli/dist/bin.js verify-entrypoint redblue --cmd→redblue: blocked (exit 1) — exited 1 with no stderr, exit 1, zero mention--cmdlacked a value. - Post-fix: same command →
usage: dream-machine verify-entrypoint <label> --cmd "<command>", exit 1. - Post-fix,
--cmdfollowed by another flag (--cmd --other) → same usage error. - Post-fix, normal case (
--cmd "npm test") → unchanged:bench: live (exit 0) — produced output. - Post-fix, pre-existing no-
--cmd-at-all case → unchanged usage error.
- Pre-fix:
Darwin Results
Not run. evaluatorEntrypoints.darwin (npx @metaharness/darwin) is unpinned (flagged repeatedly across prior nights as a supply-chain risk — resolves registry latest fresh on every invocation, not governed by this repo's lockfile). This candidate is a tiny (2-line), clear-cut, mechanically verified fix; invoking an unpinned npx entrypoint was judged not worth the supply-chain exposure for it. Flagged for human decision as in prior nights, not newly discovered tonight.
Evidence
- OBSERVATION: live pre-fix repro against built CLI.
- MEASUREMENT: vitest 809→811 (+2), governance 195 unchanged, 0 regressions; lint/typecheck clean.
- INFERENCE:
typeof cmd !== 'string'closes the hole for everyparseArgsboolean-flag shape (bare trailing, immediately-followed-by-another-flag) without affecting any legitimate string value, including--cmd=(empty string, still caught by the trailing!cmd) and--cmd ""(empty next-token, whichparseArgsitself treats as absent and converts to booleantrue, also caught). - DECISION: ACCEPT.
Reward-Hack Check
Independent critic subagent (did not author the fix) reviewed adversarially: verified the live diff directly, checked for bypasses (--cmd=, --cmd ""), confirmed the test diff is purely additive (no weakened assertion, no gold-value change), confirmed classifyEntrypointResult and mockIOWithExec were untouched (no reward-hacking the evaluator), confirmed no behavior change for any pre-existing verify-entrypoint case, and independently ran the full suite (811/811 + 195/195). Verdict: CLEAR.
Security Review
No new attack surface: this narrows an existing input-validation check on a CLI arg handled entirely in-process; no credentials, network, or filesystem scope change. The fix removes a bogus compile-time-only type cast in favor of a real runtime check — strictly tightening, not loosening, validation.
Scan Findings (cli, tui)
- cli: the bug above. Broader pattern: this is the second instance (after PR developer-experience: bare value-less CLI flags silently corrupt ledger/config state (issue #160) #161's 9 sites) of a required string flag checked via truthiness instead of
typeof. Flagged as a next step (see report) rather than fixed broadly tonight, to keep this candidate scoped to one conceptual change. - tui: no new unclaimed defect found tonight distinct from the already-open PR developer-experience: --no-color silently defeated by a stray trailing positional (issue #140) #141 (
--no-colorleak). CheckedrenderDashboard/pad()/verdictColorsiblings; no additional gap identified in the time budget.
Competitors
See report's competitor-rows table (gist, below) — this finding is internal/self-contained to this repo's own hand-rolled CLI parser, not an external-literature claim. Noted: Node's built-in util.parseArgs would make this entire bug class structurally impossible (distinguishes boolean vs. string flags at the parser level) — a repo-level next step, not implemented tonight (out of scope, would touch every subcommand).
Gist
GIST=LOCAL — public gist creation denied by this session's data-sharing policy. Full report committed into the PR as docs/dream-cycle/2026-10-14-developer-experience-report.md.
Witness
- Session commit:
b2abcc14a632d7e0948962065a7c6c8920cf306c - Report sha256:
4c4e85ad532e553be4820ce8494dacd6edf909f04356aaa0bfe32999fbf75c25 - Witness stamp:
4c8277be28712c3afe9f7ba90f4a02bfe8a8bcf7edfcd099cd5dc057728b5dfd - Self-verified with
dream-machine witness verify-report docs/dream-cycle/2026-10-14-developer-experience-report.md --commit b2abcc14a632d7e0948962065a7c6c8920cf306c→✓ witness VALID.
(Correction: an earlier draft of the PR/report computed this triple by hand with sha256sum over the whole report file, which included a stray duplicate ## Witness placeholder heading — not this repo's own splitAtWitnessSection canonical-exclusion convention added in a prior night's fix. The report and the values above were corrected and self-verified before this issue was finalized.)
Recommendation
evaluated: accepted. Candidate is small, mechanically verified, independently critiqued CLEAR, and closes a real false-positive on this pipeline's own evaluator-liveness gate. Human review requested before merge — session never self-merges.
Activity