diff --git a/TODO.md b/TODO.md index 3bff5523..98892444 100644 --- a/TODO.md +++ b/TODO.md @@ -406,10 +406,26 @@ outside the example's new README: `usePanelMemory`. A key collision between those namespaces would produce exactly this: one panel's text arriving in another's buffer, with no server involvement and nothing persisted. - First moves, in order: reproduce with a job whose output is distinctive (`seq 1 100000`), then check - whether the editor's content state or only its RENDER is affected — `Cmd+S` at that moment answers it, - as does closing and reopening the tab. If the buffer really is clean and only the view is wrong, the - suspect is a shared component instance; if the buffer is polluted, it is a key collision. + **Screenshot 2026-08-16 answers the first question and kills two theories.** The tab carries a DIRTY + dot, and the log lines have Monaco line numbers continuing the file's own sequence (…180, then eight + lines of dotenv/POSTGRES_URL output, then 189 ``). So the MODEL was mutated — this is the + editor's content state, not its render, and the earlier "the file was okay" means it was simply never + saved. Note the splice is mid-file, not a replacement: JSX text and log text share line 180 + (`Forgot?--env-file=.env --watch src/server.tsx`). + + Ruled out by that: `CodeSurface` renders with shiki, not Monaco, so the two cannot share an editor + instance. And the app's only other Monaco mount (`FileViewer/renderers/EditorRenderer.tsx`) passes no + `path`, so its model URI is `inmemory://model/N` and cannot collide with the editor's `file:///…`. + + So the pollution arrives as TEXT through the editor's own content path — `openFile`, `setContent`, or + the end-of-turn refresh that re-reads every clean file. That last one is the prime suspect: it is the + only thing that writes a buffer without a keystroke, it runs exactly when a background job is + producing output, and it lands its result by path. + + One thing to rule out first, because it is mine and it is recent: `2b70a570` gave `` a real + `path`, so models are now keyed by file URI globally rather than being per-mount `inmemory://`. Two + panels open on the same file now share one model. That should be an improvement, but it is a change + in exactly the layer that turned out to be involved. Worth noting because it is the reason to look at all: an editor that can show content the file does not contain is a correctness problem even when it never writes — the next person's instinct will be to diff --git a/src/apps/officer-web/App.tsx b/src/apps/officer-web/App.tsx index 2ec78918..99789e3c 100644 --- a/src/apps/officer-web/App.tsx +++ b/src/apps/officer-web/App.tsx @@ -34,7 +34,7 @@ export function App() { } /> - {/* Route pairs, like /headscale and /photos below: the bare page route exists so the + {/* Route pairs, like /offscale (a plugin now) and /photos below: the bare page route exists so the existing links into it keep working, and its `SettingsRoute` guard redirects to the first section. The section is the URL rather than a `*_SELECTED` global, so a settings sub-page is linkable, bookmarkable and cmd-clickable. */}