pbakaus/impeccable · warning

[impeccable] skipped unsafe copy edit DOM restore for

Error message

[impeccable] skipped unsafe copy edit DOM restore for

What it means

When the user discards pending copy edits, the script tries to restore each edit's original text back into the page DOM. This warning counts elements it refused to restore because it was unsafe: the target element was not found, lacked originalText, still had child elements, or its current text did not match the edit's recorded newText (i.e. the DOM changed since the edit). The page DOM may remain visually edited until a refresh.

Source

Thrown at skill/scripts/live-browser.js:4362

      fetchPendingCount();
    }
  }

  function restoreDiscardedManualEdits(entries) {
    let failures = 0;
    for (const entry of entries || []) {
      for (const op of entry.ops || []) {
        if (restoreMixedTextNodeManualEdit(op)) continue;
        const el = findManualEditRestoreElement(op);
        if (!el || typeof op.originalText !== 'string' || !canRestoreManualEditElement(el, op)) {
          failures += 1;
          continue;
        }
        el.textContent = op.originalText;
      }
    }
    if (failures > 0) {
      console.warn('[impeccable] skipped unsafe copy edit DOM restore for', failures, 'edit(s). Refresh to reset the page DOM.');
    }
    return failures;
  }

  function canRestoreManualEditElement(el, op) {
    if (!el || typeof op?.originalText !== 'string') return false;
    if (el.children && el.children.length > 0) return false;
    return normalizeManualContextText(el.textContent) === normalizeManualContextText(op.newText);
  }

  function mixedTextWrapRestoreHint(el) {
    if (!el || !el.dataset || el.dataset.impeccableTextWrap !== 'true' || !el.parentElement) return null;
    const siblings = directMixedTextRestoreNodes(el.parentElement);
    const textIndex = siblings.indexOf(el);
    return {
      kind: 'mixedTextNode',
      parentRef: documentRefForElement(el.parentElement),
      textIndex,

View on GitHub (pinned to 2bc2879276)

Solutions

  1. Refresh the page — that resets the DOM to match the source, which is the documented remedy in the message itself.
  2. Before discarding, avoid navigating or letting HMR re-render the edited elements.
  3. If restores routinely fail, re-pick elements after any re-render rather than accumulating edits across renders.
  4. Verify the edits are leaf text nodes (no child elements), which are the only ones safely restorable.
Defensive patterns

Strategy: type-guard

Type guard

function canRestoreManualEditElement(el, op) {
  if (!el || typeof op?.originalText !== 'string') return false;
  if (el.children && el.children.length > 0) return false; // leaf nodes only
  return normalize(el.textContent) === normalize(op.newText);
}

Prevention

When it happens

Trigger: Clicking the trash/pending-pill discard action after the page DOM changed — the edited element was re-rendered by the framework, its text was edited again, it now contains child nodes, or canRestoreManualEditElement returns false for one or more stashed ops.

Common situations: Framework re-render or HMR replaced the edited node between edit and discard; the user edited an element whose text subsequently changed; edits made in one route/component, discard attempted after navigation; nested-element edits that fail the leaf-only safety check.

Related errors


AI-assisted analysis of pbakaus/impeccable@2bc2879276 (2026-09-08). Data as JSON: /api/errors/4f165a735e1d4120. Report an issue: GitHub.