It clicked, but not on the element you meant
Three identical buttons, a list that grew by four rows, a banner that closed between the capture and the click. The number was right and the target was wrong.
The symptom. The click works. Something happens. It is not what you wanted — the wrong domain got cloned, the wrong row got deleted, the wrong dialog opened.
Nothing errors, because nothing went wrong mechanically. Diwall clicked what you designated. You designated the wrong thing.
Cause 1 — several elements match your selector
A page with three “Clone” buttons, one per domain. This selector picks the first one in DOM order:
{"type": "cliquer", "selecteur": "button:has-text('Clone')"}
Observed for real: the clone started on a different domain than the one intended, and only the server log said so. A silent inversion.
The fix — designate, do not describe. Either qualify the selector with something unique to that row:
{"type": "cliquer", "selecteur": "button[title='Clone example-two']"}
Or use the Set-of-Mark number, which is unique by construction: three identical buttons get three different numbers.
Cause 2 — the page changed, so the number moved
Set-of-Mark numbers elements in DOM order. Add four rows to the list above your target, and your target shifts by four. A procedure validated on a page with one row breaks on the same page with five — same code, same selector, different result.
Worse: something can appear or disappear between your capture and your click. A cookie banner closing, a modal opening. The number you read in the screenshot no longer designates the same element when the click executes.
The fix, two levels.
Recapture Set-of-Mark after any action that changes the DOM, and read the new numbers. That reduces the window; it does not close it on a page that keeps mutating.
To close it, capture Set-of-Mark inside the scenario itself, before the first
cliquer_som:
diwall-shot --url https://target.local/ --som --guide-version 1.3 \
--actions '[{"type":"capturer","nom":"avant","som":true},{"type":"cliquer_som","id":5}]'
Since v1.24.0 the default resolver is hybrid. When a data-dw-som-id marker
exists — set by a capturer with "som": true earlier in the same scenario —
Diwall resolves against that marker instead of re-indexing the live DOM: id: 5
is that element, whatever moved around it. Without a prior in-scenario
capture it falls back to the old raw re-indexing, unchanged. Either way the
answer tells you which path ran, in boussole.respect.som_resolution
(stable, brut, or brut_sans_reference), and flags any stable-versus-raw
disagreement in boussole.respect.som_derive_detectee — the drift is never
silent again.
The marker does not survive across two shot.py calls (each reloads the
page), which is the deeper reason a stateful sequence belongs in one scenario.
--som-brut forces the pre-v1.24.0 pure re-indexing; --som-rafraichir is
kept as a no-op alias.
Identify by content, not by position
“The most recent one is number 7” is true until someone creates a new one.
When your target carries something identifying — a timestamp, a slug, an
identifier in a value or data-* attribute — Set-of-Mark already gives it to
you. elements_som[].texte exposes it, and you can filter the JSON directly:
{"id": 12, "tag": "INPUT", "texte": "clone-2026-08-01-0930"}
Pick the number by matching that text, not by counting rows. No vision model
needed, no heuristic to break next week. Same idea for auditing after the fact
— one evaluer returns the remaining items as JSON, comparable
programmatically:
{"type": "evaluer",
"script": "Array.from(document.querySelectorAll('input.chk-item')).map(i => i.value)"}
In short
- A selector matching several elements picks the first, silently.
- Set-of-Mark numbers shift with the DOM — recapture after every mutation.
- Capture Set-of-Mark inside the scenario before acting; the hybrid resolver then pins a number to that element and reports any drift in
som_derive_detectee. - Identify targets by their content, never by their position in a list.