What. Within a single <config> tag, duplicate kwargs are last-wins at parse time (applyAttributes, grammar/enscribe.peggy — the later result.kwargs[k] = v overwrites), but editConfigKwarg's span edit replaces the FIRST occurrence: setKwargInSpan / removeKwargInSpan use a non-global regex (config-source-edit.js:28-40).
Failure shape. Given <config theme=a theme=b />, picking Tufte in the gear yields <config theme=tufte theme=b /> — the parse still resolves b, so the select snaps back on the next wire; removal likewise deletes the first occurrence and leaves the live one. Cross-NODE duplicates are handled correctly (the edit targets the last carrier config, matching config-discovery's cross-node last-wins); this is intra-node only.
Adjacent gap. No duplicate-kwarg diagnostic exists anywhere (grammar, normalize gate, config-discovery), so the authored shape is silently accepted.
Found during #445 Phase-0 (adversarial cross-check of the rewrite machinery). Rare authored shape — an edge-case defect, not a blocker; fix is targeting the LAST in-span match (or a duplicate diagnostic at the gate, or both).
What. Within a single
<config>tag, duplicate kwargs are last-wins at parse time (applyAttributes,grammar/enscribe.peggy— the laterresult.kwargs[k] = voverwrites), buteditConfigKwarg's span edit replaces the FIRST occurrence:setKwargInSpan/removeKwargInSpanuse a non-global regex (config-source-edit.js:28-40).Failure shape. Given
<config theme=a theme=b />, picking Tufte in the gear yields<config theme=tufte theme=b />— the parse still resolvesb, so the select snaps back on the next wire; removal likewise deletes the first occurrence and leaves the live one. Cross-NODE duplicates are handled correctly (the edit targets the last carrier config, matching config-discovery's cross-node last-wins); this is intra-node only.Adjacent gap. No duplicate-kwarg diagnostic exists anywhere (grammar, normalize gate, config-discovery), so the authored shape is silently accepted.
Found during #445 Phase-0 (adversarial cross-check of the rewrite machinery). Rare authored shape — an edge-case defect, not a blocker; fix is targeting the LAST in-span match (or a duplicate diagnostic at the gate, or both).