fate-bridge: run resolvers on one worker-level ManagedRuntime (F4 + F7)#24
Open
usirin wants to merge 6 commits into
Open
fate-bridge: run resolvers on one worker-level ManagedRuntime (F4 + F7)#24usirin wants to merge 6 commits into
usirin wants to merge 6 commits into
Conversation
…n, typecheck WIP Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…alias, test wiring Mechanical follow-ups to the ManagedRuntime bridge refactor: - FateContext<R> generic (default WorkerFateServices); runEffect<A,R> runs each resolver THROUGH ctx.runtime, providing Auth/LiveBus per effect. - WorkerRuntime type alias in layers.ts; used in route.ts/app.ts/bridge tests. - effect.ts/test/bridge-* doc headers rewritten to the runtime-through model. - app.test.ts mirrors prod wiring (ManagedRuntime.make + Layer.effectContext). - effect.test.ts: LiveEntities key term->Definition, span typed Tracer.Span. - genEffect keeps its single irreducible F7 assertion (documented). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The marker-runtime isolation tests need a FateContext<R> the production-typed bridge can run cast-free: - genEffect<A,R> asserts the erased env to the caller's R (the single F7 cast), so runEffect<A,R> runs each resolver on ctx.runtime: ManagedRuntime<R>. - SourceExecutor<R> + fateSource<Item, R = WorkerFateServices> parameterize the executor's ctx; production sources.ts keep the default (slot into the registry unchanged), the three fateSource isolation tests name Marker. - effect.test.ts source tests call fateSource<..., Marker> so a marker ctx is accepted (fate's executor Context is invariant via SourcePlan). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e type) + format Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…, Cause Option) #1 Type resolver/source generator bodies with Effect.gen.Return<A, never, R> (pins only the env slot R) so Effect.gen infers R structurally — deletes the `Effect.gen(body) as Effect.Effect<A, unknown, R>` cast in genEffect and the per-wrapper R generic moves outward (default FateEnv / WorkerFateServices). #2 Pass {signal: ctx.request.signal} to runPromiseExit so a disconnected fate client interrupts the resolver fiber (matches HttpEffect run-with-signal). #5 Replace Cause.findError + `_tag === "Success"` with Cause.findErrorOption + Option.match (no Result tag leaks into boundary code). Rewrite the stale .patterns/fate-effect-bridge.md to the shipped ManagedRuntime model. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Idiomatic review (#2,#5) landed; #1 (removing the genEffect cast via Effect.gen.Return) reverted — pinning R in the generator yield is contravariant and cascades into fate's QueryDefinition<FateContext<WorkerFateServices>> server constraint, so the single contained boundary cast stays. runEffect now wires {signal: ctx.request.signal} (client-abort interrupts the resolver fiber, matching HttpEffect) and unwinds the Cause via Cause.findErrorOption + Option.match. .patterns/fate-effect-bridge.md updated to match. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Refactors the fate↔Effect bridge so every resolver runs on one worker-level
ManagedRuntime(built once per isolate) instead of the old per-resolverEffect.runPromiseExit(Effect.provide(effect, capturedContext))on the empty default runtime.Why
The old bridge ran each resolver on a fresh root fiber on the default runtime, re-providing a captured services-only
Context. That discards the runtime's tracer/scheduler/FiberRefs — so the ~59Effect.fnspans were detached roots (F4). This runs resolvers through the worker runtime, so spans nest and the runtime's context is real.What changed
FateContextcarries{ runtime, request, auth, liveBus }(a capturedContextno longer). Generic inR(defaultWorkerFateServices) so tests can drive a tiny marker runtime.runEffect→ctx.runtime.runPromiseExit(effect.pipe(provide Auth, provide LiveBus)). Per-requestAuth/LiveBusare values provided onto each resolver effect, not baked into the runtime.genEffect/runEffectgeneric inR; the singleassurvives as the irreducible F7 assertion (fate'sGenerator<any>resolver bodies makeRunrecoverable) — kept + documented, no other casts.ManagedRuntimebuilt once inindex.tsinit;makeAppLive/route.tsthread it by reference (never per request).Proof
Effect.withSpanparents to the runtime's request span; the old empty-runtime path is a detached root.pnpm typecheckgreen, biome clean, zero newas/as anyin source.FateContext, stale-doc sweep,app.test.tswiring,LiveEntitieskey, span typing).This PR's preview deploy + integration suite are the live end-to-end gate (real
POST /fatequeries/mutations through the new bridge).🤖 Generated with Claude Code