patch-cc 0.2.4 — repair the 2.1.227 sentinel collision
Repairs patching on Claude 2.1.227. On that build patch-cc refused to do
anything at all — apply and doctor both stopped at
! ... is already patched and no pristine backup exists, so there is
nothing clean to patch from.
on a freshly installed, untouched binary. Upgrade and re-run patch-cc (or
patch-cc apply --from-cache).
What broke
Nothing in any matcher — every patch is green on 2.1.227. What broke was
detection: is_patched() treated the __cc_ identifier prefix as proof of
patch-cc's own edits, and 2.1.227 ships that prefix itself — __cc_name,
__cc_line, __cc_set, twenty sites inside an env-scrubbing shell snippet.
Every pristine install therefore read as already patched, and the gate that
exists to prevent patching on top of unknown edits blocked the tool's primary
function instead.
Counted across the pristine backups: 2.1.216 through 2.1.226 carry 0
occurrences of __cc_; 2.1.227 carries 20.
The fix
Authorship is declared, never inferred. Every patched bundle ends with the
//patch-cc {...} manifest line — deliberately written as the record of what
was applied — so that record is now the only thing is_patched reads:
def is_patched(source: str) -> bool:
return read_manifest(source) is not NoneDeleted outright: the SENTINEL fingerprint, the legacy --version-marker
fingerprint, and the "patched by an older patch-cc (no manifest)" status
branch that is now an impossible state. Not taken: narrowing the sentinel to
exact identifiers (it already collides — __cc_line is both a patch-cc
arrow-param and upstream's shell variable) or demoting it to a weaker signal
(as of 2.1.227 the prefix is in every pristine build, permanently — a signal
that always fires helps no verdict). Nothing is version-conditional: a
pristine binary is one without our record, on 2.1.227 and every build after
it.
Binaries patched by pre-manifest versions of patch-cc now read as clean;
Claude's daily auto-update replaced that population long ago.
Verified
doctor is green against pristine 2.1.227 and against all nine kept backups
(2.1.216 → 2.1.226), and a real 2.1.227 apply/status/restore round-trip
behaves: backup created, manifest read back, second doctor tests against
the backup. The full postmortem lives in the
release-watch ledger.