Skip to content

Changelog

Adds the Orchestration family — the 6th behavioral family — for internal coordination failures: the program’s own logic failed to complete an operation. Not retryable; no user-facing fix (report the bug).

  • Orchestration Family — 6th behavioral family. Severity 5, exit code 70 (EX_SOFTWARE), HTTP 500. Sits between Infrastructure (4) and Corruption (6) in the severity order.
  • NewOrchestration / WrapOrchestration / WrapOrchestrationf — family-specific constructors.
  • Bridge reference implementation (examples/cmd/bridge/ + examples/checkout/) — canonical classify->enrich->handle flow with 19 tests.
  • Corruption severity 5 -> 6 — bumped to preserve total order after inserting Orchestration at 5. Relative ordering of original families unchanged.
  • IsValid() boundary now spans six constants (Rejection..Orchestration).
  • Removed 52 phantom //nolint:hierarchical-errors directives across 13 files — linter was never installed.
  • examples/go.mod phantom replace directive — replaced bridge v0.0.0-... + local replace with real bridge v0.3.2. Same class of bug as the v0.6.0 hotfix.
  • go-error-family -> v0.10.0, diagnose -> v0.2.2, agent -> v0.2.2, bridge -> v0.3.2, diagnose/git -> v0.5.2, diagnose/postgres -> v0.5.2, examples -> v0.3.0

Structured-logging hook for HandleError* and an HTTP error-path fix. The root package remains zero-dependency.

  • HandleConfig.Logger *slog.Logger — optional structured-logging hook. When set, HandleErrorWithContext emits a single slog record (family, code, retryable, exit_code, context.* keys) alongside the CLI output, classifying once and logging once. Nil (default) preserves the original behavior.
  • errorfamilytest.AssertHTTPStatus(tb, err, want) — test assertion for HTTP status codes (checks HTTPStatuser override first, then family default).
  • writeHTTPError respects per-error HTTPStatuser overrides — fixes a bug where WithHTTPStatus overrides were silently dropped on the HTTP error path. Status is now computed once from the classified family, then checked for a per-error override.
  • LogError / LogErrorContext now emit exit_code — every structured log record includes the resolved BSD exit code.

