I built three libraries independently. When I put them in the same project, the boundaries between them disappeared. This is what was left. The path: a click in a React form, through schema validation, into a Rust solver running in WebAssembly, back through a typed Result , and out to a rendered porkchop heatmap — without using try/catch for control flow anywhere. The libraries: lambert-izzo — Rust solver for Lambert's problem, exposed to JS via wasm-pack . Returns a typed LambertOutcome ; domain failures come back as values, not exceptions. @railway-ts/pipelines — Result<T, E> , Option<T> , schema, and composition. ~4.8 kB brotli, fully tree-shakable. @railway-ts/use-form — schema-first React forms. The schema is the single source of truth for types, validation, field paths, and error placement. They share an idiom by design: discriminated outcomes, no exceptions for control flow. The interesting question is what happens when you put them in the same project.…