Skip to content

The push classifier reads a name inside an expression or an object as the hook's own - #678

Merged
johnnyt merged 1 commit into
mainfrom
sb-wcsm-push-classifier-test
Sep 30, 2026
Merged

johnnyt merged 1 commit into
mainfrom
sb-wcsm-push-classifier-test

Conversation

@johnnyt

@johnnyt johnnyt commented Sep 30, 2026

Copy link
Copy Markdown
Member

What

The push classifier in test/statifier_blocks/assets_test.exs (push_names/1, push_name/2, kind/1) is what the hook-kind tests rest on. It read two shapes of push as the host's expression:

  • an expression carrying a literal, such as a fallback gesture.event || "refresh";
  • a name held in an object literal, const names = {select: "x"}; this.pushEvent(names.select, {}).

kind/1's stamped-name rule is per file (stamped_names?/1 asks whether the file reads some el.dataset.*Event), so a draw hook that reads a stamped name anywhere could push a name of its own in either shape and still pass as draw-only, unless it spelled a command or list event name.

push_name/2 now has two more clauses, after the existing quoted and binding-held ones:

  • keyed_name/2 resolves object.key through an object literal the file binds object to (any of its bindings) and answers the quoted name under key;
  • any quoted name inside the argument makes the push the hook's own.

A name read from a stamped attribute through an object stays an expression: the existing probe const events = {select: this.el.dataset.selectEvent}; this.pushEvent(events.select, {}) is unchanged and still green, and so is the shipped map hook's this.pushEvent(gesture.event, gesture.payload).

A new test, "a name inside an expression or an object is the hook's own", holds four probes (two fallback expressions, two object-held names, across pushEvent and pushEventTo and the three quote styles) to [{:literal, "select-row"}], to pushing their own name and to not being draw-only, each alone and again after a stamped-name binding.

Test-only: no lib/ or hook change, no changelog fragment (changelog.d/README.md excludes tests).

Sabotage

Each reverted from a copy, byte-equal, and recompiled before the next:

Mutation Outcome
the quoted-name-inside-an-expression clause dropped from push_name/2 the new test red on the fallback probe (assertion)
the object-literal clause dropped from push_name/2 the new test red on the object-held probe (assertion); re-run after the Credo refactor of keyed_name/2, same result
the map hook pushing gesture.event || "refresh" with this change: "every other hook only measures or draws", "exactly one hook pushes commands" and the exact-source map test red; on main: only the exact-source map test red

Gate

Full mix quality green on the committed tree: 3,952 of 3,952 tests, 95.3% coverage, dialyzer clean, ADR cites green. A first run was red on one Credo readability finding (a single-clause with in keyed_name/2), rewritten as a case.

Review

In-turn review: re-read the diff against the bead. The acceptance asks for a probe for each shape classed as pushing its own name, each sabotaged; the table maps each shape's clause to a red run. The inside-an-expression rule is deliberately broad: a quoted string anywhere in the name argument (a comparison, a bracket key) counts as the hook's own, which can only make the guard stricter; no shipped hook pushes such an argument today, per a read of every pushEvent call under assets/js/.

Refs: sb-wcsm

The assets test's push classifier read a push whose name is an
expression carrying a literal (a fallback such as
gesture.event || "refresh") or a name held in an object literal
(const names = {select: "x"}; pushEvent(names.select)) as the host's
expression. Its stamped-name rule is per file, so a draw hook that
reads some el.dataset.*Event could push a name of its own that way and
still pass as draw-only unless it spelled a command or list event name.

push_name/2 now resolves object.key through an object literal the
file binds object to, and reads any quoted name inside the argument as
the hook's own. A new test holds four probes, two per shape, to
pushing their own name, each alone and after a stamped-name binding.

Sabotaged: dropping either new clause turns the new test red; a map
hook pushing gesture.event || "refresh" now fails the draw-only test
as well as the exact-source one. Test-only; no lib change.

Gate: full mix quality green on this staged tree (3,952 of 3,952
tests, 95.3% coverage, dialyzer clean, ADR cites green).

Refs: sb-wcsm
@johnnyt
johnnyt force-pushed the sb-wcsm-push-classifier-test branch from a978dc2 to cd90026 Compare September 30, 2026 11:12
@johnnyt
johnnyt merged commit 417cc9d into main Sep 30, 2026
2 checks passed
@johnnyt
johnnyt deleted the sb-wcsm-push-classifier-test branch September 30, 2026 11:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant