Drafter hardening (milestone #232) — plugin hook fix, usage signal, drift check, duplicate finder, un-merge #82
Reference in New Issue
Block a user
Delete Branch "dev"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Completes milestone #232. Six commits, CI green on each.
The blocker, fixed first
Every plugin hook was inert, silently (#2198). Three independent defects, each fatal alone:
CLAUDE_PLUGIN_OPTION_<KEY>uppercased; all four hooks read the lowercase spelling, so URL and token were always empty. This disabled the SessionStart dynamic tier, process sync, prompt auto-inject, and the write-path trigger at once.jq -rR '@uri'encodes line by line. A multi-line payload came back as several encoded lines joined by raw newlines — invalid URL, curl fails, hook exits 0 in silence. Auto-inject only ever worked for single-line prompts; the write-path trigger sends code, so it could never have worked at all.cut -c1-1200caps each line, not the payload — so the prior-art size budget wasn't one.Verified live against the running instance after the fix: dynamic rules + project context load, auto-inject surfaces a snippet on a multi-line prompt, and the write-path trigger returns its place-arm hit with session dedup suppressing the repeat. That closes the outstanding live verification for #2082, which was blocked rather than broken.
The SessionStart warning now also covers "neither URL nor token arrived" — previously the single install state that produced no signal at all, which is exactly the state defect 1 created.
The record can now age honestly
Three complementary signals — the three ways a snippet corpus decays:
note_usage_events(migration 0071) records surfaced vs pulled. Closes the gap #2082 left open: the write-path place arm carries no score and so has no home inretrieval_logs, meaning the arm firing on the strongest possible claim was the one nobody could measure. Both arms now emit events under distinct sources.verify_snippet). The server has no checkout and deliberately never gets one. A verdict is stamped with a hash of the code it was checked against, so it expires by itself on edit — no invalidation logic to maintain or forget.verification=attentioncatches failing and expired verdicts in one index-served predicate.Plus #2165 un-merge — the exact inverse of merge. Per-source attribution is now recorded at merge time (each entry keeps only what that source added), which makes partial un-merge exact and makes it impossible to strip a call site the survivor legitimately owns.
Two bugs found in passing, fixed here
doMergederived source ids from that list — a corpus-wide suggested group would have rendered incomplete and silently merged only the visible subset. Latent before this work; a corpus-wide selection exposed it.trashhad no per-entity restore, only batch. Addedrestore_entity, the missing inverse ofdelete().Known state after merge
plugin/**isn't in CI'spaths:filter, and the plugin installs straight from this repo — so plugin changes are untested and live on push. That is how the three hook defects reached a real install. The Python/UI work here is covered; the hooks still have no CI./pluginupdate +/reload-pluginsto pick up the hook fixes.🤖 Generated with Claude Code
https://claude.ai/code/session_01UaYUaouG9jjhATyuxCKrQs