Skip to content

Represent domain failures as Schema.TaggedError #34

Description

@FreshlyBrewedCode

Parent

#32

What to build

The daemon's domain failures become Schema.TaggedErrors instead of thrown Error subclasses
matched by instanceof. In scope: ConcurrencyLimitError, DispatchCapError, DedupeKeyError,
and RunCancelledSignal.

The behaviour that motivates it: server/scheduler.ts decides whether a missed cron window is
reported as skipped-concurrency or as fire-failed by instanceof-checking a caught unknown.
That is a semantic decision resting on an untyped catch — if a future error type is thrown from the
same path, it silently lands in the wrong bucket and a suppressed window looks like a failed one.
Tagged errors make the set exhaustive and the match checked.

Schema.TaggedError is already used twice in the codebase (SchedulerError,
AgentStepChunkError), so this finishes a pattern rather than introducing one. It is also what
makes the error channel usable once services move into context (#36).

RunCancelledSignal deserves care: it is the run's own unwind signal, not a workflow-observable
failure (ADR 0001 §4 / runtime/run.ts's header), and it is caught in exactly one place. Keep that
property — this ticket changes how it is represented, not who catches it.

Acceptance criteria

  • The four domain errors are Schema.TaggedErrors carrying their existing fields (DedupeKeyError keeps key and holderRunId)
  • The scheduler's skip-vs-fail branch matches on the tag rather than instanceof, and is exhaustive
  • RunCancelledSignal is still caught in exactly one place and still produces RunCancelled, not RunFailed
  • The HTTP layer's error-to-status mapping (409 for concurrency and dedupe collisions) is unchanged from a client's perspective
  • DispatchCollision events still record the key and the holding run id
  • bun run check passes

Blocked by

None (can start immediately).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    taskA single self-contained piece of work that ships as one PR

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions