commit · HEAD^@f77caf8 → HEAD@77c6208 · claude-opus-5 (cursor cloud agent)
Five unrelated small fixes, all found by using this tool on its own output rather than by reading the code again.
This review predates the rename to whymark, and the diff below is left as it was recorded: the modules appear at their old paths under src/lib/crev/, and the blob hashes pin to the commit as it was made. Rewriting a diff to match a later name would break the one property that makes a review worth reading.
Writing the first example review surfaced two output bugs: a plain modified file was serialised with from=<same path>, which made a round-trip through the parser report it as renamed; and crev prompt was emitting the human-facing preamble of the prompt template to an agent that only needed the instructions. The CLI also printed "Try --staged" when the user had just passed --staged, and --staged reviews silently included untracked files, which are by definition not staged. Finally, npm run lint rejected the useMediaQuery hook, so it is now built on useSyncExternalStore.
No behaviour in the format itself changed; the parser and serializer fixes only affect what a generated document says about a file.
This review exists to show what the format looks like when it is written about real, boring work rather than a showcase change. Every source: below is either a command whose output I read or an honest inference.
$ npm testnpm testnpm run lintnpm run typecheckBoth commands failed with the same hand-written message, and that message told the reader to "Try --staged or --branch" even when they had just passed --staged — the one suggestion guaranteed to be useless. Routing both through one helper means the advice can be computed from the scope that actually failed.
crev new --staged in a clean tree$ npm run typecheckThe suggestions are filtered against the scope that failed, so the error never recommends the thing the user just tried. Three are shown rather than all four because a one-line hint that lists every possibility reads as noise.
The second call site, identical to the first. Kept as a one-liner so the two commands visibly share the behaviour.
$ npm run typecheckcrev prompt pipes its output straight into an agent, but the template file starts with a paragraph addressed to a human ("Paste everything below into any coding agent"), which the agent would then have read as part of its instructions.
---The split is on the first line that is exactly --- because the template is markdown, where a horizontal rule is the natural boundary between "notes for the reader" and "the prompt itself". Falling back to the whole file keeps a template with no rule usable rather than emitting nothing.
$ npm run typecheckThe comment is the whole point of the third argument: the server renders fallback, so a wrong fallback shows the mobile layout for a frame on a desktop. The review page passes true for that reason.
The first version set state inside an effect to seed the initial match, which npm run lint rejects (react-hooks/set-state-in-effect) because it causes a second render pass on every mount. useSyncExternalStore is the API built for exactly this: subscribe, read, and a separate server snapshot.
$ npm run lint$ npm run buildUnused since the file's FileSection factory stopped taking a status argument; npm run lint reported it.
$ npm run lintUntracked files exist only in the working tree, so including them in a --staged review claimed that files which are not in the index are part of the staged change. The condition now names the two scopes where they belong instead of excluding the two where they do not, which is also correct for any scope added later.
crev new --staged while three new files were untracked and seeing them in the output$ npm testgit's own index line gives abbreviated hashes, so a document mixing the two sources had 7-character hashes for tracked files and 40-character ones for untracked files. Staleness comparison is prefix-based either way; this is purely so the generated file reads consistently.
$ npm testabbrev defaults to 0 so the existing caller in the validator keeps getting the full hash it compares against, and only the generator asks for a short one.
$ npm testCheck moved to the serializer when @check lines started being merged into frontmatter; the import outlived the use. Reported by lint.
$ npm run lintThis is the parser half of a round-trip bug. parseUnifiedDiff fills oldPath from the --- a/path line of every diff, including plain modifications, the serializer then wrote from=<same path>, and re-parsing that file inferred renamed from the presence of from=. A file that was only edited came back as a rename.
@file lines of a generated skeleton, not from a failing test$ npm testThe serializer half of the same bug. Both halves are needed: the guard here stops the bad output being written, and the guard in the parser stops documents that already contain it being misread.
$ npm test