| @@ -10,7 +10,6 @@ import { · 9 unmodified lines |
| 10 | Option, | 10 | Option, |
| 11 | Predicate, | 11 | Predicate, |
| 12 | Ref, | 12 | Ref, |
| 13 | Scheduler, | | |
| 14 | Schema, | 13 | Schema, |
| 15 | Semaphore, | 14 | Semaphore, |
| 16 | } from "effect"; | 15 | } from "effect"; |
| @@ -5817,28 +5816,23 @@ export const createExecutor = <const TPlugins extends readonly AnyPlugin[] = rea · 5800 unmodified lines |
| 5817 | // handler at construction), so an abandoned read cannot | 5816 | // handler at construction), so an abandoned read cannot |
| 5818 | // unhandled-reject; a fiber interrupted before it ever ran issues no | 5817 | // unhandled-reject; a fiber interrupted before it ever ran issues no |
| 5819 | // read at all. | 5818 | // read at all. |
| 5820 | // Launch order is STRUCTURAL, not scheduling-dependent. The dominant | 5819 | // Launch order is dominant-first by construction, best-effort under |
| 5821 | // tool-row read is forked FIRST with `startImmediately: true` under | 5820 | // the scheduler. The dominant tool-row read is forked FIRST with |
| 5822 | // `PreventSchedulerYield`: an immediate fork evaluates the child | 5821 | // `startImmediately: true`: an immediate fork evaluates the child |
| 5823 | // INLINE (`forkUnsafe` calls `child.evaluate` on the spot), and with | 5822 | // INLINE (`forkUnsafe` calls `child.evaluate` on the spot), so the |
| 5824 | // the yield-prevention ref inherited at fork the child's run loop | 5823 | // read is normally issued before the speculative forks below are |
| 5825 | // cannot insert a cooperative `yieldNow` mid-launch, so the child | 5824 | // even scheduled (a plain fork only queues its child on the |
| 5826 | // runs synchronously until its first genuine suspension — the | 5825 | // dispatcher for the next tick). The one exception is deliberate: if |
| 5827 | // driver-promise await, i.e. the read is ISSUED before the fork | 5826 | // the child's own operation budget (`MaxOpsBeforeYield`) expires |
| 5828 | // returns. The speculative reads are then forked plainly, which only | 5827 | // inside the launch window, the inline segment parks and a |
| 5829 | // schedules them on the fiber's dispatcher for the next tick. That | 5828 | // speculative read may launch first. That reversal is materially |
| 5830 | // makes dominant-before-speculative unconditional: without the | 5829 | // free, so it is NOT suppressed: on a synchronous driver the reads |
| 5831 | // guard, the fiber's operation budget (`MaxOpsBeforeYield`) can | 5830 | // serialize whichever order they start (same wall time), and on an |
| 5832 | // expire anywhere in this window, and the parked continuation queues | 5831 | // asynchronous driver every read suspends at its first await and |
| 5833 | // BEHIND already-scheduled children — plain-forking the dominant (or | 5832 | // they overlap regardless of order. Suppressing the yield (a |
| 5834 | // forking it immediately but without `PreventSchedulerYield`) lets | 5833 | // fiber-lifetime `PreventSchedulerYield`) is NOT an option here — |
| 5835 | // the speculative reads launch first whenever that boundary lands | 5834 | // the ref is inherited by everything the child runs and provably |
| 5836 | // here. The cost of the ref is only that this one bounded read (one | 5835 | // keeps effect timeouts from firing across CPU-bound stretches. |
| 5837 | // projected row) never cooperatively yields; the speculative | | |
| 5838 | // children are forked OUTSIDE the provide, so their scheduling is | | |
| 5839 | // untouched, and the dispatcher runs them whether or not this fiber | | |
| 5840 | // ever suspends, so a synchronous parent path delays them by one | | |
| 5841 | // tick but cannot starve them. | | |
| 5842 | const toolRowFiber = yield* Effect.forkChild( | 5836 | const toolRowFiber = yield* Effect.forkChild( |
| 5843 | core.findFirst("tool", { | 5837 | core.findFirst("tool", { |
| 5844 | where: (b: AnyCb) => | 5838 | where: (b: AnyCb) => |
| @@ -5851,7 +5845,7 @@ export const createExecutor = <const TPlugins extends readonly AnyPlugin[] = rea · 6 unmodified lines |
| 5851 | select: TOOL_INVOCATION_COLUMNS, | 5845 | select: TOOL_INVOCATION_COLUMNS, |
| 5852 | }), | 5846 | }), |
| 5853 | { startImmediately: true }, | 5847 | { startImmediately: true }, |
| 5854 | ).pipe(Effect.provideService(Scheduler.PreventSchedulerYield, true)); | 5848 | ); |
| 5855 | const policyRulesFiber = yield* Effect.forkChild(listActivePolicyRuleSet()); | 5849 | const policyRulesFiber = yield* Effect.forkChild(listActivePolicyRuleSet()); |
| 5856 | const connectionRowFiber = yield* Effect.forkChild( | 5850 | const connectionRowFiber = yield* Effect.forkChild( |
| 5857 | findConnectionRow({ | 5851 | findConnectionRow({ |
| @@ -5957,22 +5951,26 @@ export const createExecutor = <const TPlugins extends readonly AnyPlugin[] = rea · 99 unmodified lines |
| 5957 | // the two run concurrently. Both start only after | 5951 | // the two run concurrently. Both start only after |
| 5958 | // `enforceApproval` above completes — a declined call must never | 5952 | // `enforceApproval` above completes — a declined call must never |
| 5959 | // trigger the token refresh credential resolution can perform. | 5953 | // trigger the token refresh credential resolution can perform. |
| 5960 | // Credential resolution is the dominant work here and must launch | 5954 | // Credential resolution is the dominant work here and launches |
| 5961 | // first, so it uses the same structural launch-order shape as the | 5955 | // first: an immediate fork evaluates it inline to its first |
| 5962 | // pre-approval forks above: an immediate fork under | 5956 | // suspension before the plain integration-row fork is even |
| 5963 | // `PreventSchedulerYield` issues its first I/O inline before the | 5957 | // scheduled (best-effort — see the launch-order comment at the |
| 5964 | // plain integration-row fork is even scheduled, no matter where | 5958 | // pre-approval forks for why the rare budget-yield reversal is |
| 5965 | // the fiber's operation budget expires. The integration fork | 5959 | // accepted and why suppressing it is off the table: credential |
| 5966 | // is joined after `values`, so a credential resolution failure | 5960 | // resolution runs extension-owned provider code, and a |
| 5967 | // keeps dominating a storage failure exactly as it did when the | 5961 | // fiber-lifetime yield guard would disable the provider-call |
| 5968 | // reads were sequential (`Fiber.join` resumes with the credential | 5962 | // timeout across it and leak into the detached refresh fork). The |
| 5969 | // fiber's exact Exit); on that failure path the integration fork | 5963 | // integration fork is joined after `values`, so a credential |
| 5970 | // is interrupted rather than joined, so a hung integration read | 5964 | // resolution failure keeps dominating a storage failure exactly as |
| 5971 | // cannot gate the credential error and a failed one is deliberately | 5965 | // it did when the reads were sequential (`Fiber.join` resumes with |
| 5972 | // abandoned, never silently dropped as an unobserved value. | 5966 | // the credential fiber's exact Exit); on that failure path the |
| | 5967 | // integration fork is interrupted rather than joined, so a hung |
| | 5968 | // integration read cannot gate the credential error and a failed |
| | 5969 | // one is deliberately abandoned, never silently dropped as an |
| | 5970 | // unobserved value. |
| 5973 | const valuesFiber = yield* Effect.forkChild(resolveConnectionValues(connectionRow), { | 5971 | const valuesFiber = yield* Effect.forkChild(resolveConnectionValues(connectionRow), { |
| 5974 | startImmediately: true, | 5972 | startImmediately: true, |
| 5975 | }).pipe(Effect.provideService(Scheduler.PreventSchedulerYield, true)); | 5973 | }); |
| 5976 | const integrationRowFiber = yield* Effect.forkChild( | 5974 | const integrationRowFiber = yield* Effect.forkChild( |
| 5977 | findIntegrationRow(parsed.integration), | 5975 | findIntegrationRow(parsed.integration), |
| 5978 | ); | 5976 | ); |