Warning: Effeck is v0. The language will change in major, breaking ways. It is not suitable for production use.

30. Risks and experiments

first, in the Go fork          G19  one checker pass: candidate forms (D56), component fixpoint (D52)
the largest external risk      G1   prompt capture uses undocumented Effect fields
the semantic gate              G16  one law suite for both runtime strategies (R9 first)
the checker's foundation       G8   second-class continuations and the finalizer rule

No design question in this list is open: every row states the rule that stands, what could go wrong in building it, and the experiment that checks it. D57-D60 close the former open calls (Chapter 29); D57 and D58 are marked controversial. Upstream filing follows D59.

Risks, in the order to work on them

#Rule that standsRiskExperimentWhat would change the rule
G19The call rule is decided by types (Chapter 13) in one checker pass: a lambda's form per overload candidate (D44, D56), E and R of a recursive component by a fixpoint inside it (D52)The hypothesis survives on the corpus and the probes (prototype/single-pass/RESULTS.md): one patched check reaches the prototype's lowering in 46 of 46 files with 0 disagreements, and each probe disagreement is a lambda with two self-consistent lowerings, which D56 decides, or mutual recursion. What remains is the iteration inside a recursive component, which the harness lacks, and holding the three forms in the Go checker, where the harness duplicated each lambda's textBuild both in the Go fork (typescript/ in this repository, D60), compile the corpus and prototype/single-pass/probes/, and compare every lowering decision with the single-pass harness's and every contract with the prototype'sA construct that needs a check outside its own component; its rule changes so that one pass decides it
G20The prototype covers the language's core (Chapter 27)It does not yet emit .d.ts files, $direct metadata, source maps, or hovers; implement EK4202 or external iteration of producers; or test this inside Effect methodsExtend the prototype in that order, then port its decisions to the Go forkA part whose rule cannot be implemented as written
G1Strategy A is the runtime (Chapter 25)An Effect release can break capture or abandonment without noticeRun the law suite against every Effect 4 patch release in CI. Prepare a supported primitive (an opaque same-fiber stack segment plus interruption state, or Effect.prompt) using the kernel as the reference; the proposal is drafted, not filed (D59)A release breaks a law with no workaround, or the maintainers reject any splice API; capture-heavy code then falls back to strategy B and loses transparency through TypeScript combinators
G16Strategy B is the reference semanticsThe two strategies disagree today (R9) and pass separate suitesWrite the Chapter 20 laws once against a small interface with an adapter per strategy; run both. First law: the reinstalled prompt records the resume site's ContextA law the two cannot both express, which would mean Chapter 20 is ambiguous
G8Continuations are second-class; a finalizer handles its own control operations (Chapter 9)The static checks are specified, not builtImplement both checks in a checker prototype; run them over the reference programs; count false positivesCorrect handlers, such as schedulers, that need escapes transfer cannot express
G9Callback types without contracts are effect-polymorphic (D12); inferred contracts are shown on hoverUnreadable inferred types defeat inferenceInfer the reference programs' contracts with the rules of Chapters 14 and 16; check multiple callbacks, returned callbacks, aliases, and declaration round tripsA callback that needs more than one row variable to read correctly
G10Plain JavaScript only where nothing observable changes (D10)An optimization that changes behavior breaks settled decision 4Compile a corpus twice, all frames and optimized; compare results, event order, and deterministic interruption tracesAny observable difference
G2The fiber-behavior table is the diagnostic; the runtime is the guarantee (P10)An unlisted combinator that forks costs a conservative errorExtend tests/fiber-behavior.test.ts to every Effect export that takes a program, and generate the checker's table from its resultsAn export whose fiber behavior depends on a run-time value the type cannot see
G3A continuation is consumed only on its capturing fiber (P5)Closing an owning Scope from another fiber while the capturer is alive raises ContinuationWrongFiber at the closer; the segment is released only when the capturer exits (K13c)A per-fiber pending-abandonment queue, drained when the capturing fiber next runs or exits; test producers shared across fibersA common, correct pattern that needs cross-fiber consumption
G12A producer is a Stream to TypeScript; the adapter runs it on its own fiber (D26)Stream cancellation might not reach the producer's ownerAdapt a producer to a pull Stream; pull from another fiber with Stream.merge; cancel early; check that the producer's finalizers ran once and that it never ran aheadStream cancellation that cannot reach the producer's fiber
G13wire reports missing, duplicate, and cyclic providers from Layer types (D27)Layer types might not carry enough to order a graphImplement wire over Layer types; test missing, ambiguous, cyclic, failing-acquisition, residual-requirement, and run-time-selected graphsLayer types that do not carry enough to order the graph
G11The ABI and diagnostics map through .effeck spans (Chapters 27, 28)The Go fork emits declarations, but its generated nodes carry no source positions and its language service is untestedIn the fork, lower displayName; check the declaration, a type error at the .effeck span, and hoverSpans that lowering cannot map back to the .effeck source
G18Workflow bodies are ordinary programs under replay (D42)A producer or handler inside a replayed body might keep state across executionsRun a workflow whose body iterates a producer and installs a handler, suspend it durably mid-iteration, replay it, and check that finalizers ran once per execution and nothing carried overState that survives into a replay
G5Effect's own wake-ups are unbounded (F10), and its generator frames skip finally (F1-F3)Effeck code waiting on Deferred chains inherits the overflow, and TypeScript users leak resourcesThe upstream index links minimal reproductions, expected behavior, and suggested fixes; every entry is drafted, not filed (D59)Upstream treats unbounded synchronous wake-ups as intended; Effeck then wraps Deferred and PubSub waits in suspend
G14Abandonment unwinds as an interruption (P8)Finalizers see a sentinel interrupt id; diagnostics cannot yet say "abandoned"Annotate the abort cause, or add a reason, and check what Cause.pretty and finalizers show
G15Typed failures do not cross JavaScript frames in v0 (D10, D9)A pure helper that throws a typed error compiles to frames, not plain JavaScriptBridge typed failures as branded exceptions caught at the nearest frame; measure cost and correctness
G17Capture copies the segment (Chapter 25)Capture at every level of a deep recursion copies quadratically (79 ms at depth 8,000)Follow the segmented-stack draft: prototype opaque chunked segments in a patched Effect build and rerun bench/deep-capture.tsReal producers nest deep enough for the quadratic term to dominate their own work

