Skip to content

[2.0 / next] born-held asks the owner-context pass, the world asks the running passes — the two part under runWithOwner (fallback's b._fb) #4428

Closed

Description

@ryansolid

Summary

Two sites decide "which world does a pass created during another pass belong to", and they name different creators:

The two agree while the creating pass is the new node's owner. They part under runWithOwner to an ancestor. The shape in the core: fallback() (boundaries.ts) builds the boundary's fallback memo beside the output, runWithOwner(out._parent, () => computed(() => b._show(b))), while the output's own pass runs. The creation context is out._parent, so the born-held test reads the enclosing pass's flag — not the output's, the pass actually running. In the cases below that enclosing pass is running and read the future (JOINED) while the output read nothing held: b._fb is born held one level up the owner chain, where the output itself — the pass creating it — would not have made it so.

Which answer is right is a ruling, not a code fact (reader-seat design doc §7, F-transitive):

  • one-level, running creator (D-27's letter: "a node it creates during that pass"; F-mount reading A, 2026-10-29): the output read nothing held → b._fb publishes. Differs from today only in this shape (31 passes at 2k × 3 seeds; no suite shape).
  • transitive (A29 "a held pass's children are the hold's"; [2.0 rc.14 – rc.19 / next] A memo born in a newly opened <Match> that reads latest() throws a stale <Match> read and halts reactivity #4341 "its branch exists only in that world"): the output exists only in the enclosing hold → b._fb is born held. Agrees with today here; differs from today in 14 suite passes (optimistic-maparray-index-frame-f1 ×13, lazy-memo-rebuilt-reader-4142 ×1 — a mapArray row root, and a born-into render effect's child, under a pass that inherited the hold's world without reading it; today they publish).
  • today: one level up the owner chain, whichever pass is running — neither of the above.

Whichever reading is chosen, today's decider is wrong in the other shape: a one-level rule must ask the running pass, a transitive rule must not stop at one level.

Reproduction

async-gen seed 7 case #82 (packages/web/test/async-gen), also 3289 #374, 91501 #37 (and with the fallback reading a staging as well: 7 #138, 3289 #1647, 91501 #166):

const sc = fc.sample(scenarioArb(), { seed: 7, numRuns: 83 })[82];
await runScenario(sc);
[s0=2 m0=async(s0 !%4=1) m1=async(m0+latest(m0) !%4=3)]
<Loading><span>isPending(m0) isPending(s0)</span></Loading>
:: t s0=2 s0=3 s0=1 s0=3 t A(s0=0) s0=2 t t s0=3
scenario JSON
{"signals":[2],"memos":[{"async":true,"deps":[{"src":{"k":"s","i":0},"how":"plain"}],"poison":1},{"async":true,"deps":[{"src":{"k":"m","i":0},"how":"plain"},{"src":{"k":"m","i":0},"how":"latest"}],"poison":3}],"tree":{"t":"loading","child":{"t":"leaf","text":[{"how":"pending","src":{"k":"m","i":0}},{"how":"pending","src":{"k":"s","i":0}}],"attrs":[],"grouped":false}},"steps":[{"t":"task"},{"t":"write","s":0,"v":2},{"t":"write","s":0,"v":3},{"t":"write","s":0,"v":1},{"t":"write","s":0,"v":3},{"t":"task"},{"t":"action","s":0,"v":0},{"t":"write","s":0,"v":2},{"t":"task"},{"t":"task"},{"t":"write","s":0,"v":3}]}

Found by the S1 reader-seat differential (SEAT_SHADOW_REPORT): class B2 born held (old true, new false; world 0/0/0, old creator running JOINED ≠ running pass, rows ∅) — 10 / 9 / 8 instances at 2k cases × seeds 7 / 3289 / 91501 (plus 1 / 2 / 1 with the fallback also reading a staging); none in the signals, solid or web suites. No end-screen difference in any of them — the output's own publication is held whatever the fallback does — so the consequence is internal: whether the fallback's first value is staged or published.

Intended fix

The reader-seat rebuild S1 (#4395 → S1 PR) decides this from the seat stack — the running creator, one level or transitive per the ruling — and the creatorPass(context) path retires. Until the ruling and the swap land, the shadow carries this as a known class (shadowKnown, this issue) under the one-level reading.

Activity

  1. changed the title [-]signals: born-held decided by a non-running owner's stale JOINED flag (fallback's b._fb via runWithOwner)[/-] [+][2.0 / next] born-held decided by a non-running owner's stale JOINED flag (fallback's b._fb via runWithOwner)[/+] on Oct 29, 2026
  2. changed the title [-][2.0 / next] born-held decided by a non-running owner's stale JOINED flag (fallback's b._fb via runWithOwner)[/-] [+][2.0 / next] born-held asks the owner-context pass, the world asks the running passes — the two part under runWithOwner (fallback's b._fb)[/+] on Oct 29, 2026
  3. ryansolid commented on Oct 30, 2026

    @ryansolid
    MemberAuthor

    Fixed on next by #4464 (b773146); it ships in the next RC.


    Generated by Claude Code

  4. added a commit that references this issue on Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions