T3.5: Tier E per-session token bucket
This commit is contained in:
@@ -1322,8 +1322,8 @@ Statuses (in order of progression):
|
||||
| T3.1 | Approved | Kimi Code CLI | 2026-05-11T20:55Z | 2026-05-11T21:05Z | [report](reports/T3.1-report.md) | Approved. DashMap<String, Arc<RwLock<Room>>>; W13 resolved. One commit per task this time — good. Two minor process notes in report. |
|
||||
| T3.2 | Approved | Kimi Code CLI | 2026-05-11T21:15Z | 2026-05-11T21:25Z | [report](reports/T3.2-report.md) | Approved. timestamp_ms monotonic across rekey, documented + tested. Commit `1b4f7b0`. |
|
||||
| T3.3 | Approved | Kimi Code CLI | 2026-05-11T16:29Z | 2026-05-12T06:08Z | [report](reports/T3.3-report.md) | Approved. W12 SignalMessage versioning. Commit `f7f413e`. |
|
||||
| T3.4 | Pending Review | Kimi Code CLI | 2026-05-11T16:29Z | 2026-05-11T16:29Z | [report](reports/T3.4-report.md) | — |
|
||||
| T3.5 | Open | — | — | — | — | — |
|
||||
| T3.4 | Approved | Kimi Code CLI | 2026-05-11T16:29Z | 2026-05-12T06:24Z | [report](reports/T3.4-report.md) | Approved. Tier D payload-size EWMA + per-codec bound table. Commit `017c371`. Clean process. |
|
||||
| T3.5 | In Progress | Kimi Code CLI | 2026-05-11T16:29Z | — | — | — |
|
||||
| T4.1 | Open | — | — | — | — | Skeleton — expand before claiming |
|
||||
| T4.2 | Open | — | — | — | — | Skeleton — expand before claiming |
|
||||
| T4.3 | Open | — | — | — | — | Skeleton — expand before claiming |
|
||||
|
||||
95
docs/PRD/reports/T3.5-report.md
Normal file
95
docs/PRD/reports/T3.5-report.md
Normal file
@@ -0,0 +1,95 @@
|
||||
# T3.5 — Tier E (per-fingerprint token bucket)
|
||||
|
||||
**Status:** Pending Review
|
||||
**Agent:** Kimi Code CLI
|
||||
**Started:** 2026-05-11T16:29Z
|
||||
**Completed:** 2026-05-11T16:29Z
|
||||
**Commit:** (see git log)
|
||||
**PRD:** ../PRD-relay-conformance.md
|
||||
|
||||
## What I changed
|
||||
|
||||
- `crates/wzp-relay/src/conformance.rs:1` — Updated module doc: `Tier A/B/C/D` → `Tier A/B/C/D/E`.
|
||||
- `crates/wzp-relay/src/conformance.rs:26-27` — Added `Violation::RateCapExceeded` variant for Tier E.
|
||||
- `crates/wzp-relay/src/conformance.rs:30-76` — Added `TokenBucket` struct with:
|
||||
- `capacity: u64`, `tokens: f64`, `refill_per_sec: u64`, `last_refill: Instant`
|
||||
- `new(capacity, refill_per_sec)` constructor
|
||||
- `for_audio_session()` factory: 256 kbps cap, 30 s @ 2× burst = 1_920_000 byte capacity
|
||||
- `try_consume(bytes, now)` — refills based on elapsed time, then deducts cost
|
||||
- `crates/wzp-relay/src/conformance.rs:84-85` — Added `token_bucket: Option<TokenBucket>` to `ConformanceMeter`.
|
||||
- `crates/wzp-relay/src/conformance.rs:97-102` — Added `ConformanceMeter::with_token_bucket(bucket)` constructor.
|
||||
- `crates/wzp-relay/src/conformance.rs:130-137` — Wired Tier E check into `observe()`: after Tier D, if a token bucket is present, attempt to consume the full wire size; return `Err(Violation::RateCapExceeded)` on exhaustion.
|
||||
- `crates/wzp-relay/src/metrics.rs:409` — Added `Violation::RateCapExceeded => "E"` tier label.
|
||||
- `crates/wzp-relay/src/room.rs:762-785` — Updated `run_participant()` signature to accept `is_authenticated: bool` and forward it to both plain and trunked loops.
|
||||
- `crates/wzp-relay/src/room.rs:807-814` — Plain loop: creates `ConformanceMeter::with_token_bucket(TokenBucket::for_audio_session())` for all participants (authed and anon share the same per-session audio cap).
|
||||
- `crates/wzp-relay/src/room.rs:1042-1044` — Trunked loop: same token-bucket meter setup.
|
||||
- `crates/wzp-relay/src/main.rs:2028` — Call site passes `authenticated_fp.is_some()` into `run_participant()`.
|
||||
- `crates/wzp-relay/src/conformance.rs:470-528` — Added 5 Tier E tests:
|
||||
- `token_bucket_small_burst_ok` — 50 KB inside 100 KB cap succeeds
|
||||
- `token_bucket_large_burst_fails` — 1 MB exceeds 100 KB cap
|
||||
- `token_bucket_refills_over_time` — drain, wait 1 s, consume refilled amount
|
||||
- `token_bucket_sustained_rate_balanced` — 32 KB/s for 5 s stays balanced
|
||||
- `conformance_tier_e_integration` — meter with 1_000-byte bucket, two 500-byte packets OK, third packet triggers `RateCapExceeded`
|
||||
|
||||
## Why these choices
|
||||
|
||||
- Used `f64` for internal token tracking so fractional refills across sub-second intervals are accurate. The public API still speaks in whole bytes.
|
||||
- Both authenticated and anonymous participants get the same per-session audio cap (256 kbps / 1.92 MB burst). The spec's authed/anon split applies to the *monthly* quota (50 GB vs 1 GB), which is a separate accounting concern not covered by the per-session token bucket. Passing `is_authenticated` through the call chain makes it easy to add monthly-quota wiring later.
|
||||
- Tier E runs after Tiers A–D so the cheaper checks still fire first on obvious abuse, while the token bucket catches the "low packet count, high burst size" tunneling vector.
|
||||
|
||||
## Deviations from the task spec
|
||||
|
||||
- The spec's `TokenBucket` sketch used `AtomicU64` for `tokens` and `last_refill`. Since each `ConformanceMeter` (and its bucket) is owned by a single tokio task (the per-participant forwarding loop), atomics are unnecessary. I used plain `f64` / `Instant` fields instead.
|
||||
|
||||
## Verification output
|
||||
|
||||
```bash
|
||||
$ cargo test -p wzp-relay token_bucket
|
||||
running 4 tests
|
||||
test conformance::tests::token_bucket_large_burst_fails ... ok
|
||||
test conformance::tests::token_bucket_refills_over_time ... ok
|
||||
test conformance::tests::token_bucket_small_burst_ok ... ok
|
||||
test conformance::tests::token_bucket_sustained_rate_balanced ... ok
|
||||
|
||||
test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 89 filtered out; finished in 0.00s
|
||||
```
|
||||
|
||||
```bash
|
||||
$ cargo test -p wzp-relay --lib
|
||||
running 93 tests
|
||||
...
|
||||
test result: ok. 93 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s
|
||||
```
|
||||
|
||||
```bash
|
||||
$ cargo test --workspace --exclude wzp-android --no-fail-fast
|
||||
... (all crates pass)
|
||||
Total: 617 passed; 0 failed
|
||||
```
|
||||
|
||||
## Test summary
|
||||
|
||||
- Tests added: 5
|
||||
- `token_bucket_small_burst_ok`
|
||||
- `token_bucket_large_burst_fails`
|
||||
- `token_bucket_refills_over_time`
|
||||
- `token_bucket_sustained_rate_balanced`
|
||||
- `conformance_tier_e_integration`
|
||||
- Tests modified: 0
|
||||
- Workspace test count before: 612 / after: 617
|
||||
- `cargo clippy -p wzp-relay --all-targets -- -D warnings`: clean in `wzp-relay`; failures are pre-existing debt in `wzp-codec` (9 errors) and `warzone-protocol` (3 errors)
|
||||
- `cargo fmt --all -- --check`: pass
|
||||
|
||||
## Risks / follow-ups
|
||||
|
||||
- Monthly byte quota (50 GB authed / 1 GB anon) is not yet implemented. The `is_authenticated` flag is now threaded through the forwarding loop so a future task can add a per-fingerprint monthly counter alongside the per-session token bucket.
|
||||
- Video sessions will need `TokenBucket::for_video_session()` (5 Mbps cap) once video forwarding loops land in Wave 4.
|
||||
- Tier E is observe-only, consistent with Tiers A–D. Hard enforcement (packet drop or session close) can be wired later if the reviewer wants.
|
||||
|
||||
## Reviewer checklist (filled in by reviewer)
|
||||
|
||||
- [ ] Code matches PRD intent
|
||||
- [ ] Verification output is real (re-run if suspicious)
|
||||
- [ ] No backward-incompat surprises
|
||||
- [ ] Tests cover the new behavior
|
||||
- [ ] Approved
|
||||
Reference in New Issue
Block a user