Foundation Util
- Area: Foundation
- Path:
foundation/util - Kind: Shared primitives crate
Role in the stack
koder-foundation-util factors out primitives that were copied across ai/recsys, foundation/ads, and foundation/moderation during their independent evolution. One source of truth means bug fixes and performance improvements land once.
Primitives
RateLimiter— token-bucket per tenant.allow(tenant) -> bool+prune_idle(secs)+tenant_count().EventSink<E>— generic trait over the event typeE. Defaultimpls:
NoopSink(discards),InMemorySink<E>(bounded ring-buffer for tests/ops).Gate—is_blocked(scope, item) -> boolfor the moderation /brand-safety gate pattern. Default impls:
NoopGate,StaticGate(in-process set; production wires HTTP adapter tofoundation/moderation).
Consumers
| Crate | Uses |
|---|---|
ai/recsys |
RateLimiter, EventSink<RecsysEvent>, Gate |
foundation/ads |
RateLimiter, EventSink<AdsEvent>, Gate |
foundation/moderation |
RateLimiter, EventSink<ModerationEvent> |
Each consumer keeps its domain-specific event enum and exposes type aliases (e.g., RecsysEventSink = dyn EventSink<RecsysEvent>) so call-site readability stays unchanged.
Why a crate, not a module
A shared module across crates would require either workspace restructuring or git-subtree gymnastics. A real cargo dependency keeps the boundary explicit and lets each consumer pin a version independently when one needs to evolve faster than the others.
Test coverage
16 unit tests covering rate-limit refill semantics, sink ring-buffer overflow, gate scope isolation, and Arc-dyn shape verification.