diff --git a/sdk-feature-matrix.md b/sdk-feature-matrix.md index 0a83305..6ac8edc 100644 --- a/sdk-feature-matrix.md +++ b/sdk-feature-matrix.md @@ -6,7 +6,7 @@ **Feature parity and compliance status across all CacheKit SDK implementations.** -*Last updated: 2026-07-29 — LAB-903: SDK Overview versions refreshed against the registries after the protocol 1.1 (envelope `bin` encoding, cachekit-core 0.4.0) rollout — py 0.17.0, core 0.4.0, rs 0.5.0 + macros 0.5.0, ts 0.1.4; per-SDK rollout state (which releases carry the flip, which bumps sit merged-unreleased on main) is recorded once, in the [cachekit-core architecture note](#architecture-notes). LAB-998: interop/v1 ship-status corrected — the row no longer reads `unreleased`; all three SDKs have published it (PyPI 0.14.0+, crates.io 0.4.0+, npm 0.1.3+), stated as floors per footnote ⁴, aligned with docs.cachekit.io (LAB-996). LAB-729: rs backpressure flipped ❌ → ✅ (semaphore + bounded queue in the rs reliability stack; decision footnote records why the LAB-519 ts rationale doesn't transfer to tokio). LAB-430 shipped TypeScript Node-only Memcached and File backends; the protocol-owned File format and vectors now define fail-closed flag negotiation. LAB-446: Python File backend gains full TTL inspection/refresh; Memcached gains `refresh_ttl` (touch) only (see [TTL management note](#reliability-features)). LAB-595 shipped: ts Cloudflare Workers flipped ❌ → ✅ via the `@cachekit-io/cachekit/workers` entrypoint on a wasm32 cachekit-core build (~55 KB gz measured); footnote ¹ records the phase-1 surface and semantics deltas. LAB-519: ts cold-miss single-flight (in-process, always on) + LockableBackend wired into `wrap()`'s miss path (opt-in); ts backpressure decision recorded; ts Redis lock/TTL capability cells refreshed for LAB-427. LAB-272 code-verified protocol-adherence audit (2026-07-22): interop/v1 merged in Python ([cachekit-py#220](https://github.com/cachekit-io/cachekit-py/pull/220)), TypeScript ([cachekit-ts#71](https://github.com/cachekit-io/cachekit-ts/pull/71)), and Rust ([cachekit-rs#33](https://github.com/cachekit-io/cachekit-rs/pull/33)); test-vector CI coverage corrected* +*Last updated: 2026-07-29 — LAB-903: SDK Overview versions refreshed against the registries after the protocol 1.1 (envelope `bin` encoding, cachekit-core 0.4.0) rollout — py 0.17.0, core 0.4.0, rs 0.5.0 + macros 0.5.0, ts 0.1.4; per-SDK rollout state (which releases carry the flip, which bumps sit merged-unreleased on main) is recorded once, in the [cachekit-core architecture note](#architecture-notes). LAB-998: interop/v1 ship-status corrected — the row no longer reads `unreleased`; all three SDKs have published it (PyPI 0.14.0+, crates.io 0.4.0+, npm 0.1.3+), stated as floors per footnote ⁴, aligned with docs.cachekit.io (LAB-996). LAB-729: rs backpressure flipped ❌ → ✅ (semaphore + bounded queue in the rs reliability stack; decision footnote records why the LAB-519 ts rationale doesn't transfer to tokio). LAB-728: new **Stale-while-revalidate (client L1)** row, split from the server stale-grace row. rs ships L1 SWR (serve stale + `single_flight()`-deduped background re-execution, `#[cachekit]` path, rs#47); py's cell records the honest scope (L1-only mode per LAB-106 — the backed-mode ✓ was LAB-388's dead-code trust bug); ts cell summarises `getWithSwr` in `wrap()` incl. the Workers force-off¹. LAB-430 shipped TypeScript Node-only Memcached and File backends; the protocol-owned File format and vectors now define fail-closed flag negotiation. LAB-446: Python File backend gains full TTL inspection/refresh; Memcached gains `refresh_ttl` (touch) only (see [TTL management note](#reliability-features)). LAB-595 shipped: ts Cloudflare Workers flipped ❌ → ✅ via the `@cachekit-io/cachekit/workers` entrypoint on a wasm32 cachekit-core build (~55 KB gz measured); footnote ¹ records the phase-1 surface and semantics deltas. LAB-519: ts cold-miss single-flight (in-process, always on) + LockableBackend wired into `wrap()`'s miss path (opt-in); ts backpressure decision recorded; ts Redis lock/TTL capability cells refreshed for LAB-427. LAB-272 code-verified protocol-adherence audit (2026-07-22): interop/v1 merged in Python ([cachekit-py#220](https://github.com/cachekit-io/cachekit-py/pull/220)), TypeScript ([cachekit-ts#71](https://github.com/cachekit-io/cachekit-ts/pull/71)), and Rust ([cachekit-rs#33](https://github.com/cachekit-io/cachekit-rs/pull/33)); test-vector CI coverage corrected* @@ -131,6 +131,7 @@ The contract a storage backend must satisfy per SDK (bytes in / bytes out; seria | L1/L2 dual-layer cache | ✅ | ✅ moka (native) / `l1` feature | ✅ | ❌ | | Cache stampede prevention | ✅ | ❌ | ✅ Cold-miss single-flight + SWR version tokens (LAB-519) | ❌ | | TTL management | ✅ Redis + SaaS + File; Memcached refresh-only (see note) | ✅ Redis + SaaS + File (`TtlInspectable`); Memcached refresh-only (LAB-429) | ✅ Redis + SaaS + File (`TTLBackend`); Memcached refresh-only (LAB-430) | ❌ | +| Stale-while-revalidate (client L1) | ✅ L1-only mode (`backend=None`) only: `get_with_swr` serves stale + refresh on a daemon thread (sync) / task (async), `swr_enabled` / `swr_threshold_ratio` (LAB-106; the backed-mode ✓ was the LAB-388 dead-code trust bug — removed) | ✅ `#[cachekit]` serves a stale L1 hit immediately + exactly one background re-execution deduped through the cold-miss `single_flight()` (in-process + distributed); builder `swr_enabled` / `swr_threshold_ratio`, default on / 0.5 ± 10% jitter; native only (LAB-728, rs#47 — live path: macro `interop_get_swr` → `L1Cache::get_with_swr`, verified non-blocking + exactly-once in `swr_tests`) | ✅ `getWithSwr` in `wrap()`: version tokens + background refresh, `maxConcurrentRefreshes` cap (forced off on the Workers entrypoint¹) | ❌ | | Stale-while-revalidate (server stale-grace) | 🚧 LAB-381 | ❌ | ❌ | ❌ | > **Lock id transport (CWE-532):** the unlock call carries the lock capability token in the `X-CacheKit-Lock-Id` request header, never the `?lock_id=` query string (which leaks via access/proxy logs and OTel `http.url` spans). **Migration complete in all three SDKs** (verified 2026-07-20, LAB-273): Python (#131, closed), Rust (#24, closed), TypeScript ships the header (ts#63 remains open only for an unrelated NAPI-rebuild item). SaaS dual-reads both during the rollout window. See [spec/saas-api.md](spec/saas-api.md#delete-v1cachekeylock).