---
id: 01-rate-limit-type-primitives
epic: security-headers-rate-limit-sbom
title: Rate-limit type primitives and manifest field
type: technical-story
status: done
feature: core-shared
depends-on: []
blocks:
  [
    02-rate-limit-implementations,
    03-no-undeclared-rate-limit-eslint-rule,
    04-with-rate-limit-wrapper-and-conformance,
  ]
created: 2026-05-20T00:00:00Z
updated: 2026-05-20T08:24:33.292Z
---

## Goal

Add the foundational TypeScript types for the rate-limit primitive — `IRateLimit`, `RateLimitBudget`, `RateLimitDecision`, and the `RateLimited` brand — to `core-shared`, and extend the feature manifest schema with `rateLimit?: RateLimitBudget[]` so every subsequent story has a stable, schema-valid type surface to build on.

## Why

Manifest-first ordering requires types before implementations and lint rules. The `RateLimited` brand must exist in `core-shared/conformance/brands.ts` before `assertFeatureConformance` can enforce it; `RateLimitBudget` must be a valid manifest field before any feature can declare rate-limit gates; `IRateLimit` must be exported before any implementation or wrapper can reference it. All three land together because they are mutually referential and individually incomplete.

## Done when

- `packages/core-shared/src/rate-limit/rate-limit.interface.ts` exports `IRateLimit`, `RateLimitBudget`, `RateLimitDecision`.
- `packages/core-shared/src/conformance/brands.ts` exports `RateLimited<F>` brand and `isRateLimited(fn): boolean` helper.
- `UseCaseManifest` in `packages/core-shared/src/conformance/define-feature.ts` gains `rateLimit?: RateLimitBudget[]` (absent defaults to `[]`).
- New types exported from the `core-shared` barrel.
- `pnpm typecheck && pnpm lint && pnpm test && pnpm conformance && pnpm fallow:audit && pnpm coverage:diff` all pass.

## In scope

- `IRateLimit` interface: `consume(budgetName, key, weight?): Promise<RateLimitDecision>` and `reset(budgetName, key): Promise<void>`.
- `RateLimitBudget` type: `{ name: string; window: string; budget: number }`.
- `RateLimitDecision` type: `{ allowed: boolean; remaining: number; resetAt: Date }`.
- `RateLimited<F>` brand in `conformance/brands.ts` following the `Captured`, `ConsentChecked` pattern.
- `isRateLimited(fn): boolean` brand-check helper.
- `rateLimit?: RateLimitBudget[]` field added to `UseCaseManifest` in `define-feature.ts`.
- Barrel export from `core-shared`.

## Out of scope

- Implementations (`NoopRateLimit`, `InMemoryRateLimit`, `RecordingRateLimit`) — Story 02.
- `withRateLimit` wrapper, `assertFeatureConformance` extension, `wireUseCase` extension — Story 04.
- ESLint rule — Story 03.
- Auth backfill — Story 05.

## Tasks

- [x] Add `IRateLimit`, `RateLimitBudget`, `RateLimitDecision` types in `packages/core-shared/src/rate-limit/rate-limit.interface.ts`; add `RateLimited<F>` brand + `isRateLimited` helper in `packages/core-shared/src/conformance/brands.ts`; extend `UseCaseManifest` in `packages/core-shared/src/conformance/define-feature.ts` with `rateLimit?: RateLimitBudget[]`; export new types from the `core-shared` barrel; all gates pass.
