Skip to content

feat(metrics): project bounded rate-limit aggregates - #52

Draft
OnlineChef wants to merge 5 commits into
devfrom
feat/ratelimit-metrics-projection
Draft

feat(metrics): project bounded rate-limit aggregates#52
OnlineChef wants to merge 5 commits into
devfrom
feat/ratelimit-metrics-projection

Conversation

@OnlineChef

@OnlineChef OnlineChef commented Aug 2, 2026

Copy link
Copy Markdown

Scope

Projects the merged admission controller's aggregate-only snapshot into the existing metrics registry and both authenticated exports.

  • Optional JSON rateLimit subtree only while rate limiting is enabled.
  • Prometheus request-decision counters by fixed surface, source, and result labels.
  • WebSocket reservation counters by fixed reason plus current connection/tracked-principal gauges.
  • Principal-bucket and overflow-surface gauges without identity labels.
  • Read-only collection: rendering/scraping does not mutate limiter state or create buckets.
  • No principal, fingerprint, credential, Origin, remote address, provider/model/account/request/conversation, prompt, or error dimensions.
  • Default-off servers preserve the existing metrics JSON and Prometheus output.

The first commits contain the isolated projection/serialization module and focused tests. RuntimeMetrics collector registration and startServer wiring follow after the pure boundary passes typecheck.


View with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is enabled.

Greptile Summary

This change adds a read-only, bounded projection of aggregate rate-limit state for JSON and Prometheus metrics.

The projection correctly retains current supported surfaces, but adding a future rate-limit surface can silently remove its request decisions from both outputs unless the separate projection whitelist is updated. This affects src/observability/rate-limit-projection.ts.

Merge safety: do not merge until the projection surface list is tied to the authoritative rate-limit surface definition or made exhaustively checked.

Confidence Score: 4/5

T-Rex T-Rex Logs

What T-Rex did

  • T-Rex produced proofs for two posted P2 findings.
  • A focused rate-limit surface projection runtime repro source was captured as a runtime-proof artifact.
  • The model-discovery surface retention was logged in the projection output, showing JSON retention and Prometheus metrics.
  • The future-surface path was silently omitted by the projection in a simulated run, demonstrating the discard behavior.
  • Contract validation confirmed no repository changes and that only runtime-proof artifacts were created under trex-artifacts.

View all artifacts

T-Rex Ran code and verified through T-Rex

Comments Outside Diff (1)

  1. General comment

    P2 Projection whitelist can silently discard newly added rate-limit surfaces

    • Bug
      • RateLimitSurface is authoritative at src/ratelimit/token-bucket.ts:3-12, but the observability projection independently hard-codes its accepted surfaces at src/observability/rate-limit-projection.ts:34-44. isSurface at :59-60 only accepts values in that array, and normalizedRequests filters all other request rows at :71-73. Therefore, after a valid union member is added without also changing this projection list, its aggregate row vanishes from the JSON metrics DTO and is consequently absent from Prometheus output emitted at :139-145.
    • Cause
      • The runtime validation/sorting whitelist duplicates a closed TypeScript union, with no compile-time exhaustiveness check tying the two declarations together.
    • Fix
      • Derive the accepted surface set from one canonical runtime source, or define the projection list with an exhaustiveness constraint that fails typechecking when RateLimitSurface gains a member. Add a regression test covering exact union/list parity and projection of every supported surface.

    T-Rex Ran code and verified through T-Rex

Fix All in Cursor Fix All in Codex Fix All in Claude Code Fix All in Conductor

Prompt To Fix All With AI
### Issue 1
src/observability/rate-limit-projection.ts:34-44
**Projection whitelist silently drops new surfaces**

`SURFACE_ORDER` independently duplicates `RateLimitSurface`, and `isSurface` accepts only values in this local list. If a valid surface is added to the authoritative union without updating this array, `normalizedRequests` filters out its aggregate row, removing it from both the JSON metrics response and Prometheus export. Derive the accepted values from a shared runtime definition or make this list exhaustively checked against `RateLimitSurface`, with regression coverage for parity.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "fix(metrics): preserve bounded WebSocket..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3eb62275-8027-4f6c-8f6c-370cee2777d6

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added the enhancement New feature or request label Aug 2, 2026

Copy link
Copy Markdown
Author

[code]smith (@codesmith-bot) Implement the remaining P3 integration on existing branch feat/ratelimit-metrics-projection only. Do not create another branch or PR.

