bake: the anchor must have matched one element on the page

The lasting rules a bake appends apply to every element the anchor
matches, so a `tag.class` anchor shared by siblings (three cards from one
JSX element, say) restyled all of them, not the element the user picked.
The overlay now journals, with the generate event, the anchor it would
bake on (`element.anchor`: the id, else the tag with its classes) and how
many elements matched it when Go fired (`element.anchorMatches`). The
planner bakes only when the source anchor is that same selector and the
count is one; otherwise it leaves the carbonize block with the count in
`bakeSkipped`, and the agent integrates the variant by hand.

Written with AI assistance (Claude).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Abdul Wahab
2026-09-15 05:45:49 +05:00
committed by Abdul Wahab
co-authored by Claude Fable 5.1
parent 0166cbb870
commit 71a3341289
5 changed files with 168 additions and 10 deletions
+11
View File
@@ -991,9 +991,20 @@
}
} catch { /* cross-origin */ }
}
// The selector a mechanical bake would anchor lasting rules on, and how
// many elements it matches right now: the bake refuses anything but one,
// since its rules would restyle every match, not just this element.
const cssIdent = (s) => /^[A-Za-z_-][\w-]*$/.test(s);
const anchorClasses = [...el.classList].filter(cssIdent);
const anchor = el.id && cssIdent(el.id)
? '#' + el.id
: (anchorClasses.length ? el.tagName.toLowerCase() + '.' + anchorClasses.join('.') : null);
let anchorMatches = null;
if (anchor) { try { anchorMatches = document.querySelectorAll(anchor).length; } catch { anchorMatches = null; } }
return {
tagName: el.tagName.toLowerCase(), id: el.id || null,
classes: [...el.classList],
anchor, anchorMatches,
textContent: (el.textContent || '').slice(0, 500),
outerHTML: sanitizedContextOuterHTML(el, 10000),
computedStyles: {