Skip to content

refactor(core): round-2 polish cluster — 4 follow-on beads (rf2-byut1)#1009

Merged
mike-thompson-day8 merged 4 commits into
mainfrom
refactor/rf2-core-batch-polish-v2
May 14, 2026
Merged

refactor(core): round-2 polish cluster — 4 follow-on beads (rf2-byut1)#1009
mike-thompson-day8 merged 4 commits into
mainfrom
refactor/rf2-core-batch-polish-v2

Conversation

@mike-thompson-day8
Copy link
Copy Markdown
Contributor

Summary

Round-9 batched-by-surface dispatch against implementation/core. Four
P2 follow-on beads from the rf2-byut1 round-2 audit, one commit per
bead in one PR.

Commits

Bead Commit Title
rf2-rk169 341ab00 align rf/handlers predicate contract with metadata-only spec
rf2-6w7zn c1c8038 emit :rf.registry/handler-replaced on every re-registration
rf2-4ymm0 a82ccd6 P2 polish bundle — CQ4/EV4/PF1/SP6/CFX3
rf2-o7ayf 5a926dc direct unit coverage for emit-substrate + core-artefact factory

Per-bead notes

rf2-rk169 — handlers predicate (metadata-only). Spec (API.md row
156, 001 §The query API, 002 §The public registrar query API) describes
the pred-fn as applied to each metadata-map. The impl called it as
(pred-fn id meta) — non-portable. Pre-alpha: switch to the spec'd
shape, update the lone existing test to use (fn [m] ...).

rf2-6w7zn — handler-replaced on every re-registration. Spec 001
§Hot-reload trace surface mandates emit on every re-registration so
devtools refresh from the event. The impl gated on
(not= (:handler-fn previous) (:handler-fn metadata)), dropping legitimate
events for kinds like :frame whose slot replacement need not rotate
:handler-fn. Emit unconditionally; keep :different-fn? in :tags
so tooling can branch idempotent reloads.

rf2-4ymm0 — P2 polish bundle. Selected items from the 23-item
bundle, scoped to implementation/core to avoid spec hot-zone risk
(spec/Conventions.md, spec/Spec-Schemas.md, spec/001-Registration.md
are sequential per the dispatch rules):

  • CQ4with-frame rejects vector bindings of wrong arity
    (correctness; prevents silent fall-through to Shape 1 with vector
    *current-frame* value)
  • EV4police-effect-map-shape! short-circuits on well-shaped
    maps via every? #{:db :fx} pre-check
  • PF1 — collapse build-name JVM/CLJS twins into one CLJC defn
    (bodies were identical)
  • SP6 — shared runs-on-platform? helper across fx/cofx
  • CFX3 — align :db / :event standard-cofx docstrings

Skipped (hot-zone): SP3/SP9 (:event/kind:rf.event/kind),
CFX1 (::cofx/no-value:rf.cofx/no-value).

rf2-o7ayf — audit → tests. Audit recommended direct unit tests for
emit_substrate/make-listener-registry and core_artefact/defwrapper
absent-policy branches — both underpin multiple public surfaces, both
had only indirect coverage.

  • emit_substrate_test.clj (9 tests): register / unregister / clear /
    fan-out / empty-noop / listener-exception isolation / external atom /
    re-register-replaces.
  • core_artefact_test.clj (12 tests): every :on-absent policy
    (:throw / :nil / :false / :empty-vec / :empty-map /
    literal), :ex-data symbol scoping, structured throw shape.

LoC delta

10 files changed, 487 insertions(+), 99 deletions(-) — net +388 LoC,
driven by the +290 LoC of new tests (rf2-o7ayf).

Test plan

  • clojure -M:test from implementation/core — 477 tests, 2461
    assertions, all passing (was 456 before; +21 new tests)
  • npm run test:cljs — 1817 tests, 5105 assertions, all passing
  • npm run test:elision — every sentinel PRESENT

Mike Thompson added 4 commits May 14, 2026 11:57
…k169)

Per spec/API.md row 156, spec/001-Registration.md §The query API, and
spec/002-Frames.md §The public registrar query API the `pred-fn`
supplied to `(handlers kind pred-fn)` is applied to each metadata-map.
The implementation called the predicate as `(pred-fn id meta)` — a
unary predicate written to spec arity-failed; code written to the
current behaviour was non-portable across implementations.

Change to spec — metadata-only, single-arg. Id-namespace filtering
composes via a user-tag on the slot (or `filter` over the result map's
keys); the docstring carries the new guidance. Pre-alpha: no
back-compat shim.

The existing test exercised the 2-arg shape; updated to drive the
filter through a `:rf/group` user-tag on the slot's meta, which
documents the right composition idiom.
…n (rf2-6w7zn)

Per Spec 001 §Hot-reload trace surface — Spec 001 / 009 require the
trace event to fire on EVERY re-registration so devtools (10x,
re-frame-pair) refresh their view from the event. The `register!` impl
only emitted when `(not= (:handler-fn previous) (:handler-fn metadata))`
held, so kinds without a `:handler-fn` slot (`:frame`, where reg-frame
replaces the metadata/config map) never surfaced through the trace.

