Skip to content

Fix verbose controller errors and brand type explosion#735

Draft
Copilot wants to merge 2 commits intomainfrom
copilot/refactor-error-handling-verbose-errors
Draft

Fix verbose controller errors and brand type explosion#735
Copilot wants to merge 2 commits intomainfrom
copilot/refactor-error-handling-verbose-errors

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 5, 2026

Controller handler errors were nearly useless: wrong error types triggered "overload" complaints (from Effect/Stream handler union alternatives), and all types were expanded — e.g. NonEmptyString255 showed as string & B.Brand<"NonEmptyString255"> & B.Brand<"NonEmptyString2k"> & B.Brand<"NonEmptyString64k"> & ... instead of the named alias.

Brand type aliases — drop Simplify

All brand types (NonEmptyString*Brand, StringIdBrand, UrlBrand, Min3String255Brand, Int*Brand, PositiveNumber*Brand, EmailBrand, PhoneNumberBrand) converted from interface extends Simplify<B.Brand<"X"> & Y> to plain intersection type aliases:

// before
export interface NonEmptyString255Brand extends Simplify<B.Brand<"NonEmptyString255"> & NonEmptyString2kBrand> {}

// after
export type NonEmptyString255Brand = B.Brand<"NonEmptyString255"> & NonEmptyString2kBrand

Simplify was merging the entire brand hierarchy into a single flattened mapped type, which TypeScript inlined in error output.

Controller handlers — generators only

HandlerWithInputEff and HandlerWithInputStream removed from the handler union. Only generator functions are accepted. This ensures TypeScript reports exactly one failure with the right information instead of cycling through three overload candidates.

For stream requests, the generator must now return a Stream.Stream value (previously any value was accepted and coerced at runtime):

// stream handler — must return Stream
*StreamTicks() {
  return Stream.fromIterable([1, 2, 3])
}

// error path — yield* Effect.fail still works (generator never returns)
*StreamFailEffect() {
  return yield* Effect.fail(new StreamBoom({ reason: "from-effect" }))
}

router3 R-inference updated to also capture the returned stream's R channel.

All existing test handlers (arrow functions / Effect.fnUntraced wrappers) converted to generator methods.

Copilot AI and others added 2 commits May 5, 2026 13:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants