feat: normalize volatile tokens in recurrence signatures (v2)#36
Merged
Conversation
Recurrence signatures embedded literal command text, so semantically identical operations never shared a byte-identical signature and never registered as recurring. Introduce a deterministic, model-free normalization pass that replaces volatile tokens (absolute and home paths, URLs, UUIDs, long hex runs, long digit runs) with stable placeholders while preserving command structure, and bump the signature grammar v1 -> v2 (and DETECTION_SPEC_VERSION -> detection/v2) at every mint site. See ADR 0014 and docs/specs/signature/v2 for the rules, real-data yield numbers, and the v1 -> v2 compatibility story (registered mutations keep their immutable v1 selectors; reindex re-mints stored signatures; status detects and hints an outdated index). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Claim
Recurrence detection was reading as dead on its most common agent because
signatures embedded literal command text. Real agent commands are long one-shot
compounds dense with volatile tokens — absolute scratchpad/session paths, UUIDs,
content hashes, timestamps, ports, line numbers — so two semantically identical
operations never produced a byte-identical signature and never registered as
recurring.
This PR introduces a deterministic, model-free signature-normalization pass
that replaces volatile tokens with stable placeholders while preserving command
structure, and versions the change end to end: signature grammar
v1 → v2atevery mint site (
operation,failure,recovery,correction), andDETECTION_SPEC_VERSION → detection/v2so the findings cache (ADR 0013)auto-invalidates.
Full rationale, rules, and compatibility story in ADR 0014
(
docs/decisions/0014-signature-normalization-v2.md) and the versioned grammarspec
docs/specs/signature/v2/(README + JSON Schema + valid/invalidfixtures, validated in-code).
Normalization rules
Applied in order over the whitespace-collapsed command, most specific first;
binaries, subcommands, flags, and shell operators are preserved.
scheme://…to the next shell delimiter«url»/seg/seg…(≥2 segments) at a shell boundary«path»~/…at a shell boundary (≥1 segment)«path»8-4-4-4-12«uuid»a–fletter«hex»«n»The pass is pure, total, and idempotent (normalizing twice equals once); it never
touches the clock, locale, filesystem, network, or a model.
cargo test -p aandcargo test -p bstay distinct;cd /x && go buildandcd /y && go buildcollapse to one shape. Plain long numbers (e.g. a date
20260717) read as«n»,not
«hex».Before / after on real Claude Code history
Imported the machine's actual Claude Code transcripts (35,682 events, 151
sessions) into a throwaway database (isolated
--database+AUTOPHAGY_CONFIG_DIR;the user's real DB/config were never touched).
the default gate (≥3 occurrences across ≥2 sessions) rose from 2 under the
v1literal grammar to 44 underv2. Volatile one-shots now share sensibleshapes:
operation/v2|shell|«path»(72×),cat «path»(28×),reins screenshot --tab «n»(14×). No degenerate mega-bucket — the largest is0.4% of indexed rows.
property of this corpus, not the normalization. Verified directly: the 390
tool failures form 276 distinct failing shells and not one repeats even
twice, under either grammar. The user's failing commands here are genuinely
one-shot exploratory invocations, so there is no failure recurrence to surface.
v2removes the signature bottleneck; it does not manufacture recurrence thehistory does not contain. The near-miss list is now clean normalized shapes
(
until [ -f «path» ]; do sleep 5; done,JAR=«path» … curl … «url») insteadof raw volatile noise.
The end-to-end detector gain is proven deterministically in
autophagy-patterns(
volatile_paths_recur_as_one_failure_under_v2): three byte-distinct failingcommands differing only by scratchpad path now share one
failure/v2signatureand qualify as a single finding across three sessions — exactly the class the
v1grammar discarded.Compatibility
re-derivable projections change.
v1trigger selectors as validaudit records; a
v1selector simply no longer matches a freshly mintedv2signature, and re-proposing generates a
v2candidate. The deterministicgenerator refuses to parse a
v1selector into av2candidate (covered by atest).
autophagy reindex --index-tool-inputre-mints the stored exact-signatureindex under
v2from untouched events;autophagy statusdetects anoutdated index (
EventStore::signatures_below_version) and prints a one-linereindex hint.
Privacy
Normalization is strictly subtractive on derived text: a
v2signature containsless literal command text than the
v1signature it supersedes — absolutepaths, URLs, UUIDs, hashes, and long numbers no longer appear in the derived
signature at all. Raw events are unchanged, no new text is persisted, and
signatures are still indexed only from the redaction-approved projection.
Verification
mise run checkgreen (fmt + lint-D warningspedantic + full workspace test +docs + ci). New unit tests cover every normalization rule plus property-style
idempotence and distinctness; a detector test proves cross-path recurrence now
qualifies; minted signatures are validated against the published
v2schema.🤖 Generated with Claude Code
https://claude.ai/code/session_015LY7xtercMc3NtLeX2z4YV