Skip to content

Triage duplication: the kernel mapping nothing shouldn't mean the framework helps with nothing #69

Description

@btravers

From a DX review of the constraints this repo holds deliberately.

Thesis #3the kernel never maps an outcome to a transport — is correct and stays. What is worth separating from it is that declining a default mapping is not the same as declining a helper, and the two got decided together.

The cost is visible in the examples. DuplicateOrder is one domain error, and it is hand-triaged at least twice, in two files that will never see each other:

  • examples/order-api/src/slices/orders/controller.ts:40-46mapErrCaseserrors.CONFLICT({ … })
  • examples/order-temporal-worker/src/slices/fulfillment/activities.ts:63mapErrCaseserrors.OrderAlreadyPlaced({ … })

and @btravstack/amqp's own CLAUDE.md describes a third disposition for the same class of failure (ack / retry / dead-letter, split three ways between the library's dispatch and the handler).

That the destinations differ is the whole point and is genuinely good design — the same Err is a CONFLICT where a caller is waiting, a nonRetryable contract error where a workflow is, and a dead-letter where nobody is. The examples' own TSDoc argues this well.

What is not good design is that the exhaustiveness obligation is duplicated per transport with nothing tying the copies together. A new domain error is a compile error in each triage site independently — which sounds like a feature until you notice nothing tells you how many sites there are, or that you have covered them all. P._ is banned repo-wide precisely so every case is named; the repo has no equivalent guarantee that every transport has been considered for a given error.

Worth exploring: a helper that takes a domain error union and a per-transport mapping and yields the three triage functions, so the sites stay separate but the coverage is stated once; or, more modestly, a type-level check that a given error union is exhaustively handled across a named set of triage sites. Either keeps the kernel mapping nothing and keeps each transport's decision its own — it only stops the obligation from being invisible.

The lighter alternative, if a helper proves to be over-engineering: nothing in code, and a line in the root CLAUDE.md naming every triage site for a shared domain, so adding an error has a checklist.

Acceptance

  • A decision recorded in the root CLAUDE.md next to thesis fix: audit dropped Results, and document two runtime contracts #3, distinguishing "the kernel maps nothing" (unchanged) from "the framework offers nothing to help" (the part under review).
  • If a helper ships: each transport still decides its own destinations, and the kernel still maps nothing.
  • If it does not: the triage sites for a shared domain error are enumerated somewhere a contributor will find when adding one.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Should land before 1.0 — real DX cost, or a decision blocking other workdecisionNeeds a choice, not codeenhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions