Skip to content

fix: bound metrics error labels#58

Merged
lan17 merged 2 commits into
mainfrom
agent/bounded-error-labels
Jul 17, 2026
Merged

fix: bound metrics error labels#58
lan17 merged 2 commits into
mainfrom
agent/bounded-error-labels

Conversation

@lan17

@lan17 lan17 commented Jul 17, 2026

Copy link
Copy Markdown
Owner

Summary

Bound DialCache error metrics to a backend-neutral failure-site taxonomy instead of forwarding arbitrary JavaScript exception names.

This keeps the existing error label and in_fallback dimension, while ensuring custom adapters, Prometheus, and the planned Datadog adapter receive the same finite values. Per the confirmed scope for this issue, useCase and keyType remain unchanged.

Closes #45.

Root cause

ErrorMetricLabels.error was an unconstrained string, and core emission paths populated it from Error.name. Application errors and Redis/client-specific error classes could therefore create a new backend series for every caller-defined name.

The adapter boundary was vendor-neutral after #56, but the event values crossing that boundary were not cardinality-safe.

Architecture and design

The core now exports a closed MetricErrorKind union:

Value Failure site
key_construction Cache-key selector or DialCacheKey construction
config_resolution Runtime config provider, layer configuration, or ramp resolution
cache_read Local-cache or Redis read
cache_write Local-cache or Redis write
serialization_load Redis payload deserialization
serialization_dump Redis value serialization
invalidation Invalidation watermark write
fallback Wrapped application function
unknown Reserved future safety bucket

Classification happens at the component that knows the operation. In particular, RedisCache distinguishes client reads/writes from serializer load/dump failures before preserving the existing fail-open control flow. Serializer errors are recorded once and do not also produce a generic write error.

Runtime config-provider failures now produce error="config_resolution" with layer="noop", because they happen before any cache layer is selected, while retaining the existing fail-open behavior and disabled(reason="config_error") event.

Raw thrown values remain available to the existing logger paths, but exception names, messages, cache IDs, arguments, and Redis keys never enter metric labels.

Public API and migration

  • Export MetricErrorKind from dialcache.
  • Narrow ErrorMetricLabels.error from string to MetricErrorKind.
  • Preserve Prometheus collector names, label names, buckets, and registry ownership.
  • Preserve the in_fallback label for existing cache-versus-application queries.
  • Change error label values from exception class names such as Error or TypeError to the failure-site values above.

Applications with alerts or dashboards matching exception-name values must migrate those queries. Custom adapter implementations continue to receive the same ErrorMetricLabels object shape, now with a bounded error value.

Test contract

The tests now lock:

  • every MetricErrorKind member, including reserved unknown, through both the packed public types and Prometheus export;
  • every current core emission site, including provider/local/remote configuration, local/remote reads and writes, serialization, invalidation, key construction, and application fallback;
  • both inFallback values;
  • all reachable fallback layers: noop, request_local, local, and remote;
  • one metric event per failure site without serializer/write double counting;
  • exclusion of dynamic error names, messages, tenant IDs, and Redis-key-shaped data.

Scope

This PR intentionally does not add limits, warnings, normalization, or policy changes for useCase or keyType. It also does not add a classifier hook or any backend dependency.

Validation

Validated with Node 22.22.0 unless noted:

  • corepack pnpm typecheck
  • corepack pnpm test: 146 tests passed; 97.73% statements and 91.26% branches; src/dialcache.ts has 100% statements, functions, and lines
  • corepack pnpm build: ESM, CJS, and declarations
  • corepack pnpm test:package: packed ESM/CJS/type consumers
  • Packed package consumer validation on Node 20.17.0
  • corepack pnpm test:integration: 46 Redis, Valkey, and cluster integration tests
  • corepack pnpm audit --prod --audit-level high: no known vulnerabilities
  • git diff --check

@lan17
lan17 marked this pull request as ready for review July 17, 2026 21:54
@lan17
lan17 merged commit acb94fb into main Jul 17, 2026
4 checks passed
@lan17
lan17 deleted the agent/bounded-error-labels branch July 17, 2026 22:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Define and enforce a bounded-cardinality metrics contract

1 participant