| … | … | @@ -4316,23 +4316,30 @@ injected per layer: |
| 4316 | 4316 | core. For example, `core->verify` (replicator.cpp:732) reaches the replicator's `inOndata_` request |
| 4317 | 4317 | resolutions (replicator.cpp:145, 156) through `onappend` / `onupgrade`. The scope would drain those |
| 4318 | 4318 | microtasks before `_handleData`'s remaining steps; today, and in JS's single queue, they run after. R4c-4c-3's |
| 4319 | | scopes never hit this, because they wrapped pure storage calls. So E0 as written was NOT a no-op. The fix, as |
| 4320 | | migration scaffold deleted at R4i together with `Sync` (same lint): |
| 4321 | | - **rt:** a scope can be a FRONTIER scope. `rt::queueMicrotaskForeign(fn)` queues onto the queue that was |
| 4322 | | current when the OUTERMOST open frontier scope began: the root, or a non-frontier scope around it. With no |
| 4323 | | frontier open it is `queueMicrotask`. Storage-level `Sync` scopes nested inside a frontier are unaffected. |
| 4319 | scopes never hit this, because they wrapped pure storage calls. So E0 as written was NOT a no-op. A first fix |
| 4320 | (3cd545b: `queueMicrotaskForeign` at a fixed list of producer sites) was INCOMPLETE and is superseded here. |
| 4321 | Core calls foreign code synchronously through many exits: about 25 `core->on*` hooks into the replicator, |
| 4322 | `Session::emit` into user listeners, every API's CPS `done` (the caller's continuation), and option callbacks |
| 4323 | (`encodeBatch`, `preappend` / `postappend`, `onseq` / `onwait`, `ongc`, `onmessage`). Anything those queue, or |
| 4324 | any promise they resolve directly, would be captured. The fix, as migration scaffold deleted at R4i together |
| 4325 | with `Sync` (same lint), is a BOUNDARY MARKER: |
| 4326 | - **rt:** a scope can be a FRONTIER scope (`scopePush(frontier)`). `scaffold::Foreign` is an RAII frame. While |
| 4327 | it is the innermost frame, `queueMicrotask`, `complete` and `rejectedWithNoHandler` go to the context |
| 4328 | outside the OUTERMOST open frontier: the root, or a non-frontier scope around it. That is today's position. |
| 4329 | A core call that re-enters from foreign code opens its own scope on top, and is isolated again. With no |
| 4330 | frontier open, `Foreign` pushes nothing. `scopeCheckpoint` / `scopeDeliver` / `scopePop` throw while a |
| 4331 | `Foreign` frame is innermost; `handlerAdded` searches every level, as before. |
| 4324 | 4332 | - **scaffold:** `Frontier` is a `Sync` (same `wait`, same drain to quiescence) that pushes a frontier scope. |
| 4325 | 4333 | E0's frontier sites use `Frontier`; core's internal storage scopes stay `Sync`. |
| 4326 | | - **Foreign producers use `queueMicrotaskForeign`:** the replicator's two `inOndata_` deferrals, blobs' |
| 4327 | | callback deferrals (blobs.cpp:194, 253, 296, 321, 501), autobee-wakeup's `Promise.resolve(false)` |
| 4328 | | (autobee_wakeup.cpp:59), and protomux's deferrals (protomux.cpp:44, 136, 143, 147, 148, 153, 204). Their |
| 4329 | | microtasks keep today's position whether or not a core op is on the stack. core/streams.cpp:56 is core's |
| 4330 | | own, and stays. |
| 4331 | | - **Gate:** r4c_scaffold gains cases for this: a foreign microtask queued inside a frontier runs after it, in |
| 4332 | | FIFO with the root's; nested frontiers target the OUTERMOST frontier's parent; a `Sync` inside a frontier |
| 4333 | | captures as before. E0's gates (ctest, m4b / m4c / m4d / m3c / m5* / r3c) must be identical, which shows |
| 4334 | | the frontier is atomic and no foreign microtask moved. A drill: a producer back on `queueMicrotask` must go |
| 4335 | | red in a pipe gate. |
| 4334 | - **core:** foreign functions are wrapped WHERE THEY ENTER core, not at each call site (`scaffold::foreign(fn)` |
| 4335 | returns a function that runs `fn` under a `Foreign`): the `done` each frontier entry receives, the `on*` |
| 4336 | hooks where repl assigns them, listeners at registration, option callbacks when stored. |
| 4337 | - **Lint:** inside core, no `std::function` that came from outside core is invoked unwrapped. |
| 4338 | - **Gate:** r4c_scaffold gains cases for this: foreign work queued inside a frontier runs after it, in FIFO |
| 4339 | with the root's; re-entry from a `Foreign` frame is isolated; nested frontiers target the OUTERMOST |
| 4340 | frontier's parent; a `Sync` inside a frontier captures as before; checkpoint / deliver / pop under a |
| 4341 | `Foreign` frame throw. E0's gates (ctest, m4b / m4c / m4d / m3c / m5* / r3c) must be identical, which shows |
| 4342 | the frontier is atomic and no foreign work moved. A drill: removing any one wrapper must go red in a gate. |
| 4336 | 4343 | - **Rules carried from the hazards:** |
| 4337 | 4344 | - **Timer-resumed continuations open their own `Sync`.** `waitForRecovery`'s tail holds the state mutex, and |
| 4338 | 4345 | a timer callback is a frontier entry (D4). |