Emit unconditionally on re-registration; preserve `:different-fn?` in
`:tags` so tooling can branch idempotent reloads from real fn-identity
changes without re-emitting through a sibling surface.

The outermost `interop/debug-enabled?` gate stays — :advanced +
goog.DEBUG=false still constant-folds the entire branch.

Test update: `trace-stream-completeness` exercised both a frame
re-registration (now emits with `:different-fn? false`) and an event
re-registration with a different body (`:different-fn? true`). The
asserter now partitions the captured events by the `:different-fn?`
slot, locking the new contract — at least one of each must surface.
Selected items from the P2 polish bundle (rf2-4ymm0), scoped to
implementation/core to avoid spec hot-zone collisions with sibling
batches.

CQ4 — `with-frame` rejects vector bindings of wrong arity
  Shape 2 of `with-frame` is `[sym expr]`. A vector binding of any
  other arity (typos like `[]` or `[f g h]`) silently fell through to
  Shape 1, which would `binding` `*current-frame*` to a vector and
  produce a confusing runtime error far from the call site. Reject at
  expansion time with a structured ex-info. +12 LoC src; +20 LoC test.

EV4 — `police-effect-map-shape!` short-circuits on well-shaped maps
  Per dispatch × per `reg-event-fx` return the policer allocated an
  `offending` vec even when the effect-map carried only `:db` /
  `:fx` keys (the overwhelming majority of returns). Pre-check via
  `every? #{:db :fx}` first; fall through to the doseq build only
  when at least one key is offending. ~ -8 LoC effective hot-path.

PF1 — collapse `build-name` JVM/CLJS twins into one CLJC defn
  The fn body was identical across the reader-conditional twins
  (string assembly with no platform calls). Drop the duplicate
  pair; one CLJC defn covers both scopes. ~ -15 LoC.

SP6 — shared `runs-on-platform?` helper between fx and cofx
  Per Spec 011 §634-642 the `:platforms` slot applies symmetrically
  to `reg-fx` AND `reg-cofx`. The two parallel `*-runs-on-platform?`
  predicates held identical bodies. Promote the fx-side defn to
  public `runs-on-platform?`; alias from cofx.cljc. ~ -8 LoC.

CFX3 — align `:db` / `:event` cofx docstrings
  Both standard cofx are no-ops (the runtime pre-populates the slot).
  The docstrings disagreed on shape ("drain loop" vs "dispatch
  envelope") for the same mechanism — runtime. Re-align so the pair
  reads as a single contract surface.

Skipped from the bundle in this PR to avoid spec hot-zone risk
(spec/Conventions.md / spec/Spec-Schemas.md / spec/001-Registration.md
are sequential per the dispatch rules): SP3/SP9 (`:event/kind` →
`:rf.event/kind`), CFX1 (`::cofx/no-value` → `:rf.cofx/no-value`), and
the items audit-flagged as already shipped (CQ2/CQ-R2.3, IC1, the
test_support reset table, frame destroy hooks).
…actory (rf2-o7ayf)

Per the rf2-o7ayf audit (rf2-byut1 round-2 core review): high-leverage
helpers that underpin multiple public surfaces had only indirect
coverage. Higher-level integration tests caught downstream symptoms,
but the contract at the factory layer had no direct lock.

Two new test files:

emit_substrate_test.clj (9 tests)
  Covers `make-listener-registry` — the listener-registry factory
  backing both `re-frame.event-emit` and `re-frame.error-emit` (Spec
  009 §What IS available in production). Locks:
    - :register returns the id and the listener is reachable;
    - :unregister drops a single listener; siblings unaffected;
    - :clear empties every registration;
    - :fan-out invokes every listener with the record;
    - :fan-out is a no-op when the registry is empty (the hot-path
      short-circuit the factory documents);
    - listener exceptions are caught; cascade continues;
    - an externally-held :listeners atom IS the backing store (the
      hot-reload-survives contract — consumers `defonce` their atom);
    - re-register on the same id replaces.

core_artefact_test.clj (12 tests)
  Covers `defwrapper` — the optional-artefact factory backing ~ 30
  wrappers across core_<artefact>.cljc (flows / routing / schemas /
  machines / ssr / epoch / http). Locks each :on-absent policy
  branch:
    - :throw       — `late-bind/require-fn!` shape: :where, :reason,
                     :recovery :no-recovery, message = :error-keyword
                     printed as string;
    - :nil         — returns nil when absent, delegates when present;
    - :false       — returns false when absent;
    - :empty-vec   — returns [] when absent;
    - :empty-map   — returns {} when absent;
    - literal      — returns the literal value;
    - :ex-data sym — symbol values resolve in arity locals and ride
                     the throw's ex-data.

The fixture snapshots and restores `late-bind/hooks` around each test
so the contract is exercised in isolation from framework registrations.
@mike-thompson-day8 mike-thompson-day8 merged commit 30065b7 into main May 14, 2026
32 checks passed
@mike-thompson-day8 mike-thompson-day8 deleted the refactor/rf2-core-batch-polish-v2 branch May 14, 2026 04:36
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