Closed

#QuestionResult
G4A handoff for producers that cannot act on a lost raceBuilt and tested (H1-H4, Chapter 21)
G6Spans and AsyncLocalStorage across prompt captureSpans correct (G6a, T01). AsyncLocalStorage is not delimited (G6b), hence the rule in Chapter 22
G7The cost of quadratic captureMeasured (Chapter 25); remaining work is G17
WHand-lowering the reference programs to Chapter 26's shapes and running them on the kernelDone by the prototype compiler, which lowers mechanically instead: its 46 example files, including the six reference programs (ref1 to ref6), compile and run on the kernel (prototype/esc)
PrototypeThirty findings from compiling the corpusSettled: D44-D53
Single passWhether the call rule needs more than one checker passNot for lowering: one patched check per file reaches the prototype's output in 46 of 46 files (817 call sites, 257 lambdas), in 46 checks instead of 124. The probes' 16 lowering disagreements settled D56; mutual recursion amended D52; the Go work stays G19 (prototype/single-pass/RESULTS.md)
Review, first draftFive kernel bugs from the conformance review (abandonment Exit, pending interruptions, abort leaking through a finalizer's capture, transfer revocation, registration leak)Fixed; the review's 54 tests run with the suite
Reviews, 2026-10-16Five defects in implementation and lowering: tail resume from a compiled clause (R10, Fable 1), a cleanup defect dropped by explicit abandon (R2b), a transfer outliving its fiber (R5), Effect.catch recovering a defect (R1), and masked acquisition blocking cancellation (R3, Fable 2)Fixed. Regression tests K11-K14 cover the kernel changes, and 12 of them fail on a copy of the kernel with the fixes reverted; K15 pins Effect's own acquisition behavior (experiments/KERNEL-CHANGES.md)
Reviews, 2026-10-16Rule gaps: catch with mixed causes, using ownership, resumeWith requirements, fork outside a region, provider sharing, control operations through TypeScript, function values in plain positions, trust for foreign codeDecided: D13, D14, D17, D19, D21, D20, D9, D5 with D22 and D23
Coverage auditSeventeen gaps found by mapping every Effect docs page (docs/research/effect-feature-coverage.md)Decided: D22-D28 and D37-D43; tooling D30-D36; partial annotations are settled by D57

Reference programs

Programs the compiler must handle end to end. The prototype runs a version of each (prototype/esc/examples/ref1 to ref6):

  1. Existing Effect service. Import a generic, overloaded, aliased TypeScript Effect function; compose it without changing E or R; provide a Layer from TypeScript.
  2. Provider graph. A shared database, two dependent services, a service with a default, test overrides, a failing acquisition, a missing provider, an ambiguous provider, and a cycle. Acquisition dependencies must not leak to callers.
  3. Resourceful retry. Acquire, fail, release, retry with fresh locals, then cancel during a later attempt, including an interruptible acquisition. Each acquisition is released exactly once.
  4. Callbacks and foreign code. A pure Array.map; a rejected callback that pauses; an effect-aware traversal; a trusted function with @throws; a callback API adapted with suspend under cancellation.
  5. Programs as data. Store, return, retry, and concurrently compose a program without running it early; read a composed Config; compare two Exit values.
  6. Handlers. Nested prompts, one resumption, a rejected double resumption, abandonment with finalization, a producer with early break over 100,000 elements in constant stack, a producer consumed as a Stream from another fiber, and a control operation rejected at a fork.