refactor(core): round-2 polish cluster — 4 follow-on beads (rf2-byut1)#1009
Merged
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Round-9 batched-by-surface dispatch against
implementation/core. FourP2 follow-on beads from the rf2-byut1 round-2 audit, one commit per
bead in one PR.
Commits
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-fnas applied to each metadata-map. The impl called it as(pred-fn id meta)— non-portable. Pre-alpha: switch to the spec'dshape, 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 legitimateevents for kinds like
:framewhose slot replacement need not rotate:handler-fn. Emit unconditionally; keep:different-fn?in:tagsso tooling can branch idempotent reloads.
rf2-4ymm0 — P2 polish bundle. Selected items from the 23-item
bundle, scoped to
implementation/coreto avoid spec hot-zone risk(spec/Conventions.md, spec/Spec-Schemas.md, spec/001-Registration.md
are sequential per the dispatch rules):
with-framerejects vector bindings of wrong arity(correctness; prevents silent fall-through to Shape 1 with vector
*current-frame*value)police-effect-map-shape!short-circuits on well-shapedmaps via
every? #{:db :fx}pre-checkbuild-nameJVM/CLJS twins into one CLJC defn(bodies were identical)
runs-on-platform?helper across fx/cofx:db/:eventstandard-cofx docstringsSkipped (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-registryandcore_artefact/defwrapperabsent-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-absentpolicy(
:throw/:nil/:false/:empty-vec/:empty-map/literal),
:ex-datasymbol 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:testfromimplementation/core— 477 tests, 2461assertions, all passing (was 456 before; +21 new tests)
npm run test:cljs— 1817 tests, 5105 assertions, all passingnpm run test:elision— every sentinel PRESENT