the trap keeps its evidence, and says where the procedure is

This bug will not be reproduced on demand. It will arrive as somebody's report,
hours later, from a browser whose console is long gone — so a `console.warn` is
seen by nobody, and "what did you see?" gets an answer built from memory and a
screenshot.

So the trap now persists. Up to five occurrences in
`localStorage['officer:editor-buffer-trap']`, each carrying the stack at the moment
of the edit, the first 200 characters that arrived, how many, which file, and when.
The question becomes "paste this key", and the answer is complete.

Recording a bug must never become one: private mode, a full quota and a disabled
storage API all throw at that write, and none of them is worth breaking an edit
over. The console line survives either way.

`docs/editor-buffer-corruption.md` is the procedure — what it looks like, the four
candidates already eliminated and why, the one command to ask a reporter for, how
to read each field, what an EMPTY key would mean (either the editor was focused,
making it a paste, or the insertion came in chunks under the threshold), and the
instruction to delete every piece of this once the cause is known. Linked from
TODO.md and from CLAUDE.md's reading list, so somebody handed a report finds it
without grepping for it.

Stated there rather than left implicit: a fix invented without knowing the cause
would hide the symptom on the one screen where it is visible while the mechanism
carried on doing whatever else it does. The corruption is never saved and reopening
the tab clears it, so waiting is cheap and a wrong fix is not.

tsgo clean, frontend builds, 873 pass / 7 fail unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-16 11:18:56 +00:00
co-authored by Claude Opus 5
parent fc8d02e8e1
commit c0e61a4cba
4 changed files with 133 additions and 18 deletions
+6 -4
View File
@@ -428,10 +428,12 @@ outside the example's new README:
no synthetic keyboard events, no clipboard writes near the editor. That leaves Monaco's own change
event, which means it looks like a paste or a programmatic `executeEdits`.
`reportSuspiciousEdit` in CodeEditor.tsx logs any insertion over 200 characters that arrives while
the editor is NOT focused, with a stack trace taken at that moment. That is the missing evidence:
whoever calls it will be named in the trace. Delete it once the cause is known — it is a trap, not a
feature.
**`docs/editor-buffer-corruption.md` is the procedure — read that when someone reports this.** A
trap is set: `reportSuspiciousEdit` in CodeEditor.tsx records any insertion over 200 characters
arriving while the editor is NOT focused, with the stack at that moment, into
`localStorage['officer:editor-buffer-trap']` (last five). It persists rather than only logging
because this arrives as a report hours later, when the console is long gone — the question becomes
"paste this key" instead of "what did you see?". Delete all of it once the cause is known.
One thing to rule out first, because it is mine and it is recent: `2b70a570` gave `<Editor>` a real
`path`, so models are now keyed by file URI globally rather than being per-mount `inmemory://`. Two