--- name: feedback-fake-dom-escapehtml-harness description: When writing an ad hoc fake-DOM harness to independently verify frontend/app.js click/navigation flows, document.createElement's stub must implement real textContent->innerHTML entity-escaping, or escapeHtml() silently returns "" and looks like a content bug that isn't real. metadata: type: feedback --- `frontend/app.js`'s `escapeHtml(text)` (line ~20) works by setting a real DOM element's `.textContent` and reading `.innerHTML` back, relying on the browser to do entity-escaping as a side effect — it does not use string replace itself. **Why:** while independently verifying task 773a7a08 (Planner 产出总览 list click-through to `#/artifacts/:id`), I wrote a throwaway Node `vm` harness to simulate a real click -> hashchange -> render() -> mountArtifactBrowser -> showPreview flow (going beyond the repo's own `frontend/test_graph_console_smoke.js`, which only exercises pure render functions, not the full DOM/fetch mount flow). My first `document.createElement` stub had a naive `innerHTML` getter/setter pair that just stored/returned a string, with no `textContent` handling at all — so every `escapeHtml()` call inside app.js silently returned `""`, and the simulated artifact preview came back completely blank (type and content both empty) even though the fetched artifact object was 100% correct. This looked exactly like the real bug this task was fixing. Only after tracing `artifact.lineage`/`artifact.content` at every step and finding them intact right up until the final `escapeHtml()` call did the harness bug become obvious. **How to apply:** any time you build a fake DOM to validate `frontend/app.js` logic beyond what `frontend/test_graph_console_smoke.js`'s `makeFakeDiv()` already covers, either reuse that file's `makeFakeDiv()` verbatim or give your own stub a `textContent` setter that HTML-escapes (`&`, `<`, `>`, `"`) into the same backing store `innerHTML` reads from. If a simulated preview/content render comes back suspiciously blank while every value up to the last `escapeHtml()`/DOM-write call traces correctly, suspect the harness's fake DOM before suspecting app.js.