Claims ledger¶
This ledger tracks verified behavioral claims in docs and README, with code references.
Policy documents under docs/reference/ are authoritative for policy statements.
| Claim-ID | Claim | Doc location | Code source | Status | Notes |
|---|---|---|---|---|---|
| CLM-001 | policy.ParseKey splits "namespace.name" into PolicyKey Namespace and Name; no dot yields empty Namespace. | docs/concepts/policy-keys.md#Parsing | policy/key.go:ParseKey | verified | - |
| CLM-002 | MissingPolicyMode behavior: FailureDeny returns NoPolicyError (errors.Is ErrNoPolicy); FailureAllow runs a single attempt; FailureFallback uses DefaultPolicyFor; default MissingPolicyMode is FailureDeny. | docs/concepts/policies.md#Missing policy behavior, docs/blog/why-recourse.md | retry/executor.go:resolvePolicyFast, retry/executor.go:NewExecutorFromOptions | verified | - |
| CLM-003 | EffectivePolicy.Normalize clamps values to safe bounds and records normalization metadata. | docs/concepts/policies.md#Effective policy, docs/blog/why-recourse.md | policy/schema.go:Normalize | verified | - |
| CLM-004 | NewDefaultExecutor registers built-in classifiers, sets default classifier AutoClassifier, registers budget "unlimited", and hedge triggers fixed_delay, p90, p95, p99; observer is Noop. | docs/getting-started.md#Standard usage (custom defaults) | retry/defaults.go, classify/builtins.go, budget/builtins.go | verified | - |
| CLM-005 | AutoClassifier uses HTTPClassifier when err implements HTTPError; otherwise AlwaysRetryOnError. | docs/concepts/classifiers.md#Built-ins, docs/blog/why-recourse.md | classify/auto.go | verified | - |
| CLM-006 | HTTPClassifier retries idempotent transport errors, 5xx, 408/429 (plus configured extra 4xx) and honors Retry-After for backoff override. | docs/concepts/classifiers.md#Built-ins, docs/blog/why-recourse.md | classify/http.go | verified | - |
| CLM-023 | Executor records Outcome on each attempt and uses it to decide retry, stop, or abort. | docs/concepts/classifiers.md#Classifiers, docs/blog/why-recourse.md, docs/design-overview.md | retry/executor.go:doValueWithTimeline | verified | - |
| CLM-007 | gRPC integration: DefaultKeyFunc maps /Service/Method to PolicyKey; UnaryClientInterceptor uses executor; Classifier maps gRPC codes and delegates non-gRPC errors; WithClassifier sets default classifier. | docs/concepts/integrations.md#gRPC integration, docs/concepts/classifiers.md#Built-ins, docs/blog/why-recourse.md | integrations/grpc/grpc.go | verified | - |
| CLM-008 | DoHTTP clones request per attempt, replays body via GetBody, wraps non-2xx and transport errors as StatusError (HTTPError), drains and closes failed responses (4096 bytes), and returns response, timeline, and error. | docs/concepts/integrations.md#HTTP integration, docs/blog/why-recourse.md | integrations/http/http.go | verified | - |
| CLM-009 | DoHTTP returns an error if req.Body is set and GetBody is nil. | docs/concepts/integrations.md#Constraints and safety | integrations/http/http.go | verified | - |
| CLM-010 | Budget Decision allows or denies attempts and may include a Release called once after an allowed attempt completes. | docs/concepts/budgets.md#Budgets & backpressure, docs/blog/why-recourse.md, docs/design-overview.md | budget/types.go, retry/budget.go:allowAttempt | verified | - |
| CLM-011 | UnlimitedBudget always allows; TokenBucketBudget is a token bucket with capacity and refill rate. | docs/concepts/budgets.md#Built-in budgets, docs/blog/why-recourse.md | budget/builtins.go | verified | - |
| CLM-012 | Missing budget handling: empty budget name allows with reason no_budget; nil registry, missing budget, or nil budget uses MissingBudgetMode (default FailureDeny) with reasons budget_registry_nil, budget_not_found, budget_nil. | docs/concepts/budgets.md#Missing budgets and failures, docs/blog/why-recourse.md | retry/budget.go, budget/reasons.go, retry/executor.go:NewExecutorFromOptions | verified | - |
| CLM-013 | RecordTimeline returns a capture; Timeline includes per-attempt records and FinalErr; executor stores the timeline after the call. | README.md#Debugging story, docs/index.md#Observability-first, docs/concepts/observability.md#Timeline, docs/incident-debugging.md#Capture a timeline, docs/blog/why-recourse.md, docs/design-overview.md | observe/timeline_capture.go, observe/types.go, retry/executor.go:doValueWithTimeline | verified | - |
| CLM-014 | Observer hooks OnStart, OnAttempt, OnHedgeSpawn, OnBudgetDecision, OnSuccess, OnFailure are defined and invoked. | docs/concepts/observability.md#Observer hooks, docs/index.md#Observability-first, README.md#Debugging story, docs/incident-debugging.md#Capture a timeline, docs/blog/why-recourse.md, docs/design-overview.md | observe/types.go, retry/executor.go:doValueWithTimeline, retry/group.go, retry/budget.go | verified | - |
| CLM-024 | AttemptInfo is stored in context and returned by AttemptFromContext. | docs/concepts/observability.md#Attempt metadata in context | observe/attempt_info.go | verified | - |
| CLM-025 | Executor resolves an EffectivePolicy via PolicyProvider for the provided PolicyKey and sets pol.Key to that key before execution. | docs/blog/why-recourse.md, docs/design-overview.md | retry/executor.go:resolvePolicyWithAttributes, retry/executor.go:resolvePolicyFast | verified | - |
| CLM-015 | Context cancellation is respected across attempts, backoff sleeps, and hedges. | docs/design-overview.md#The operational contract, docs/gotchas.md#Timeouts and cancellation | retry/executor.go, retry/executor.go:sleepWithContext, retry/group.go | verified | - |
| CLM-016 | Circuit breaker is consecutive-failure with closed/open/half-open; open fails fast with CircuitOpenError; half-open probe limit is one; hedging is disabled in half-open; reason codes include circuit_open and circuit_half_open_probe_limit. | docs/concepts/circuit-breaking.md#Behavior, docs/blog/why-recourse.md | circuit/breaker.go, circuit/registry.go, retry/executor.go:doValueWithTimeline, circuit/types.go | verified | - |
| CLM-017 | Hedging supports fixed delay and latency-aware triggers; winner success cancels other attempts; CancelOnFirstTerminal stops on non-retryable/abort; hedged attempts use Hedge.Budget; OnHedgeSpawn fires; AttemptRecord includes IsHedge and HedgeIndex; latency tracker uses ring buffer snapshots (p50/p90/p95/p99). | docs/concepts/hedging.md#Overview, docs/concepts/hedging.md#Behavior, docs/blog/why-recourse.md | retry/group.go, retry/executor.go:getTracker, hedge/tracker.go, hedge/fixed_delay.go, hedge/triggers.go | verified | - |
| CLM-018 | RemoteProvider caches policies with defaults (cacheTTL 1m, negativeCacheTTL 10s), uses Source.GetPolicy, caches missing, and normalizes before caching. | docs/concepts/remote-configuration.md, docs/blog/why-recourse.md | controlplane/remote.go | verified | - |
| CLM-019 | Policy defines bounds for attempts, backoff, and timeouts (executor uses policy fields for attempts and backoff). | docs/index.md#Concretely recourse gives you, docs/design-overview.md#The operational contract, README.md#What makes it different, docs/blog/why-recourse.md | retry/executor.go:doValueWithTimeline, policy/schema.go | verified | - |
| CLM-020 | Compatibility policy: SemVer for root module, stable packages list, separate integration modules, telemetry contract, internal/examples excluded. | docs/reference/compatibility.md, README.md#Compatibility policy | docs/reference/compatibility.md | verified | Policy doc is authoritative. |
| CLM-021 | Go version support is defined by each module's go.mod: root currently 1.23, with optional integration modules declaring isolated baselines. | docs/reference/compatibility.md#Go version support, README.md#Versioning | go.mod, integrations/grpc/go.mod, integrations/otel/go.mod | verified | - |