Skip to content

Commit ef3e591

Browse files
committed
docs(rfc): propose shared platform errors
Summary: Define stable platform error identities for conditions with common semantics across domains. Keep error identity separate from retry classification, use platform errors directly rather than through domain aliases, and illustrate the distinction with ErrVersionMismatch and ErrNotFound. Test Plan: - make fmt - make lint - make check-tidy - make check-gazelle Revert Plan: Revert this commit. API Changes: N/A Monitoring and Alerts: N/A
1 parent 39d61fe commit ef3e591

2 files changed

Lines changed: 51 additions & 0 deletions

File tree

doc/rfc/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Design documents and technical proposals, grouped by scope. Shared/cross-cutting
88
- [Message Queue Contract](messagequeue-contract.md) - How queue payloads are defined (Protobuf, serialized as protobuf JSON), located by audience (external in `api/{domain}/messagequeue/`, internal in `{domain}/core/messagequeue/`), bound to topics (the `topics` proto option), and enforced by Bazel visibility
99
- [Consumer Gate](consumer-gate.md) - Stopping and starting individual queue controllers at runtime via consumer middleware: parked deliveries held in-flight with visibility extension, gate state as a separate extension with a file-based first implementation shared by tests and operators
1010
- [Change URIs](change-uri.md) - Identity of a code change: `scheme://{host[:port]}/{path}` per provider (GitHub PR, Phabricator Diff, git ref/commit) and canonical-form rules
11+
- [Shared Platform Errors](shared-platform-errors.md) - Cross-domain error identities with common classification only where recovery behavior is universal
1112

1213
## SubmitQueue
1314

doc/rfc/shared-platform-errors.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Shared Platform Errors
2+
3+
Define shared error identities for conditions that have the same meaning across domains. A shared identity enables consistent `errors.Is` checks and, where appropriate, a common platform classification. Sharing an error identity does not by itself make the error retryable.
4+
5+
## Problem
6+
7+
SubmitQueue and Stovepipe define duplicate sentinels for common conditions such as a missing resource and an optimistic version conflict. Callers must know which domain package produced the error, and platform code cannot apply a common policy without importing domain packages or adding domain-specific classifiers.
8+
9+
| Concern | Current | Proposed |
10+
|---|---|---|
11+
| Error identity | Each domain defines equivalent sentinels | `platform/errs` owns shared semantic sentinels |
12+
| Usage | Callers check domain aliases such as `storage.ErrVersionMismatch` | Callers use `platformerrs.ErrVersionMismatch` directly |
13+
| Retry policy | Classification is repeated in controllers or domain wiring | The platform classifies only errors whose recovery policy is universal |
14+
| Domain contracts | Storage and configuration contracts own both APIs and common error identities | Domain contracts remain domain-owned; only shared error identities move |
15+
16+
## Proposal
17+
18+
An error belongs in `platform/errs` when:
19+
20+
1. It has the same meaning across multiple domains.
21+
2. Callers benefit from one `errors.Is` identity.
22+
3. Its meaning is independent of a domain entity or extension API.
23+
4. Any default classification applied by the platform is valid for every use.
24+
25+
Domains use shared errors directly rather than re-exporting them through permanent aliases:
26+
27+
```go
28+
if errors.Is(err, platformerrs.ErrVersionMismatch) {
29+
// Handle workflow-specific convergence.
30+
}
31+
```
32+
33+
Implementations preserve context with wrapping:
34+
35+
```go
36+
return fmt.Errorf("update batch %s: %w", batch.ID, platformerrs.ErrVersionMismatch)
37+
```
38+
39+
A domain may define a more specific error that wraps a platform error when callers need both identities. Domain storage and configuration interfaces remain in their existing packages.
40+
41+
## Initial errors
42+
43+
| Error | Meaning | Default platform classification |
44+
|---|---|---|
45+
| `ErrVersionMismatch` | An optimistic conditional update lost a concurrent race | `InfraRetryable` |
46+
| `ErrNotFound` | A requested resource does not exist | None; remains non-retryable by default |
47+
48+
`ErrVersionMismatch` has a universal recovery policy: reload current state and retry or converge. `ErrNotFound` does not. Depending on the call site, absence may be an expected result, a user error, or an infrastructure invariant violation. Controllers may add a contextual classification only when they have information the shared error does not carry.
49+
50+
The generic classifier recognizes `ErrVersionMismatch` through the existing error-chain walk. This proposal does not change retry limits, backoff, DLQ policy, or delivery guarantees.

0 commit comments

Comments
 (0)