Repository navigation
fix: resource identity and coarse-claimed results off-box on every event copy; SSR non-finite numbers as JavaScript spells them (rf2-uc1n9, rf2-xg1vu, rf2-dzbyz) - #11826
Merged
Conversation
…2-dzbyz) canonical-number fell through to pr-str for a non-finite double, so the emitter wrote `##NaN` / `##Inf` / `##-Inf` in reader syntax where React's client render prints `NaN` / `Infinity` / `-Infinity`, and hydration saw a text mismatch. Both arms now print String(x): the JVM arm gains three non-finite arms beside the finite-double arm, and the CLJS arm prints with `str`, which is pr-str's form for every finite number. Changing the JVM arm alone would have made the two hosts disagree, in the emitter's text and in the install-ledger digest that shares the function.
… event copy (rf2-uc1n9)
Off box a resource's scope tokenizes and its params ride unless the owner
makes the coarse :sensitive? / :large? claim. The FX carriers took that rule;
the event-bearing copies did not. The [:rf.resource/ensure ...] request's own
payload, and a continuation reply's :resource/key and
:correlation :rf.reply/resource-key riding its :reply-to target, reached off
box raw on the trace's :rf.event/v and :event and the epoch record's
:trigger-event under :rf.egress/include-event-args?, on the record's
:effects args under :rf.egress/include-fx-args?, and on the always-on
:rf.observe/error record at the default posture.
The resources carrier projector now walks the event carriers beside the FX
carriers and gives a [:rf.resource/<op> {...}] request's :scope and :params
the rule its scoped key takes. The epoch tool-pair applies it to
:trigger-event and :effects args as to the tags they were captured from, and
project-event-slot applies it to the always-on records' :event. The on-box
trace keeps the raw identity.
…laim off box (rf2-xg1vu) Managed HTTP settles an attempt by dispatching [<internal-reply-id> <verification-payload> <result>], so under :rf.egress/include-event-args? a coarse owner's decoded response rode raw on that event's :rf.event/v and the record's :trigger-event, while the continuation reply carrying the same value tokenized. The carrier projector now gives the result a continuation reply's slot rule: :value tokenizes when the owner the payload's work id names (a mutation attempt's :mutation-id) redacts, and the :error envelope tokenizes unconditionally. The read and mutation twins are both covered; a plain owner's value rides.
mike-thompson-day8
force-pushed
the
worker/resources-ssr-egress-fix
branch
from
October 30, 2026 01:19
5124fd0 to
e62c746
Compare
…y arm (rf2-xg1vu)
mike-thompson-day8
marked this pull request as ready for review
October 30, 2026 01:58
mike-thompson-day8
added a commit
that referenced
this pull request
Oct 30, 2026
Merge: c0b027b at 2026-10-30T02:00:54Z. Completeness: Complete: resource request identities and coarse transport replies are projected across trace, Pair event and effect carriers; SSR non-finite numeric spellings now agree across hosts. The path-only transport follow-up is separately tracked in rf2-9yvig and will be inspected in merge chronology. Correctness: Correct: owner-frame classification, scope projection, raw on-box controls and canonical numeric parity are supported by focused regression cases, reported fault plants and passing CI. No new actionable defect found. Implementation quality: Good: reuses carrier projection and existing owner-frame hooks, with explicit internal-event recognition and one shared numeric conversion; no unnecessary public API. Findings: none. Source forward pointers: none.
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.
Three off-box and wire-correctness fixes.
rf2-uc1n9: a resource's identity takes its off-box rule on every event copy
Spec 016 §Resource registration spec: off box a resource's scope always tokenizes, and its params ride unless the owner makes the coarse
:sensitive?/:large?claim. The FX carriers already followed that rule. The event-bearing copies did not.Probe (JVM, a
:sensitive? trueresource and a plain one, each ensured with params and an identity-bearing scope, settled to a failing:reply-totarget, then projected withrf/project-egressat the default posture and under each include flag). At trunk the coarse owner's key params and every scope reached off box raw here:[:rf.resource/ensure …]request's:params/:scope, on the trace's:rf.event/vand the record's:trigger-event:rf.egress/include-event-args?:resource/keyand:correlation :rf.reply/resource-key(and its scopes), on:rf.event/v,:eventand:trigger-event:rf.egress/include-event-args?:effects[*].args(the:dispatchof the reply):rf.egress/include-fx-args?:rf.observe/errorrecord's:eventThe control was the reply's own
:params/:value, which the event chokepoint already tokenizes. It read tokenized throughout. The default epoch posture was already clean, because the event and fx args reduce to their ids there.Fix. One rule, applied by the projector that already carries it for the FX carriers:
re-frame.resources.trace-egress: the carrier projector (project-fx-args-egress→project-embedded-keys) walks the event carriers:rf.event/v/:eventbeside:rf.fx/args/:rf.event/fx. It also gives a[:rf.resource/<op> {…}]request's:scopeand:paramsthe rule its scoped key takes (project-request-identity, throughproject-trace-scoped-key). The event id's reserved namespace is the proof.re-frame.epoch.tool-pair: once an opt-in hands back:trigger-eventor:effects[*].args, each is projected exactly as the tag it was captured from (:rf.event/v/:rf.fx/args), so a record and its trace cannot disagree.re-frame.projection/project-event-slot: the always-on records':eventtakes the same projector after the registration pass. The trusted-local:rf.egress/include-sensitive?lifts it, as it lifts the tool-pair arm.:resources/project-fx-args-egressnow describes the event carriers and the three consumers.The on-box trace keeps the raw identity, and the new test pins that as its fixture. A plain owner's params still ride, and its scope now tokenizes on these copies too, which is the same rule.
rf2-xg1vu: a transport reply's result takes its owner's coarse claim
The same probe found one more copy. Managed HTTP settles an attempt by dispatching
[<internal-reply-id> <verification-payload> <result>], so underinclude-event-args?a coarse owner's decoded response rode raw on that event's:rf.event/vand on the record's:trigger-event. The continuation reply carrying the same value already tokenized.The carrier projector now gives the result a continuation reply's slot rule.
:valuetokenizes when the owner redacts: the owner is the resource the payload's work id names, or the mutation attempt's:mutation-id. The:errorenvelope tokenizes unconditionally, asreply-error-slotdoes everywhere in the family. Both the read twin and the mutation twin are covered, and a plain owner's value rides.rf2-dzbyz: NaN and the infinities render as JavaScript spells them
re-frame.ssr.hash/canonical-numberfell through topr-strfor a non-finite double, so[:span ##NaN]shipped<span>##NaN</span>where React printsNaN. The JVM arm gains three arms (NaN,Infinity,-Infinity).The CLJS arm prints with
str(String(n)), which agrees withpr-stron every finite number. Changing the JVM arm alone would have made the two hosts disagree, both in the emitter's text and in the install-ledger digest, which shares the function. The digest therefore reads a non-finite double asNaN/Infinityon both hosts.No spec sentence changes. 004B already says numbers become text by JS
ToString, and Spec 016's identity sentence is what now ships.Quality gates
Exit codes are the runner's own, captured to a file.
These ran on the final tree, rebased onto trunk at
1651a9cf1c.scripts/test-jvm-implementation.sh(attempt 2): exit 0, all 17 artefacts. Its printed gate root names this worktree. It coversclojure -M:testinimplementation/ssrandimplementation/resources. Attempt 1, run before the rf2-xg1vu fold, stopped at ssr-ring with exit 1. The cause was oneHttpTimeoutExceptioninring-draintime-error-test's concurrent-request test while other workers' builds loaded the machine. Attempt 2 passed ssr-ring with no change.npm run test:cljs(attempt 2): exit 0.re-frame.ssr-hash-test: exit 0.clj-kondoon the changed files: no new findings. The one warning, an unusedre-frame.interoprequire intool_pair.cljc, is also present at trunk.The final commit changes only a late-bind directory description string, so this PR's CI is its gate. CI is also the gate for the browser, prod-elision and bundle lanes.
Test delta. The baseline is trunk CI at the merge base
b037cf2b48(tests run 40979166051).The code under test is the same at the merge base and at the rebased base, because trunk moved by docs only. Every lane landed on its predicted count:
implementation/ssrimplementation/resourcesimplementation/core:node-testhash_check_cljs_test)Plants. Each was planted, run, restored, and the restore verified by the file's blob hash against the committed object.
pr-strrestored for non-finite doubles. Exit 1, with 6 failures (NaN,Infinity,-Infinityand the float infinity in text, plus the attribute and the digest). The finite-double control stayed green.:paramscontrol and the on-box fixture stayed green under every plant.:trace-event-argsand:trigger-event.:trace-event-args,:trigger-eventand:error-record.:trigger-eventraw under the opt-in: exit 1, red on:trigger-event.:effectsargs raw under the opt-in: exit 1, red on:effect-args.project-event-slotwithout the projector: exit 1, red on:error-record.The CLJS arm of
canonical-numberis covered by the newhash_check_cljs_testassertion throughnpm run test:cljs. No CLJS plant was run. The final-base gate is this PR's CI.