Repository navigation
Conversation
…roze maxAgeDays:1 (issue TBD) packages/cli/src/index.ts's `freshness stamp` command computed Number(flag) directly on --max-age. parseArgs turns a value-less flag into the boolean true, and Number(true) === 1 is a valid positive safe integer, so a bare --max-age silently wrote the strictest possible evidence-freshness policy (maxAgeDays: 1) instead of erroring like the file's already-hardened --open-count/--since-row flags. Adds parseMaxAgeDays() mirroring that existing precedent, plus an upper bound (MAX_EVIDENCE_AGE_DAYS, imported from @dream-machine/witness) found by an independent critic review so out-of-range values fail at a single CLI-level exit code instead of leaking one layer deeper into the witness package's own differently-shaped error. npm test: 809+195 -> 812+195 (+3 new, 0 regressions). typecheck/lint clean. Rotated tonight's DEEP surface from SLOT 3 (security-adversarial) to SLOT 4 (developer-experience) per the ledger's own learning signal: the supplychain.ts unpinned-npx detector has had 5 narrow bypass-widening PRs across prior nights (#68/#99/#138/#149/#157), none merged -- repeated >=3x, so not re-widened a 6th time tonight. Checked issue #160/PR #161 (open, unreviewed) in full first: it hardens 9 different (flags.X as string) || fallback call sites and does not touch --max-age's distinct Number()- coercion shape, so this is not a duplicate. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_016d8nUtzH17Nd2EQqhL2h7f
Ledger append ran before the issue/PR existed (chicken-and-egg: the ledger row includes the PR number, but the PR includes the committed ledger row). Issue #179 and PR #180 now exist; replacing the LOCAL/LOCAL placeholders. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_016d8nUtzH17Nd2EQqhL2h7f
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #179.
Hypothesis
Given
dream-machine freshness stampinvoked with--max-ageas a value-less flag (nothing after it, or another--flagimmediately after, soparseArgsyields the booleantrue) or with an out-of-range numeric string, the current code either (a) silently acceptsmaxAgeDays: 1(thetruecase, sinceNumber(true) === 1is a valid positive safe integer) or (b) accepts any valueNumber()can parse and defers range checking to@dream-machine/witness'snormalizedMaxAgeDays, producing a different exit code (2) and message shape than this file's own sibling flags (1). Replacing the inlineNumber(maxAgeRaw)with aparseMaxAgeDays()helper — same fail-closed shape asparseOpenCandidateCount/parseSinceRow, bounds mirroringMAX_EVIDENCE_AGE_DAYSfrom@dream-machine/witness— closes both at the CLI layer with one consistent usage error and exit code, with zero behavior change for any valid numeric--max-age. Confirmed.Candidate
packages/cli/src/index.ts: addsparseMaxAgeDays(flag: string | boolean | undefined): number | undefined, mirroring the existingparseOpenCandidateCount/parseSinceRowpattern exactly (same file, few dozen lines above), with its upper bound sourced from@dream-machine/witness's already-exportedMAX_EVIDENCE_AGE_DAYSconstant rather than a duplicated literal. Thefreshness stamphandler'sconst maxAgeRaw = flags['max-age']; ...Number(maxAgeRaw)is replaced with a single call to the new helper.packages/cli/src/index.test.ts: +3 tests — a valid-value regression guard, a value-less-flag rejection (the core finding), and a non-numeric/out-of-range table test (abc,0,-1,1.5,3651).+16/-2 in the source file, +34/-0 in the test file. 62 lines total, well under the 300-line target, one conceptual change.
Evaluation Receipt
Real evaluator
npm test(vitest run && npm run test:governance), run live viagit stash/git stash poparound the candidate diff:main@b2abcc1)typecheck/lintclean.Baseline
Measured live by stashing the candidate diff and re-running the identical
npm test/npx vitest runcommands — not inferred from logs, not simulated.Darwin Lineage
DARWIN=not-applicable— a single validation-shape fix has no evolvable population or fitness landscape to search (same judgment recorded for #103/#122/#141/#160). Control-plane liveness check only:npx --yes @metaharness/darwin --versionresolved and printed real usage output tonight; not required for this verdict.Evidence
OBSERVATION (grep:
--max-agenot among the file's four already-hardenedparse*helpers) → OBSERVATION (live repro, baseline: bare--max-age→maxAgeDays: 1, exit 0) → HYPOTHESIS (frozen above) → MEASUREMENT (809/195 → 812/195) → MEASUREMENT (live post-fix repro, all cases) → INFERENCE (independent critic, separate subagent context) → DECISION (adopt critic's upper-bound follow-up) → MEASUREMENT (re-run green) → DECISION (ship; ACCEPT).Reward-Hack Check
Independent adversarial critic (separate subagent context, no authorship stake, read the real diff and the full surrounding file directly): CLEAR, with one non-blocking gap it found and this session adopted before shipping — the first-draft fix had no upper bound, so very large values sailed past the CLI guard and failed one call deeper inside the witness package with a different exit code/message shape. Fixed by importing
MAX_EVIDENCE_AGE_DAYSand mirroring it inparseMaxAgeDays's range check. Critic confirmed: no existing assertion/fixture/golden value/threshold touched; the "valid --max-age" test is not tautological (drives the realrun()→parseArgs→parseMaxAgeDays→evidenceFreshnessPolicyDigest→io.writeFilepath, asserted against written JSON); whitespace/leading-zero/+/scientific-notation numeric strings parse sanely (matching this file's existing permissive-Number()convention elsewhere, not a new footgun); zero regression for any previously-valid input. Full re-run after the follow-up:npx vitest run packages/cli/src/index.test.ts→ 104/104 passed.Security Review
Pure in-memory CLI argument validation. No new I/O, network, filesystem, or credential surface. Strictly more restrictive than before — can only newly reject previously-silently-accepted input, never newly accept something previously rejected. The validated field gates
@dream-machine/witness's evidence-freshness promotion check; a silently-acceptedmaxAgeDays: 1never bypassed that gate, it only ever made it spuriously stricter — but it masked an operator mistake instead of surfacing it, which is the actual harm closed here.Regression Analysis
0 pre-existing tests modified or removed. All 809 baseline vitest tests pass unchanged (812 total, +3 new); 195 governance tests unchanged. Lint/typecheck clean. Build clean, no wasm/NAPI degradation (pure-TS workspace).
ADR
None — a CLI input-validation bug fix matching an existing in-file precedent, not an architectural decision.
Gist
GIST=LOCAL— noghCLI (GH_TOKENinvalid this session) or gist-creation MCP tool available. Full report committed atdocs/dream-cycle/2026-10-13-developer-experience-report.md.Issue
#179
Witness
Reproduce:
node packages/cli/dist/bin.js witness verify-report docs/dream-cycle/2026-10-13-developer-experience-report.md --commit b2abcc14a632d7e0948962065a7c6c8920cf306cMerge Policy
Human review required. This session never self-merges and never autonomously promotes candidate state. No
automerge-safelabel applied.🤖 Generated with Claude Code
https://claude.ai/code/session_016d8nUtzH17Nd2EQqhL2h7f
Generated by Claude Code