The pure boundary already exists in src/observability/rate-limit-projection.ts with focused tests. Reuse it exactly; do not create a second serializer or duplicate limiter counters.

  1. RuntimeMetrics optional collector in src/observability/metrics.ts:

    • import projectRateLimitMetrics, appendRateLimitPrometheus, and RateLimitMetricsSnapshot;
    • use a type-only import of RateLimitAggregateSnapshot from src/server/rate-limit.ts;
    • add optional rateLimit?: RateLimitMetricsSnapshot to MetricsSnapshot without changing version: 1;
    • add one private collector (() => Readonly<RateLimitAggregateSnapshot>) | null and public setRateLimitCollector(collector | null): void;
    • reset() must clear the collector for test/server isolation;
    • snapshot() calls the collector at most once, inside try/catch, projects a detached copy, and omits rateLimit when absent, disabled, or collector throws;
    • prometheus() calls appendRateLimitPrometheus(lines, snapshot.rateLimit) exactly once. Rendering must not invoke the collector a second time or mutate admission state.
  2. Server registration in src/server/index.ts immediately after createServerAdmissionControl:

    • runtimeMetrics.setRateLimitCollector(admission.enabled ? () => admission.snapshot() : null);
    • no per-route refresh and no file I/O;
    • default-off start explicitly clears a stale prior collector.
  3. Tests:

    • extend tests/metrics.test.ts for optional JSON subtree, exact Prometheus series, single collector invocation per snapshot/prometheus call, fail-closed collector exception, detached output, and reset() clearing the collector;
    • extend tests/server-metrics-endpoint.test.ts or add a focused server test proving default-off output has no rate-limit subtree/series, enabled authenticated traffic appears in both /api/metrics/json and /metrics, and two direct render calls do not change ServerAdmissionControl.snapshot() counters/gauges;
    • assert no principal/fingerprint/credential/Origin/address/provider/model/account/request/conversation/prompt/error fields.
  4. Update the metrics docs section to list the new bounded series and state that rate-limit metrics appear only while enabled and are process-local/read-only.

Run typecheck and focused projection/metrics/server tests before pushing one coherent commit. Keep PR draft.

@OnlineChef OnlineChef left a comment

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pure projection is typecheck-green; connect it to the existing registry without adding a parallel metrics state store.

Comment thread src/observability/rate-limit-projection.ts

Copy link
Copy Markdown
Author

greptile-apps Review current head 967ff54 only for the pure projection boundary. Reproduce and verify: disabled input returns null; all labels are fixed bounded enums; counters clamp non-finite/negative values; output is detached; JSON/Prometheus rendering is read-only; no principal/fingerprint/credential/Origin/address/provider/model/account/request/conversation/prompt/error dimensions can appear. Do not treat the still-pending RuntimeMetrics/startServer collector wiring as implemented. Report concrete defects only.

Comment thread src/observability/rate-limit-projection.ts Outdated
Register an optional aggregate-only admission collector on RuntimeMetrics:
snapshot() invokes it at most once inside a fail-closed try/catch and
projects a detached copy through the existing projection boundary, while
prometheus() appends the bounded series from that same snapshot without a
second collection. startServer registers the collector right after
createServerAdmissionControl when admission is enabled and explicitly
clears any stale collector on default-off starts. reset() drops the
collector for test/server isolation. Docs list the new bounded series and
their enabled-only, process-local, read-only semantics.

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
@blacksmith-sh

blacksmith-sh Bot commented Aug 2, 2026

Copy link
Copy Markdown

OnlineChef

[code]smith (@codesmith-bot) Implement the remaining P3 integration on existing branch feat/ratelimit-metrics-projection only. Do not create another branch or PR.

The pure boundary already exists in `src/observa...

P3 integration is complete on the existing branch, pushed as f1c2602 to PR #52 (kept draft): #52

  • RuntimeMetrics (src/observability/metrics.ts) now holds one private (() => Readonly<RateLimitAggregateSnapshot>) | null collector with setRateLimitCollector(); snapshot() invokes it at most once inside a fail-closed try/catch and projects a detached copy via the existing projectRateLimitMetrics, omitting rateLimit when absent/disabled/throwing (version: 1 unchanged); prometheus() appends via appendRateLimitPrometheus(lines, snapshot.rateLimit) exactly once from the already-taken snapshot, so rendering never re-invokes the collector; reset() clears the collector.
  • startServer (src/server/index.ts:273) registers admission.enabled ? () => admission.snapshot() : null immediately after createServerAdmissionControl, so default-off starts explicitly clear a stale collector; no per-route refresh, no file I/O.
  • Tests: 7 new unit tests in tests/metrics.test.ts (optional subtree, exact series, single invocation, fail-closed, detached output, reset, bounded-fields-only key audit) and 2 new server tests in tests/server-metrics-endpoint.test.ts (default-off has no series/subtree even after an enabled prior server, enabled authenticated traffic appears in both /api/metrics/json and /metrics, two direct renders produce identical rate-limit output proving read-only collection, plus identity-dimension regex checks). One fixture note: the default-off restart uses a fresh OPENCODEX_HOME because rewriting the config in place trips the OpenAI-tier migration backup collision; the stale collector lives on the in-process singleton so the assertion is unaffected.
  • Docs: the metrics section in docs-site/src/content/docs/reference/configuration.md now lists the bounded rate-limit series and states they appear only while rate limiting is enabled and are process-local and read-only.

Validation: bun run typecheck, bun run privacy:scan, and the focused projection/metrics/server-endpoint suites all pass (22/22). No second serializer was added; everything reuses rate-limit-projection.ts.

View with [code]smith

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
@cursor

cursor Bot commented Aug 2, 2026

Copy link
Copy Markdown

Pickup status (cloud agent): Implementation complete and CI green. Stale Greptile/Codesmith threads resolved (RATE_LIMIT_SURFACES canonical order + RuntimeMetrics wiring already landed).

Next step: Mark this PR Ready for review (still draft), then merge after #51/#53. Completes the metrics ↔ admission projection lane on top of #42+#45.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant