diff --git a/.claude/memory/MEMORY.md b/.claude/memory/MEMORY.md
index 139a498..1fcb6ba 100644
--- a/.claude/memory/MEMORY.md
+++ b/.claude/memory/MEMORY.md
@@ -17,6 +17,7 @@ Keep this file under 200 lines — anything longer is content bloat, not memory.
- [learnings/sentry-dedupe-must-check-closed-tickets](learnings/2026-05-27-sentry-dedupe-must-check-closed-tickets.md) — step-2 Sentry dedupe must match closed tickets too, not just open — canary errors (no Sentry write tools / ENG-21) get re-filed forever otherwise (APP-1 → ENG-17 closed → ENG-29 dup)
- [learnings/fetch-before-merge-on-long-lived-branch](learnings/2026-05-27-fetch-before-merge-on-long-lived-branch.md) — On long-lived branches, run `git fetch origin ` before `git merge origin/`; local origin ref goes stale during review-feedback rounds (PR #12 round 3 escalation)
- [learnings/git-checkout-theirs-replaces-whole-file](learnings/2026-05-27-git-checkout-theirs-replaces-whole-file.md) — `git checkout --theirs ` during a merge replaces the WHOLE file, silently reverting unrelated edits earlier on the branch; verify with `git diff origin/` afterwards (PR #29 round 1)
+- [learnings/verify-ticket-issues-still-exist-on-main](learnings/2026-05-28-verify-ticket-issues-still-exist-on-main.md) — Re-read the ticket's target file in current `origin/` before drafting; humans push small fixes direct-to-main between ticket creation and agent pickup (PR #29 ENG-30 round 1)
## Decisions
- [decisions/mcp-for-small-writes-checkout-for-big](decisions/2026-05-26-mcp-for-small-writes-checkout-for-big.md) — Single-file writes go through GitHub MCP; multi-file or test-needing changes use the mounted checkout + `git push`
diff --git a/.claude/memory/learnings/2026-05-28-verify-ticket-issues-still-exist-on-main.md b/.claude/memory/learnings/2026-05-28-verify-ticket-issues-still-exist-on-main.md
new file mode 100644
index 0000000..66ae4cd
--- /dev/null
+++ b/.claude/memory/learnings/2026-05-28-verify-ticket-issues-still-exist-on-main.md
@@ -0,0 +1,63 @@
+# Re-read the ticket's target file in current `origin/` before drafting fixes
+
+For docs/copy tickets — and any ticket where the acceptance criteria are
+described by line/snippet against a specific file — the criteria can be
+moot by the time the agent starts drafting. Humans push small fixes
+direct-to-main (no PR, no ticket reference) constantly, especially on
+README and other docs. The window between ticket creation and agent
+pickup is wide enough for entire sections to be rewritten.
+
+Mitigation: after `git checkout -b`, before writing any code, run
+
+```sh
+git fetch origin
+git log origin/ --since= --
+```
+
+and re-read each target file at `origin/:`. If the file has
+been touched since the ticket was filed, manually re-validate each
+acceptance criterion against current content. Drop any criterion whose
+fix is already in main; narrow the PR scope before pushing.
+
+## Anchor — PR #29 / ENG-30 (2026-05-27)
+
+Timeline:
+
+- `15:20:26Z` PR #28 (human) merged — README install section rewritten.
+- `15:22:26Z` reviewer agent files ENG-30 with **4** acceptance criteria
+ based on the just-merged PR #28 state.
+- **`15:23:01Z` human pushes `a028eb3` directly to `main`** (no PR,
+ no ticket reference) — rewrites the install section AGAIN, addressing
+ 3 of ENG-30's 4 criteria.
+- `15:23:20Z` manager agent opens PR #29, forked off `a028eb3` (so the
+ fetch was current), but drafted all 4 fixes from the ticket without
+ re-reading the file in current main.
+- Round 1: reviewer flags 3 of 4 fixes as already-applied. Agent merges
+ main, drops 3 fixes, narrows to 1 line, ships. Cost: one extra review
+ round, one extra build/lint pass, one stale draft on the wire.
+
+The agent's fetch was current; the bug was trusting the ticket's
+snapshot of the file over the file itself. Re-reading the file at
+`origin/main:README.md` before drafting would have caught all 3
+already-fixed criteria in seconds.
+
+## Distinct from existing learnings
+
+- `check-open-pr-before-ticket-pickup` / `recheck-open-prs-at-pr-open` —
+ agent-vs-agent races at ticket-pickup and PR-open time. Direct-to-main
+ commits don't show up in `list_pull_requests` so the PR-grep
+ mitigation doesn't catch them.
+- `fetch-before-merge-on-long-lived-branch` — staleness at merge time,
+ on a long-lived branch. This is staleness at draft time, on a fresh
+ branch.
+- The shape is: "reviewer-filed ticket snapshots a file; humans rewrite
+ the file in the gap; agent drafts against the snapshot."
+
+## Doesn't apply when
+
+- The ticket's acceptance criteria don't reference specific file
+ content (feature tickets, infra tickets).
+- The branch was opened within seconds of the ticket (no realistic
+ window for a direct-to-main commit).
+- The reviewer agent's filing timestamp matches the ticket's described
+ base SHA — implies the reviewer read against current main.