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

Part V. Decisions

29. Decisions

settled before this document      1-7     the owner's original decisions
decisions since                  D1-D124 the owner's calls and reported build defaults; gaps reserved
rules of the runtime and compiler P1-P22  adopted (D29), revised where the 2026-10-16 reviews broke them
end-to-end build calls          D61-D124 recorded below where reported; unreported numbers stay unassigned

Every rule in this document traces to one of these. The log with full reasons is docs/design/DECISIONS.md; a default is a decision made to complete the design, and the owner can overturn any default.

Settled before this document

These come from the earlier conversation and are not reopened.

  1. Every function participates in one computation model. No effect function keyword and no effect(...) wrapper. Ordinary calls compose computations and expose successful results without a marker at each call. A way to construct, store, pass, retry, and concurrently compose programs as values is required (D7 spells it).
  2. Explicit contracts are written Effect<A, E, R> as a return annotation. The annotation describes the whole computation, and the return expression is checked against A. Most code infers. In the owner's words: "Success, errors, and requirements must each support inference or explicit declaration. We have not finalized the shorthand for partially annotating those channels. Preserve that requirement without inventing a premature spelling or silently confusing inference with never. Use the same contract model for function types, callbacks, service methods, and exported declarations."
  3. throw contributes to the owning computation's inferred E. An explicit E constrains what escapes. Effect<A, never, R> may handle expected failures internally but rejects escaping ones. Expected failures, defects, and interruption stay distinct.
  4. Optimization preserves computation semantics. E = never and R = never do not prove purity or synchronous completion. Constructing a cold program never executes its work.
  5. Dependency injection is core and is designed with the continuation semantics: identity, contracts, inferred and declared requirements, acquisition, composition, missing, ambiguous, and cyclic providers, acquisition failures, residual requirements, scoped sharing and release, test overrides, Context across suspension and children, and interoperability with Effect Context keys and Layers. No second DI container.
  6. New syntax must earn its place. Ordinary function syntax and the Effect<A, E, R> annotation reuse TypeScript syntax.
  7. Broad npm interoperability is not an MVP constraint. Interop with TypeScript code that already uses Effect is.

D57 supplies the partial-annotation spelling required by decision 2: explicit infer Name slots.

Decisions since

"Will" marks the owner's decisions; every other row is a default. Controversial marks a decision the owner is likely to revisit after using the language.

