fix: feedback review follow-ups from #95 - #96
Merged
Conversation
- --json validation errors now emit {status:'error', submitted:false,
error} on stdout (exit still 1) — uniform machine-readable contract
with the success and transport-failure shapes
- --file: reject >256KB before reading (detail caps at 4000 chars; a
huge file is a wrong path or an archive) and reject binary content
(NUL check) instead of truncating garbage
- redact.ts: document the accepted IPv4 over-scrub asymmetry
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fermionic-Lyu
enabled auto-merge (squash)
August 18, 2026 19:29
jwfing
reviewed
Aug 18, 2026
jwfing
left a comment
Member
There was a problem hiding this comment.
Review: fix — feedback review follow-ups from #95
Summary: A tight, well-tested follow-up that fixes the three non-blocking suggestions from #95 (JSON-channel validation errors, --file size/binary guards, and a documenting comment on the IPv4 over-scrub) — no Critical issues, safe to merge.
Requirements context
No /docs/superpowers/ (or docs/specs/) spec matched this PR — assessing against the PR description and the parent #95 review intent alone. The PR is scoped precisely to the three named follow-ups and adds nothing beyond them, which is correct for a review-follow-up change.
Findings
Critical
(none)
Suggestion
- Functionality / defense-in-depth —
src/commands/feedback.ts:143-148. The size guard relies onstatSync(opts.file).size, which reports0for character/FIFO special files and follows symlinks. A--filepointed at e.g./dev/zero(or a symlink to one) passes theMAX_FILE_BYTEScheck and thenreadFileSync(..., 'utf8')reads unbounded, hanging/OOMing the CLI. This is pre-existing (before this PRreadFileSyncran with no guard at all, so the PR is a net improvement and not a regression), but since this change is specifically the place that adds a size ceiling, a!statSync(...).isFile()reject would close the one path the byte-count guard can't. Non-blocking — an agent or human aiming--fileat a device node on their own box is a remote scenario.
Information
- Software engineering —
test/feedback.test.ts:140-142. Nice catch addingafterEach(() => { process.exitCode = 0 }): the new--jsonvalidation test intentionally setsprocess.exitCode = 1, and without the reset a green run would still exit the vitest process non-zero. Calling this out as a positive, not a defect. - Security —
src/commands/feedback.ts:148. Binary detection keys on a NUL byte only, so a non-NUL binary with invalid UTF-8 would be read (as U+FFFD replacement chars) and sent. Acceptable — the 256 KB ceiling and the 4000-chardetailtruncation bound the blast radius, and NUL-sniffing is the standard cheap heuristic. No action needed. - Functionality —
src/commands/feedback.ts:149-152. Themsg.startsWith('--file') ? msg : ...re-wrap correctly avoids the--file <path>: --file <path> is …double-prefix for the guards' own messages while still prefixingstatSync/readFileSyncerrors (ENOENT, EISDIR). Verified against theguard→onError→diepath insrc/index.ts:31-38— the non---jsonbranch still rethrows and reachesdieas plaintext stderr exactly as before, so existing behavior is preserved.
Dimension coverage
- Software engineering: Good. New tests exercise the changed behavior directly (text/oversized/binary
--file, and--jsonvalidation → JSON-on-stdout + exit 1). Style, comments, andthrow-plain-Error convention match the surrounding file. - Functionality: All three follow-ups land correctly.
--jsonvalidation errors now emit{status:"error", submitted:false, error}on stdout withprocess.exitCode = 1(uniform with the success/transport shapes) instead ofguard()'s plaintext stderr; the deliberate exit-1 (fixable flags) vs exit-0 (unfixable backend) asymmetry is preserved and documented. - Security: No new secrets logged or returned; the size/binary guards reduce the chance of shipping a garbage/binary blob.
--filereads a local path the caller already controls; content is still redacted before send. See the special-file Suggestion above. - Performance: Bounded —
statSync+ a ≤256 KBreadFileSync, no hot path, no new network/DB work.
Verdict
approved (informational — zero Critical findings; the GitHub green-check remains a separate human action). One non-blocking Suggestion and a few Information notes.
Merged
Fermionic-Lyu
added a commit
that referenced
this pull request
Aug 18, 2026
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.
Addresses the three non-blocking suggestions from the #95 review:
--jsonvalidation errors are now JSON. Previously a bad/missing flag unwound throughguard→dieas a plaintext stderr line while every success/transport path returned JSON. Now--jsongets{status:"error", submitted:false, error}on stdout with the same self-teaching enum message; exit code stays 1 (validation is fixable by the agent).--fileguards: reject files >256KB before reading (detail caps at 4000 chars — anything huge is a wrong path or an archive) and reject binary content (NUL check) instead of redact/truncating garbage.redact.ts: comment documenting the accepted IPv4 over-scrub asymmetry (4-part version strings can be scrubbed; over-scrub is recoverable noise, under-scrub is a leak). Same comment mirrored to the ingest's copy in InsForge/insta-feedback.npm run typecheck && npm testgreen (308).🤖 Generated with Claude Code
Summary by cubic
Unifies JSON-mode validation output in the feedback command and hardens
--filehandling to prevent garbage input. Old:--jsonvalidation errors were plaintext on stderr; new: a JSON object{status:'error', submitted:false, error}is printed to stdout with exit code 1. Also rejects files >256KB and binary content before reading;redact.tsonly adds a comment about accepted IPv4 over-scrub.--jsonmode, validation errors no longer throw; the command prints the JSON error on stdout, setsprocess.exitCode = 1, and returns. Non-JSON mode behavior is unchanged (throws on bad flags).--fileis size-checked before read and rejected if binary (NUL check). Error messages name the path and reason.Migration
--jsonvalidation errors, switch to parsing stdout JSON and checkstatus:'error'andsubmitted:falsewith exit code 1.--fileare text and under 256KB; trim or sample logs before sending.Written for commit f7b2af7. Summary will update on new commits.