…swer into it (#3800) (#3881)
* fix(signals): a new async memo created over a hold lands its first answer into it (#3800)
A memo created while a transaction holds a value, whose first pass reads
that value and returns a promise, was a loading source the seam does not
hold (plan sec. 15.2), so its answer landed as mainline commit #0 and its
readers showed the held future beside the committed page. The same memo
with a synchronous first answer is born held (A29). The first pass now
records the transaction it was born into under the born-held arm's
conditions (a joined read, or a verdict lane's mount reading a staging),
and its first landing is staged into that transaction while it is live.
The hold never waits for the first load (the direction rule, #3820).
Maintainer clarification (2026-10-07): the #3869 ruling covers new memos
that don't read async; a new memo that reads the held world is held,
async first answer included.
Co-authored-by: Claude via Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
* chore(size): size exception for a new async memo's first landing into its hold (#3800)
Raises seventeen caps to CI brotli + 10 B with their recorded minified,
from Size run 37684843282 against next @ dafad1d — the frozen core,
simple-app, hydrating and live-page floors among them. Accepted by the
maintainer 2026-10-07 on the condition hello world stays under 10 KB
(CI: 9,914 B).
Co-authored-by: Claude via Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Claude via Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Adds the direction rule to the async SPEC as a dated amendment (2026-10-06): a hold never waits on work that has never committed. Docs and tests only; no source changes, so no changeset.
Why
A structural review of the post-L2 fixes found the concept they were missing: direction. L2 has one relation between transactions,
merge, which is symmetric, so "this work read that hold" means both wait for each other. That's right for committed work. It's wrong for work that has never committed (a node mounted during a hold, its first load): that work should wait for the hold, and the hold should not wait for it. Each create-time fix said this locally by checkingSTATUS_UNINITIALIZED. The amendment names the rule and points at those mechanisms; it adds none.A carve that made direction a transaction-level relation (a frame follows a hold) was built and measured on a scratch branch. It is not adopted:
_bornIn). §15.2's loading-source rule, all four parts of Loadingonshould behave as a keyed <Show> around the boundary; a boundary mounted under a hold must not be born held (A29) #3540, F13, [2.0] Mounting a memo during a held action can crash a render callback #3802/fix(signals): skip the run for a re-staging effect pass #3814 and F6's guard were each still needed.What the amendment says
#2937loading-source rule (plan §15.2), onnext;onshould behave as a keyed <Show> around the boundary; a boundary mounted under a hold must not be born held (A29) #3540, pending onfix/create-time-holds(91e474506,ca71e5d9d). They are linked, not claimed as onnext.Pins
packages/signals/tests/direction-rule-probe.test.ts:nextit.failsit.failsit.failsThe three
it.failsrows pass under the measured follow model, so they will flip loudly if a fix makes those shapes one-way. They also stay failing with #3800 and #3540 applied, which is consistent with the amendment.Also:
INTERNALS-ASYNC-STATE.md§0 and the carve plan's §15 open question 4.RULES-INDEX.mdregenerated;rules-index --checkis clean.Public API changes
None.