#DecisionReason and evidenceChapters
D1Services are abstract classes whose instance members are all abstract; nominal; keys derived and unique; no extends, new, instanceof, or generics; emitted as D45 saysUses no valid TypeScript meaning (TS2339, TS2348); structurally equal classes would alias (probe); rare in real code4
D2Control operations are abstract classes that extend the global ControlOne declaration form for services and operations; no keyword9
D3Errors use the global TaggedError (Will)Effect's Data.TaggedError; Schema.TaggedError for serialized errors3
D4The prelude: Effect, Schema, Layer, TaggedError, Control, and the built-ins; imports shadow itWhat 77-81%, 39-44%, and 34-44% of Effect files import1
D5Calls to non-Effect code need a declared trust level (Will)Foreign code may throw; platform APIs are replaced; clock reads go through services10
D6The standard library is Effect's (Will)Effect ships the modules and the platform implementations11
D7Program values are functions with no argumentsNo new syntax; () => already means "not yet"5, 13
D8No |> in v0; the pipe(program, …stages) built-in stays. Superseded by D154Calls run before a pipe sees them; Stage 2 since 2021; 1.1% and 2.6% of pipes keep two stages5
D9A function value where a plain function is expected passes its plain-JavaScript form, or EK4301Fable review, finding 313, 16
D10Plain JavaScript when a function performs no Effect operation and E is never; source order kept; pure recursion on the JavaScript stackCodex review R4; settled decision 4; the owner's add feedback15
D11Higher-order functions compile to frames in v0Fable review, finding 515, 16
D12A callback type without a contract accepts any contract; unchanged by D57Settled decision 2 forbids reading it as never16
D13catch handles a cause only when it holds no defect and no interruptionCodex review R1; K14a-K14c3, 17, 26
D14Only using acquisitions belong to the blockCodex review R86, 23, 26
D15A failure during cleanup is never droppedCodex review R2b; K12a-K12e17, 21
D16v0 exposes handle, resume, resumeWith, abandon; transfer stays in the standard libraryCodex review R5; K13 now bounds a transfer by its fiber, and G3 remains9, 21
D17resumeWith runs code whose R is neverCodex review R79, 20
D18A clause whose last step is resume compiles to the tail-resume shapeBoth reviews (R10, Fable 1); K11a-K11d20, 26
D19fork is block-ownedFable review, finding 97, 26
D20A TypeScript function whose R holds a control operation is EK4202 in v0Codex review R69, 16
D21Each Effect.provide builds its layers once; provide at main; ManagedRuntime for several entry pointsFable review, finding 6; conformance test D054
D22Effect's own packages are trusted, with the functions and values they returnD6; Option and Result are data in Effect 410
D23A trusted contract is the @effeck trusted JSDoc tag, with @throwsTypeScript syntax only; the compiler's metadata channel10, 27
D24A call runs only Effect itself; subtypes are data until called; new never runsConfig, Exit, keys, and errors extend Effect13
D25using adds no masking policyK15a-K15c6, 21
D26Producers: for...of by type; a producer is a Stream to TypeScript; the adapter runs it on its own fiber behind a zero-capacity handoffStream operators pull on other fibers; continuations are fiber-affine; a one-element buffer runs ahead (prototype finding 26)8, 26
D27wire is an intrinsic with a bounded contract (EK3201-EK3204)Layer types carry outputs and inputs4
D28A catch over several expected failures receives the firstK14a3, 17
D29P1-P22 are the spec's rules, as revised belowThe reviews' verified findings29
D30Installation: effeck (effeck) and effeck-runtime; effect 4.0.5 exactlyMirrors typescript@7 packaging28
D31Builds: effeck --watch; effeck-vite for ViteOne checker for CLI, editor, and bundler28
D32The editor: effeck --lsp --stdio; the effeck.effeck extensionThe fork's binary already serves LSP28
D33v0 editor features: hover, completions, quick fixes, four refactorsThe diagnostics with mechanical fixes28
D34Diagnostics: errors, except the policies EK2004 (a warning) and EK4403; compilerOptions.effeckSoundness errors cannot be lowered28
D35One owner per diagnostic: effeck for types and language, Oxlint for linttsgolint embeds TypeScript's checker28
D36Debugging through composed source maps; spans for logical stacksThe frame invariant keeps callers off the JavaScript stack28
D37catch never sees an unlisted exception; a dead catch is the warning EK2004Coverage audit X2; prototype finding 163, 10
D38Runners only where no fiber runs the code; EK1005 elsewhereCoverage audit X413
D39A function-or-Effect parameter: a function if plain, a program if it can pauseCoverage audit X913
D40Service statics: layer, make; static readonly default makes a Context.ReferenceCoverage audit X124
D41S.member(…) always adds S to R; service members win over the key's members; EK3006 for a static that shares a member's nameCoverage audit X13; prototype findings 3, 44, 13
D42Workflow bodies are ordinary programs: interrupted on durable suspension, rerun on replayCoverage audit X17; workflow/Workflow.ts:695-780, 1031-103623
D43Effect.callback is an explicit boundary; its resume takes an Effect, and .effeck passes an ExitCoverage audit X11; Effect.ts6, 10
D44"The expected type" is the declared, uninstantiated parameter type of the resolved overloadPrototype finding 1: the contextual type is inferred from the lambda itself13
D45A service compiles to an interface plus a Context.Key class, with an optional brandPrototype finding 19: Effect's class form breaks implements (TS2720)4, 27
D46finally lowers to Effect.onExit; throw to return yield* Effect.fail(e); E is the type of causes made only of expected failuresPrototype findings 11, 12, 1414, 17, 26
D47A block that declares using or calls fork is a Scope regionPrototype finding 1823, 26
D48Scope joins the prelude, as module and typeContracts name it constantly; Effect 4's type is Scope.Scope1
D49Arrays and records of programs convert where Effects are expectedPrototype finding 55, 13
D50Continuation<V, E, H>: resume returns the handle's result typePrototype finding 249
D51Plain calls at a module's top level are ordinary calls; @throws {T} names a classPrototype finding 2110
D52E and R of recursion by a fixpoint inside the component, never a whole-program pass (EK2102 for A); A widens; definite assignment on the sourcePrototype findings 7, 10, 13; the single-pass probe isEven/isOdd14, 26, 27
D53Diagnostic codes follow the prototypePrototype diagnostics28
D54Inside a plain-JavaScript function, try, catch, and finally are JavaScript's own; catch rethrows anything unexpectedD10 with D5: nothing in the function can pause15
D55A method implementing a plain-function member ([Equal.symbol], [Hash.symbol]) compiles to a plain JavaScript method, or EK4301The member's declared type is not an Effect15
D56A lambda's form (plain, Effect function, program) is decided against each overload candidate's declared parameter type, and the first candidate that accepts it wins; never by the lambda's own inferred type. D10 eligibility is computed on demandSingle-pass experiment: 0 disagreements in 46 files; 6 probe lambdas with two self-consistent lowerings13, 15, 27
D57Controversial. Partial annotations use infer Name per channel in a function return annotation with a body; omitted slots are EK2003. D12 standsTypeScript 7 parses infer; explicit slots distinguish inference from never2, 14, 16, 28
D58Controversial. Keep EffectScript, esc, .es, and @effectscript; superseded by D125Another compile-to-JavaScript language uses the name28
D59Draft upstream issues and proposals in docs/upstream/; status: drafted, not filedFiling speaks for the owner in a third-party project and needs his go-ahead24, 25, 30
D60Will. One private repository, effectscript on GitHub; the compiler lives in typescript/Spec and implementations change together; the imported TypeScript tree omits 349 MB of baselines27, 28

