refactor(hub): tighten Result<T> typed payload — ADR-0174 SDK retirement Phase 1.2 (#176) (#221)

* refactor(hub): tighten Result<T> to typed-payload-per-kind discriminated union (#176)

Each Hub error variant now carries only its own typed payload. The generic
`errorKind` field is renamed to `kind`; `message`/`details` escape hatches
are removed from Hub-emitted errors. Factory functions (makeUnknownCommand,
makeInvalidArgs, makeHandlerRefusal, makeHandlerFailure) are exported and
used in phase-command-router.cjs. Callers switch on `result.kind`.

Part of ADR-0174 P1.2.

<!-- docs-exempt: no docs/ changes; API is internal to Hub callers -->

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(hub): act on P1.2 review findings (#176)

Addresses 4 review findings on PR #221:
- Hub now runtime-validates ok:false variants against the typed shape
  and coerces malformed returns to HandlerFailure with a contract-
  violation message (codex finding #1, code-review finding #1)
- catch path now preserves the original throwable for non-Error
  throws via an Error wrapper with .thrown attached (codex finding #2)
- All 4 factory returns are Object.freeze'd (review finding #9)
- makeHandlerFailure validates cause is Error; non-Error causes are
  wrapped with .thrown attached (review finding #10)

Tests added for each finding (TDD red → green).

Refs #176. Part of #174.

* fix(docs-lint): add docs-exempt markers to both P1.2 changeset fragments

Both `176-typed-result-discriminated-union.md` and `176-hub-p1.2-review-findings.md`
carry `type: Changed` which triggers the docs-required lint. Neither fragment had
a `<!-- docs-exempt: <reason> -->` marker, causing `docs-lint` to fail with
`FAIL_DOCS_MISSING`. Added the per-fragment exemption marker to both (the repo has
no `no-docs` label). This is a purely internal SDK refactor (ADR-0174 P1.2) with
no public docs surface.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-05-24 14:20:28 -04:00
committed by GitHub
parent 5b3646d6c8
commit d011a6fac2
5 changed files with 680 additions and 76 deletions

View File

@@ -0,0 +1,7 @@
---
type: Changed
pr: 176
---
`CommandRoutingHub` P1.2 review findings addressed: Hub now runtime-validates handler-returned `{ ok: false, ... }` results against the typed schema and coerces malformed variants to `HandlerFailure` with a contract-violation message (Finding 1). The catch path wraps non-Error throwables in an Error with `.thrown` attached so the original value is never silently dropped (Finding 2). All four factory functions (`makeUnknownCommand`, `makeInvalidArgs`, `makeHandlerRefusal`, `makeHandlerFailure`) now return `Object.freeze`'d objects to protect the variant invariant (Finding 3). `makeHandlerFailure` validates its `cause` argument and wraps non-Error causes in an Error with `.thrown` so downstream callers can safely access `.cause.stack` (Finding 4).
<!-- docs-exempt: internal refactor — Hub runtime-validation hardening is SDK-internal (ADR-0174 P1.2); no public docs surface affected -->

View File

@@ -0,0 +1,7 @@
---
type: Changed
pr: 176
---
`CommandRoutingHub` error results are now a typed discriminated union (ADR-0174 P1.2). The `errorKind` field is renamed to `kind` and each variant carries only its own typed payload: `UnknownCommand` → `{ kind, command }`; `InvalidArgs` → `{ kind, arg, reason }`; `HandlerRefusal` → `{ kind, reason }`; `HandlerFailure` → `{ kind, message, cause? }`. Factory functions `makeUnknownCommand`, `makeInvalidArgs`, `makeHandlerRefusal`, `makeHandlerFailure` are exported for handler and caller use. The generic `message`/`details` escape hatches are removed from Hub-emitted errors.
<!-- docs-exempt: internal refactor — Hub Result shape is SDK-internal (ADR-0174 P1.2); no public docs surface affected -->