BuildFlow-inspired error handling additions. All new APIs use only the Go standard library — the root package remains zero-dependency.

  • HTTPStatuser interface — sixth consumer interface. Errors implementing HTTPStatus() int override the family-based HTTP status per-error. Mirrors the ExitCoder pattern.
  • Error.WithHTTPStatus(status int) *Error — copy-on-write mutator (0 = use family default). Example: NewRejection("battle.not_found", "...").WithHTTPStatus(404) returns 404 instead of family default 400.
  • RegisterClassificationType[T error](family Family) — generic type-based classifier sugar. One-liner for the common “type T → Family F” case.
  • RegisterClassificationTypeFor[T error](r *Registry, family Family) — variant targeting a custom Registry.
  • ExitCoder interface — fifth consumer interface. Errors implementing ExitCode() int override the family-based exit code per-error.
  • Error.WithExitCode(code int) *Error — copy-on-write mutator (0 = use family default).
  • Error.WithContextAny(key string, value any) *Error — type-safe context attachment for non-string values.
  • WrapOnce / WrapOncef — idempotent wrap. Returns the existing *Error unchanged if the chain already contains one.
  • errorfamilytest.AssertExitCode and errorfamilytest.AssertHTTPStatus — test assertions for exit codes and HTTP status codes.
  • safeCauseString — panic-recovery guard around cause.Error().
  • Fuzz tests: FuzzWrapOnce, FuzzContextValueToString, FuzzWithExitCode, FuzzWithHTTPStatus, FuzzRegisterClassificationType.
  • Benchmarks: BenchmarkWithExitCode, BenchmarkExitCodeOverride, BenchmarkWithHTTPStatus, BenchmarkHTTPStatusOverride.
  • Examples: ExampleError_WithHTTPStatus, ExampleHTTPStatus, ExampleRegisterClassificationType.
  • Root module reverted from encoding/json/v2 to encoding/json — the GOEXPERIMENT=jsonv2 requirement (introduced in v0.7.0) has been removed. JSON output is byte-identical; only 2 call sites were affected.
  • HTTPStatus(err) checks HTTPStatuser first — a per-error override wins over the family default.
  • writeHTTPError no longer double-classifies — the Classify result is reused for both the response body and the status code.
  • ExitCode(err) checks ExitCoder first — a non-zero custom exit code wins over the family default.
  • Error.Error() / Summary() / formatVerbose() use safeCauseString for cause rendering.
  • Migrated root module to encoding/json/v2 — required GOEXPERIMENT=jsonv2 on Go 1.26. Reverted in v0.8.0.
  • Removed local replace directives and phantom require from published go.mod files. Root module is now genuinely zero-dependency.
  • Examples extracted to separate moduleexamples/ has its own go.mod (requires root + diagnose). This keeps the root module truly zero-dependency.
  • RegisterClassifier / RegisterClassifiers — predicate-based classification for dynamic third-party errors (*sqlite.Error). Stored lock-free behind atomic.Pointer[[]Classifier], copy-on-write.
  • Code(err) string — public code extraction wrapping errors.AsType[Coded].
  • TemplateForCode(code) — registry-then-builtin template lookup for HTTP/gRPC boundaries.
  • Wrap{Family}f variants — WrapRejectionf, WrapConflictf, WrapTransientf, WrapCorruptionf, WrapInfrastructuref. Nil-safe.
  • HTTPStatus(err) / HTTPHandler(fn) — net/http middleware writing safe JSON responses. Never leaks err.Error().
  • LogError(err, logger) / LogErrorContext — structured log/slog logging with family/code/retryable/context fields.
  • errorfamilytest subpackageAssertFamily, AssertCode, AssertRetryable, AssertContext, AssertContextMissing.
  • Classification pipeline now 6 steps — classifiers added as step 5.
  • Registry type with Clone() for inherit-and-extend, test isolation, and scoped error handling.
  • Family.Severity() — total order for multi-error classification.
  • Family.HTTPStatus() — canonical family to HTTP status mapping.
  • Family.RetryPolicy() — advisory retry defaults (Transient: 3 attempts, 100ms-5s).
  • Error.JSON() — canonical JSON view for API boundaries.
  • RegisterStdlibDefaults(reg) — pre-registered classifications for common stdlib errors.
  • Copy-on-write errorsWithContext/WithCause/WithTimestamp return a NEW *Error.
  • {key} template syntax — replaced {{.key}} to avoid collision with Go’s text/template.
  • Severity-ordered multi-error classification — worst family wins, deterministic regardless of argument order.
  • Lock-free sentinel lookupatomic.Pointer[sentinelMap], ~5x faster, zero allocations.
  • TextMarshaler/TextUnmarshaler for Family/Audience — enables YAML/JSON config integration.
  • ParseAudience / ParseStatus — case-insensitive string parsing for all enums.
  • Family.Audience() — User / Ops / All for presentation-layer decisions.
  • Integration tests.
  • HandleConfig.Diagnose bool removed — diagnostics run whenever DiagnosticFunc is set.
  • agent.Config.Enabled returns error — calling Analyze on a disabled agent is a programming error.
  • HandleErrorWithContext — context-propagating handler (canonical entry point).
  • HandleErrorDetailedWithConfig — configurable structured result.
  • CommandRunner interface — mock injection for testable diagnostic rules.
  • ContextKey typed strings — replaces raw strings in rule specs.
  • WithTimestamp — copy-on-write timestamp setter.
  • Modularized diagnostic rules — git moved to diagnose/git, postgres to diagnose/postgres.
  • Fuzz tests and benchmarks.
  • License changed to MIT.
  • README rewritten (removed fabricated API docs).
  • Initial release.
  • Family enum, interfaces, Error struct, constructors, Classify, HandleError, diagnostic rules, debug agent, templates.