Decisions from the end-to-end build (2026-10-16)

The following rows record build defaults, not new language decisions. Lane U recorded D97-D99 from F7's compiler notes because its inbox report was absent. The decision log groups known gaps by area and distinguishes landing snapshots from later fixes. D114-D119 have no reported decisions.

#DecisionReason and evidenceChapters
D61Controversial. An EK diagnostic is a TypeScript diagnostic with source EK, on upstream's content-mapper pathOne diagnostic path for CLI and LSP28
D62The prelude is the runtime's exportsLazy imports preserve files that use no prelude names1, 27
D63A .effeck file imports ./x.effeck or ./x.ts by source name with no flag (no TS5097); specifiers become .js in JavaScript and .d.ts outputSource names for checking, output names for JavaScript10, 27, 28
D64A failing compiler case passes when its exact set of error codes matches (TypeScript codes count, warnings do not); a runnable case compares only its @@result line, so programs may logExact codes detect regressions while result markers allow logging10, 27, 28
D65A call from a .effeck file to a plain function runs inline as f$direct(a) everywhere, including a module's top level, because it computes a value and runs no programPlain computation runs no program13, 15
D66An overload candidate that asks for a plain function rejects an .effeck function value that can pause, as it rejects such a lambda (D56 extended to function values); a TypeScript function that returns an Effect passes as data; when every candidate rejects, EK4301 reports against the first candidate's formNamed values and lambdas need the same callback safety13, 16
D67Controversial. A function with a plain return annotation keeps that type and compiles to one plain function; only unannotated or Effect-contract functions get the $direct plus Effect.sync pair, whose TypeScript type is (…) => Effect<A, never, never> (chapter 15's one calling convention)Plain annotations support JavaScript protocols10, 14, 15
D68Controversial. D12 (a callback parameter without a contract accepts any contract) applies to declarations, methods, and function expressions that are not call arguments; the added type parameters are named E and R (then E2, R2) and appear in .d.ts outputMissing callback channels must not mean never16, 27
D69A program lambda lowers to Effect.gen(function* …), a converted function value to Effect.suspend(v), and an array or record of programs built at run time to $programsConversions must preserve cold execution5, 13, 27
D70Controversial. A return, break, or continue that leaves a finally block is a new error, EK2006; in JavaScript such a jump discards the failure in flight, and compiling finally to Effect cleanup cannot honor itEffect cleanup cannot honor jumps that discard failures17, 28
D71EK2102 also covers a catch variable or return type typed before its cycle's E and R are known; the fix is a written contractThe checker cannot revise cached recursive types14, 28
D72EK2102 applies only to functions that run Effects; a pure recursive function keeps TypeScript's TS7023, which a plain annotation fixes (consistent with D67)Pure recursion needs no Effect channel analysis14, 15
D73A call to a function with a complete written contract adds the contract's E and R, not what its body doesCallers rely on the public contract14
D74Methods are exempt from EK2003 for a plain annotation, because a method implementing a plain-function member is declared that way (D55)Plain protocol members need plain annotations14, 15
D75The tsc/cmd/tsc binary identifies as Effeck; there is no separate cmd/effeckOne upstream entry-point seam27, 28
D76Controversial. The editor serves .ts only when the built-in TypeScript extension is disabled, or with Cursor's useTsgoDisabling validation also hides Effeck diagnostics; amends D3228
D77Controversial. Hover shows a running call's success value and a plain helper's direct and TypeScript-facing signatures; .ts hover stays unchangedExplain both call semantics and helper ABI15, 28
D78Prelude names and service members complete in scope; local declarations shadow prelude namesDiscoverability without explicit imports1, 4, 28
D79Reuse TypeScript TextMate grammar; resolve effeck from setting, project, then PATH; require workspace trustKeep theme support and project compiler ownership28
D80The runtime checks Effect's version by importing effect's package metadata with a static JSON import attribute; works in Node, Bun, and bundlersJSON attributes work in Node, Bun, and bundlers27, 28
D81The runtime exports suspend, handoff, Resumer, and HandoffProtocolViolation for TypeScript callback adapters (D43)Resource adapters need cancellation and lost-race reporting6, 21
D82The extraction kept the prototype helpers' behavior and continuation parameter order; discrepancies with the spec are documented in packages/runtime/README.md, not fixed silentlyExtraction must preserve compiler compatibility26, 27
D83Setup writes absolute file: dependencies on the repository's packages into new projects instead of bun link; nothing registers globally and nothing is published, so a project keeps working only while the checkout stays where it isLocal setup needs no registration or publication28
D84-D89No decisions reported in the build inboxLeave these numbers unassigned
D90The member-call rule (D41) is structural: it applies to any Context key whose service type declares the member, which covers .effeck services, TypeScript Context.Service classes, and Effect's FileSystem and PathContext keys and Effeck services share call behavior4, 13
D91Controversial. A control-operation call lowers like a service call, yield* (yield* Approval).approve(x), as the prototype did (amending the original Chapter 13 lowering); handle provides an implementation that performs the kernel operationsPreserves the prototype implementation pending F79, 13
D92A method in a .effeck file becomes an Effect when its body runs or looks up an Effect, or when its expected type returns one; it stays a method whose body is return Effect.gen({ self: this }, function* () { … })Generators must retain the method receiver15, 27
D93Controversial. Service keys use package, module, and name; defaults require static readonly; EK2101 requires all three Effect channels; wire emits consumers firstStable service identity and bounded provider analysis4, 14
D94Effect acquisitions receive the block Scope; other initializers need Disposable, null, or undefined; Disposable results also run Symbol.disposeEffect acquisitions and ordinary Disposables have different ownership6
D95In an Effect function, for (using x of values) makes each iteration's body a Scope region; the value is taken first, and using or fork inside the body join that regionCleanup belongs to the iteration that owns it6, 7
D96Controversial. A fork belongs to the innermost block around it; an arrow function with an expression body has no block, so () => fork(p) is Effect.forkScoped and keeps Scope in RAn expression body has no owning block7
D97Controversial. Continuation H is the program's A, or never with onReturn; handle unions program and clause results. Recorded from the compiler notesTypeScript fixes H before checking onReturn; mixed early returns can narrow resume too far9
D98Producers return lazy Streams; direct loops use the consumer fiber, Stream operators use a separate fiber and a handoff with no buffer. Recorded from the compiler notesLazy interoperability, cleanup, and bounded stack without running ahead8, 26
D99EK4201 checks known fiber boundaries and control-requiring producer arguments; EK4202 checks foreign callees' declared control requirements. Recorded from the compiler notesDiagnose unreachable handlers; runtime enforces fiber ownership9, 16
D100Code no fiber runs is plain JavaScript for EK4401 too: a module's top level and the plain callbacks it passes to TypeScript functions (describe bodies, route handlers), the same places D38 allows runnersFramework callbacks run outside a fiber10, 13
D101Controversial. Only built-ins that parse outside text declare expected failures (JSON.parse with SyntaxError, decodeURI and decodeURIComponent with URIError); every other built-in's exceptions are defectsUnlisted built-in exceptions remain defects10, 26
D102Controversial. Original platform-import restriction; import half superseded by D108; globals and allowed web standards retainedPlatform work needs typed, replaceable Effect services10, 11
D103EK1001 covers any top-level call that would run a program, including service member calls and Effect-value calls, reported once at the outermost callOne outer call identifies attempted program execution13, 28
D104Compiled generators are named after their function, variable, or property (an object method { *name() {} }.name when the body refers to that name); tracing: "exported" spans exported functions, "all" every named lowered function plus methods through Effect.withSpan("Class.method"); anonymous lambdas get no spanNames and spans identify source failures19, 26, 28
D105Vite compiles a project through one shared effeck subprocess per source revision, with cached output; amends D31Whole-project checking keeps caller contracts consistent28
D106After an edit the plugin invalidates every loaded .effeck module and its transitive importers, because callers compile differently when a contract changesContract changes can change caller lowering28
D107Controversial. Sources must sit under Vite's root; the plugin overrides emit paths and source roots there so output lookup and source maps are predictableOne source root makes output lookup predictable28
D108EK4402 reports platform execution, including calls and property reads; imports and passing values are allowed. Supersedes the import half of D102Effect adapters must accept host function values10, 11, 28
D109An expected callback or program asks for the Effect form only when its type is effect's own Effect interface, or a type parameter constrained to it; subtypes such as Config are data (D24), so Config.orElse's fallback stays plainD24 keeps structured subtypes as data13, 16
D110The pipe look-ahead (D8) reads the first stage's callee signatures, or a function value's own signatures; it runs only when the first argument can be a program, and never checks the stage earlyReading signatures avoids circular inference5, 13
D111The D49 conversion covers any iterable (Set, a Map's values) through its iterated type; an iterable never converts as a record, matching Effect.all at run timeMatches Effect.all at run time5, 13
D112A callback whose expected return mixes plain and Effect (boolean | Effect<…>) is plain when D10 allows and an Effect function otherwise; the same holds wherever both forms fitD10 selects the eligible form without Effect work13, 16
D113A lambda with a contract that takes the plain form has type (…) => A; where only a plain function fits, inference from its annotation starts from APlain inference needs A rather than its Effect wrapper14, 16
D120Local runtime dependencies use setup's tarball; refresh all three packages with bun update; examples omit bun.lockAvoid a second Effect copy that prevents child interruption; amends D8327, 28
D121Controversial. Effect trust follows re-exports and returned values, including assertions from @effect/vitestTests need usable assertions; direct Vitest imports and local TypeScript retain boundary checks10, 16
D122Every runner checks all services it does not supply; it.effect supplies Scope and its layer servicesDiagnose missing services before execution4, 28
D123Declaration prelude imports use free aliases when names are already boundAvoid duplicate identifiers in declaration consumers27
D124Setup relinks effeck launchers pointing into another checkout or at missing filesKeep the launcher usable after workspace changes28
D125Controversial. The language is Effeck: binary effeck, files .effeck, codes EK, unscoped npm packages effeck, effeck-runtime, effeck-viteThe @effectscript npm scope belongs to another language28
D126error NotFound { id: string } declares a tagged error class with readonly fieldsFewer tokens for the most common declaration3
D127Controversial. Effect types are written Result!Error!Dependencies; an empty slot is never, and left-out dependencies are inferred on a function with a bodyFewer tokens than Effect<A, E, R> in every contract14
D128(Amended by D220, reverted by D223.) service and control declare abstract classes whose bodiless members are abstract; an implemented member is EK2103Fewer tokens than abstract class and abstract on every member4, 9
D129(Superseded by D221.) layer UsersLive: Users { setup; find(id) { ... } } is Layer.effect (or Layer.succeed without setup); setup after members is EK2104Fewer tokens than Layer.effect(S, () => { return { ... } })4
D130A block form provides a layer to statements that stay code of the enclosing function; its keyword is provide since D172Fewer tokens than Effect.provide(() => { ... }, AppLive), and return keeps its meaning4
D131catch (e: NotFound) handles only failures with that type's _tag; superseded by D216Fewer tokens than narrowing and rethrowing3
D132try { ... } handle Approval.approve(request) { resume(true) } handles a control's operations; the block and the clauses stay code of the enclosing functionFewer tokens than handle(() => ..., Approval, { approve(request, k) { return resume(k, true) } }), and return keeps its meaning9
D133schema User { id: string; role: "admin" | "member" } declares a Schema.Struct and the interface of its decoded typeFewer tokens than a struct and a type alias, and the two cannot drift apart11
D134Controversial. Members of interfaces and object types are readonly unless written mutableImmutable data is the common case and no longer repeats readonly10
D135A module that exports a parameterless main runs it with NodeRuntime.runMain, or the runtime's copy without @effect/platform-node, when the host starts the moduleNo run.effeck file or runner line per program; importing the module still runs nothing1
D146Every export of effect's root is in scope; JavaScript's own globals win, host globals do notImports from effect were 5.9% of the docs' tokens1, 27
D147Controversial. A call is passed by name where a parameter expects a program: fork(fetchReport())Thunks around single calls were 2.6% of the docs' tokens5, 13
D148Controversial. (Amended by D229-D232.) sync, try, and callback are boundary hatches whose first arguments are plain TypeScriptOne visible escape hatch replaces five Effect constructors and their lambda rules10, 28
D149try(…) parses as a call in .effeck; Effect's { try, catch } object is EK4404A try statement needs a block, so try ( is unambiguous10, 28
D150runPromise, runFork, runSync, runCallback are in the prelude, for TypeScript and hatch bodiesThe way back in; EK1005 still applies where a fiber runs10, 13
D151sleep, log, retry, timeout, all, forEach, race, and seven more Effect functions need no prefixThey were 329 of the 538 Effect. member uses in the docs1, 27
D152Controversial. A value of an Effect data type takes its module's data-first functions as methods: stream.filter(p).take(3) is Stream.take(Stream.filter(stream, p), 3); own members winRemoves the module prefix and nesting from data-type code; the emitted calls tree-shake as Effect's do5, 13
D153A data type's method exists only in a call; any other access is EK4501No function value exists to bind13, 28
D154Controversial. The Hack pipe operator in .effeck files: x |> f(%, a), topic %, left-associative, looser than every binary operator; supersedes D8Fewer tokens and no nesting for operator chains; any argument position5, 27
D155Controversial. A topic follows the by-name rule: where % stands for a program, the left side is passed by name; elsewhere it runs once, before the body; both in one pipe is EK1008fetchUser(id) |> retry(%, policy) must retry the call, as retry(fetchUser(id), policy) does5, 13
D156A pipe's body must use % (EK1006); % outside a pipe's body is EK1007; after an operand % is still the remainderThe proposal's early errors; % keeps its JavaScript meaning where it already has one5, 28
D166fork is a keyword: fork x is fork(x) and fork { ... } forks a blockConcurrency reads as one word, with no lambda
D167Controversial. await waits for a Fiber, a Deferred, or an array or object of them, failing fast; superseded by D225 and D226Fibers need a join, and await was free outside hatches
D168Superseded by D197. Controversial. select runs the first case to finish and interrupts the rest; ties go to the first written; default polls; break leaves itFirst-of-several events without raceAll plumbing
D169for concurrent(n) runs the body per item in its own fiber; continue ends an item; break and return are EK4605 and EK4606forEach with a concurrency option, as a loop
D170detach(program) and forkIn(scope, program) are fork's variantsLonger lifetimes without Effect's names
D171await's types accept one level of arrays and objects; D228 carries the rule to joinDeeper recursive types exceed TypeScript's limits
D172provide AppLive { ... } replaces with AppLive { ... }; with still compiles with the warning EK1009 and a quick fixEffeck keywords reuse Effect's own names, so provide reads as Effect.provide4
D173provide Key = value provides one service; providers separated by commas mix layers and services; provide(...) { } means the sameEffect.provideService without a layer, in the same block form4
D174In a provider, an effect module stands for its key of the same name: Clock for Clock.Clockprovide Clock = testClock and provide Scheduler = fifo swap runtime services4, 28
D175The analyzer reads an array of providers element by elementA layer that provides nothing would otherwise hide the others' services4
D176catch (cause: Cause) catches every reason, as Effect.catchCause; superseded by D217Effect's catchCause in a typed clause's shape17
D177throw cause with a Cause rethrows every reasonEffect.failCause without a new keyword17
D178finally (exit) binds the try statement's ExitEffect.onExit in finally's shape17
D179exit, interrupt, and yieldNow are bare functionsEffect's names; no bare yield7, 17
D180Controversial. uninterruptible, restore, and interruptible blocksEffect's names in a block that keeps jumps17
D186throw is also an expression: x ?? throw new NotFound({ id })TC39 throw expressions (stage 2); fails as the throw statement does3
D187do { } is an expression whose value is its last statement'sTC39 do expressions (stage 1); a racer or an arm gets several statements13
D188Controversial. A block after a call is its program: withSpan("load") { ... }, it.effect("name") { ... }; an Effect dual takes it in its program's placeTC39 block params (stage 1); removes () => { } around multi-statement programs13
D196Controversial. await.all, await.allSettled, await.race, await.any start programs by name and behave as the Promise methods; EK4608TC39 await operations and Await Dictionary; await.x reads as Promise.x
D197await.race [...] replaces select, which is EK4607case read as value comparison and "select" is not Effect's word
D206match (x) { when P: v; default: d; } is an expression; mixed and/or/not need parentheses (EK4705)TC39 pattern matching (stage 1); one expression per arm, do { } for more3
D207The supported pattern subset: literals, bindings, arrays, objects, matchers, extractors, and/or/not, guards, isThe proposal's core; regular expression, relational, and async forms deferred3
D208Controversial. Option, Exit, Result, and primitive classes compile to their own guardsExact binding types without a runtime protocol; a shadowing local is not consulted3
D209Controversial. A match without default over a finite union that misses a case is EK4701Match.exhaustive at compile time; other types throw the proposal's TypeError3
D210A binding inside or or not is EK4702Inline boolean lowering has nowhere to declare it3
D211Controversial. is binds only in an if or while && condition, for the then branch or body (EK4703)Nesting keeps narrowing; the proposal also scopes else and the rest of the block3
D212Regular expression and relational patterns and non-literal computed keys are EK4704Reported with a guard as the fix instead of misparsed3
D213Deviation. A matcher is a custom matcher, a primitive class (typeof), a class (instanceof), a predicate, or a value (SameValue)Built-in brand checks cannot be written in a runtime helper3
D214A match lowers to a returning block, a labeled block, or an immediately invoked arrow functionTypeScript narrows each arm and arms run Effects in every position3
D215customMatcher is exported, and every error class matches by instanceof and extracts itselfSame-tag classes stay distinct3
D216A catch clause no longer tests a failure's type; catch (e) and match (e) or e is T; typed clauses warn (EK2112)Catching by tag was too magical; pattern matching covers it3
D217A whole cause is recovered by matching on exit(…); catch (cause: Cause) warns (EK2113)One mechanism, pattern matching, for failures and exits17
D218A match on a caught failure must be exhaustive over E or rethrow with default: throw eA complete match needs no rethrow3
D219EK2112 and EK2113 quick fixes rewrite retired clauses when the result is exactMigration without guessing at types28
D220(Superseded by D223.) Controversial. service class Users { ... } and control class Approval { ... }: the word is a modifier, as declare is; the spelling without class warned (EK2120)Reads as a TypeScript class and keeps Effect's word; Will was on the fence4, 9
D221Controversial. A layer is Effect's own call, Layer.effect(Users) { setup; return { ... } } through block params, or Layer.succeed(Users, { ... }); layer X: Y { } warns (EK2121)No syntax of its own; Will expected D129 to be reworked4
D222A layer block's returned members are typed by the service; a mismatch is TS2769 at the call, and failures, requirements, and using setup flow into the layerContextual typing through Layer.effect4
D223service Users { ... } and control Approval { ... } are the spelling again; service class and control class warn (EK2120), and the quick fix removes classWill: "class is redundant and we don't use class in other stuff in the api"4, 9
D225join is a keyword: join f, join [a, b], join { a, b } join fibers (Fiber.join), failing fast; join( stays a call; EK4611, EK4612await on fibers confused readers about promises; Effect's own word is join
D226Controversial. A plain await in Effeck code is an error: EK4609 (fix: join), EK4610 (fix: d.await()), EK4601-EK4604; the await operations stayIn JavaScript await means a promise; keep that meaning
D227A Deferred waits with d.await()Method syntax (D152) already names Deferred.await
D228join's types reach one level of arrays and objects, as D171's didDeeper recursive types exceed TypeScript's limits
D229Controversial. A hatch's TypeScript is self-contained: it reads no binding of the .effeck file except error declarations (EK4405, with a quick fix)Will: TypeScript in a hatch uses no values or closures from outside; may change later10, 28
D230Inputs, the arguments after a hatch's function, fill its first parameters, before the signal or resume; Resume<A, E> annotates resumebind lowers it, and parameters line up with the arguments as written10
D231try's error mapper stays the second argument, and inputs follow itD148's try(f, mapper) keeps its meaning10
D232Only a hatch's first argument is TypeScript; inputs and the mapper are Effeck; the function decides sync or asyncInputs run before the hatch, as Effeck calls do10
D236catch is also an expression: x catch fallback is Effect.orElseSucceed and x catch (e) => … is Effect.catch; the left side runs inside the catch, and defects and interrupts pass throughZig's inline catch; one expression replaces a try statement whose blocks only return3
D237catch binds looser than ?? and || and tighter than ? :, assignment, and |>, associating to the left; a handler's body extends as an arrow function's doesa() catch b() catch c chains3
D238A catch expression's value is A | B and its E is what the fallback or handler lets escape; a handler's exhaustive match removes the failures; a left side that cannot fail is EK2004The statement's checks, applied to the expression3
D239A catch expression in a hatch body is EK2114A hatch body is plain TypeScript28
D240Every rule and feature of @effect/language-service 0.87.5 is answered: ruled out by syntax, covered by an EK code, Effect 3 only, or implemented as EK4801-EK4825, a quick fix, a refactor, a hover, or a completionWill: support every rule, preferring syntax over lint28
D241EK4801-EK4825 are lint: defaults of error, warning, or off; all but EK4813 adjustable in compilerOptions.effeck and by @effeck-diagnostics commentsThey mark style and likely bugs, not code without meaning28
D242Controversial. EK4801, EK4819, and EK4820 also report in .ts files outside node_modulesEffeck replaces the server that would run @effect/tsgo10, 28
D243EK4813 replaces TS2339 for an Effect 3 name of the Effect module and writes the Effect 4 name; .ts files get the quick fix on TS2339A type error with a known repair28
D244Controversial. Effeck warns where Effect's defaults are off: extendsNativeError, newPromise, unsafeEffectTypeAssertionFailures are error declarations, promises cannot be awaited, contracts check types28
D245Refactors are refactor.rewrite code actions: write or remove a contract, interface to schema, async to an Effeck function (with an error per await), calls to a pipe and back, and the two pipe stylesEffect's 15 refactors, for one function form28
D246A layer's hover lists what it provides, needs, and fails with; wire's hover its build order; Duration.Input strings, a brand's name, and @effeck-diagnostics codes completeEffect's hovers and completions that still apply28

Rules of the runtime and compiler

Proposed in the first draft as P1-P22 and adopted by D29. A row marked revised changed because a review verified a counterexample.

#RuleEvidenceChapters
P1The machine in Chapter 20 is the specification. Every feature is a rule over itChapter 18All
P2Runtime: Effect-native prompts (strategy A). Reference semantics: an explicit machine (strategy B), once G16 runs one law suite on both. Revised: the two disagree today on the Context a reinstalled prompt records (R9), so passing tests in both are not agreement148 kernel tests; 20 reference tests; T7a; review probe R925
P3Deep handlers, dynamic selection, clauses run outside their promptT9, clause-outside test20
P4Context is a snapshot across capture; the reinstalled prompt records the resume site's ContextT1, T13, T1522
P5Every consumption of a continuation (resume, transfer, abandon) happens on the capturing fiberT14, T14b, O04, O0621
P6A second resume is a defect at the caller; a root wait that loses a race reports itT2, T5a-T5c21
P7An owner frame abandons an unresumed continuation. transfer (standard library only) moves ownership to the Scope region around the handler, revokes an earlier transfer, and rejects ownership cycles and parallel Scopes. Revised: the capturing fiber's exit is a second owner, so a transfer never outlives its fiber (R5)T3, T4, T10, O01-O08, K13a-K13e21
P8Abandonment unwinds like interruption and never disturbs real pending interruptions; a masked handler that swallows it is re-raised. Revised: every cleanup failure is reported beside pending interruptions, on every abandoning path (R2b)kernel-edges, A01-A04, I03, I10, I11, K12a-K12e20, 23
P9Services always use in-place evidence. Control operations use prompt evidence, or in-place evidence when TypeScript supplies an implementation that always resumes; the checker treats them as fiber-bound either wayIn-place and override tests; T84, 9, 16
P10Control operations cannot cross fibers. Revised: the runtime is the guarantee (HandlerNotOnThisFiber); the fiber-behavior table is the diagnostic (EK4201), and TypeScript functions with a control operation in R are rejected (EK4202)T7b, T8, probes; review probe R69, 16
P11The frame invariant; source regions compile to Effect frames, never JavaScript try, in functions that compile to framesF1-F326
P12Revised as D10: plain JavaScript only with no Effect operation and E = never; pure recursion on the JavaScript stack; pure permits inlining onlyF9, T6a; review probe R415
P13The kernel bounds synchronous wake-up depthF10a, K10a, K10b24
P14A callback type without a contract is effect-polymorphic (D12); D57 leaves this rule intactSettled decision 216
P15Effect 4 onlyResearch §1010
P16Fork microsoft/TypeScript tsc/ at a published nightly; in-tree package; no shimsCompiler research27
P17A declaration without a body states its full contract; a bare return type there is an error, never neverSettled decision 214
P18Revised as D17: resumeWith may raise only the operation's declared E, and its R is neverSettled decision 3; review probe R79
P19A finalizer's control operations must be handled inside the finalizerI06, I1117, 23
P20Programs start only at runners; calls never create fibers; a module's top level cannot run a program (EK1001). Revised: runners are called only where no fiber runs the code (EK1005, D38)Fable review13, 23
P21for...of over a producer is internal iteration; pulling from outside uses transferT10, T168, 26
P22Revised as D18: a clause whose last action is resume, outside any region of the clause, compiles to return tailResume(k, v) and iterates in constant stack. The first draft's evidence, T17, covered only a flatMap-shaped clauseK11a-K11d; review probe R1020, 26

Former open questions

#QuestionNow
O1How are program values spelled?D7
O2Declaration syntax for services and control operations?D1, D2
O3Does v0 expose the handler API?D16
O4Does function* mean producer?D26
O5Which owner does fork use?D19
O6Is wire a compiler intrinsic?D27
O10Does deep pure recursion overflow like JavaScript?D10
O11What does a call to plain TypeScript mean?D5, D22, D23

Closed calls for the end-to-end build

Former itemDecisionResult
O7D57 (controversial)infer Name marks an inferred channel; all three return-annotation slots are required; D12 stands
O8D59Upstream issues and proposals are drafted in docs/upstream/, not filed
O9D58, superseded by D125 (controversial)Effeck: effeck, .effeck, EK codes, and unscoped npm packages
Remote and repository layoutD60The one repository is private at effectscript on GitHub, with the compiler in typescript/

No language or repository decision waits on the owner. D59's filing boundary remains: these drafts are ready to file, and none is filed without his go-ahead. The build lanes land locally; the orchestrator handles any push.