Repository navigation
v1.18.3
1.18.3 — 2026-10-29
Third pass: the items the previous two rounds left open, plus two findings from the maintainer's re-review (the policy fingerprint was cached for 5 minutes, and a run killed by a signal after printing a result was still reported as success).
- [P1-16] Two concurrent fix-mode reviews on the same repository could overwrite each other's working tree. Fix mode now takes a per-repository lock (
activeFixRepos, keyed by the resolved path) for the duration of the run; a second fix request is refused with an actionable message while read-only reviews stay unrestricted. The lock is released on every settle path and on every preflight refusal, so a rejected call cannot leave a repository locked. - [P1-8] A cancelled synchronous review lost the paid-for work.
waitForResult=truenever registered a job, so when the client cancelled, the SDK dropped the response and the subagent reports were unreachable. Both review and followup now create and register the job before branching: a cancelled sync call leaves a pollable job (claude_review_statuswith no jobId lists it by repository), and the synchronous return value is unchanged. - [P2-14] The stale-process fingerprint check was cached for 5 minutes. The guard self-test result carries a TTL, but the hook is spawned from disk on every call — so an upgrade without a host restart could run up to 5 minutes with two different policies while everything looked green. When
codeDrift()says the sources on disk are newer than the process, the self-test now runs withrefresh: trueand refuses immediately. - [SEC-14]
CLAUDE_REVIEW_ALLOW_UNGUARDED=1also bypassed a failed guard installation. That is exactly the case it must never bypass: the run would advertise a guard while no command is policed. The escape hatch now applies only to a guard the operator deliberately switched off (CLAUDE_REVIEW_SHELL_GUARD=0); installation and self-test failures always refuse, with instructions to fix the guard. - [P2-7] A run killed by a signal (or exiting non-zero) after printing a result was reported as success. Only the JSON event was consulted. The report is now preserved, but the result is
isError: truewithstatus: "completed_with_error", a banner naming the signal/exit code, andexitCode/signalin structuredContent (followup too). - [P2-4] Result size had no bound. A very large report could exceed what an MCP client will deliver.
claude_review_statusnow caps the text andstructuredContent.reportat 512 KiB with UTF-8-safe truncation, a marker line, and pointers to the log/partial-report files;job.resultitself is untouched, so repeated polls do not accumulate markers. - [P2-1] Two report formats coexisted in one prompt.
REPORT_FORMAT, the bundledSKILL.mdblock, the native appendix and the fallback prompt are now one contract, verbatim:## Code Review Summary/<verdict>,## Findings (N)with one### [SEVERITY] title — path:lineblock per finding + What/Why/Fix/Evidence, severitycritical | major | minor | nit,## Notes, and an explicit no-findings branch. The fleet prompt carries the block exactly once. - [P2-5]
cancel-test.mjsonly worked on Windows (tasklist). It now inspectsps -axo pid=,command=on POSIX and matches the resolved claude CLI path, so the real-CLI cancellation path can be exercised on macOS/Linux (still opt-in and billed). - [scanner] Three more command-executing git keys are refused:
pager.<subcommand>,core.askPass,sequence.editor(live values only — a dead path stays a note;pager.*booleans are inert and allowed). UNC values (//server/shareor the backslash form) are refused before any filesystem probe, so a Windows UNCcore.attributesFile/[include]no longer stalls the pre-spawn scan for ~21 s. - Suites: shell-guard 238, audit-fixes 272, p0-regression 95, validation 16, cross-cases 149/149 (C1–C26: new C23 signal-exit, C24–C26 concurrency/sync-job), smoke PASS —
npm testgreen.