diff --git a/changelog.d/20261110_rs-ts-one-outcome-per-call-released.md b/changelog.d/20261110_rs-ts-one-outcome-per-call-released.md new file mode 100644 index 0000000..db3917c --- /dev/null +++ b/changelog.d/20261110_rs-ts-one-outcome-per-call-released.md @@ -0,0 +1,8 @@ +### SDK feature matrix — one outcome per wrapped call released in cachekit-rs 0.13.1 and npm 0.2.2 + +- [`sdk-feature-matrix.md`](sdk-feature-matrix.md), **SaaS session telemetry headers**: the Rust and TypeScript + cells drop their ⚠️ notes. `cachekit-rs` 0.13.1, with `cachekit-macros` 0.13.1, is the first release where a + `#[cachekit]` call counts one outcome ([API-76](spec/saas-api.md#api-76), + [cachekit-rs#196](https://github.com/cachekit-io/cachekit-rs/pull/196)); `@cachekit-io/cachekit` 0.2.2 is the + first where a `wrap()` call does ([cachekit-ts#265](https://github.com/cachekit-io/cachekit-ts/pull/265)). Both + verified in the published `.crate` and `.tgz`; 0.13.0 and 0.2.1 count the reads inside the call instead. diff --git a/sdk-feature-matrix.md b/sdk-feature-matrix.md index d7903c9..4832756 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-11-07 — TypeScript wire-format, test-vector and hardware-acceleration cells flipped to the published `@cachekit-io/cachekit` 0.2.2, the first release whose exact pins, `cachekit-core-ts` 0.2.1 and `cachekit-core-wasm` 0.2.1, embed `cachekit-core` 0.7.2, so TypeScript ships the envelope pre-scan and the aarch64 Crypto Extension probe from 0.2.2. Every version-keyed claim is verified against the **published artifact** (registry metadata, and the `.crate`/`.tgz` contents where an embedded dependency version decides the answer), not against a repo branch — see [decisions/matrix-version-verification.md](decisions/matrix-version-verification.md) for why and how. Per-PR fold verdicts are in [CHANGELOG.md](CHANGELOG.md); per-row history is `git log sdk-feature-matrix.md`.* +*Last updated: 2026-11-10 — Rust and TypeScript session telemetry headers cells: the one-outcome-per-call rule ([API-76](spec/saas-api.md#api-76)) ships in the published `cachekit-rs` / `cachekit-macros` 0.13.1 and `@cachekit-io/cachekit` 0.2.2, so their ⚠️ notes are gone. Every version-keyed claim is verified against the **published artifact** (registry metadata, and the `.crate`/`.tgz` contents where an embedded dependency version decides the answer), not against a repo branch — see [decisions/matrix-version-verification.md](decisions/matrix-version-verification.md) for why and how. Per-PR fold verdicts are in [CHANGELOG.md](CHANGELOG.md); per-row history is `git log sdk-feature-matrix.md`.* *__Cells that reversed — check these if you built on them:__ Rust sync support (✅ → does not exist) and the Rust `::secure` preset (✅ → spelled `::encrypted` on every published `cachekit-rs` through 0.7.0 → `::secure` from 0.8.0¹¹), Builder API (py/ts ✅ → ❌), Hardware acceleration (rs ✅ → not re-exported → re-exported from 0.8.0, ts N/A → ❌ → surfaced from 0.2.1), TypeScript Arrow (🔜 → ❌), Python's encrypted read path (documented fail-closed → **fail-open by default**), and `cache.secure.wrap()` in TypeScript (implied encryption → no guarantee → **enforced since LAB-513: throws without encryption**). The TypeScript protocol-1.1 `bin` rollout also reversed twice in two days: it was **not** shipped on either ts path through 0.1.5, and ships on both from 0.2.1 (per-artifact evidence in the [cachekit-core architecture note](#architecture-notes)).* @@ -229,7 +229,7 @@ The contract a storage backend must satisfy per SDK (bytes in / bytes out; seria | Metrics | ✅ Live `prometheus_client` counters / gauges / histograms on the default registry; no HTTP exposition helper | ✅ `cachekit-rs` 0.8.0+ — live counters ([cachekit-rs#81](https://github.com/cachekit-io/cachekit-rs/pull/81)). `CacheKit::stats()` returns `L1Stats`, plus `l1_entry_count()` and `circuit_state()`; no Prometheus exposition (LAB-521) | ✅ Node — live Prometheus metrics via the optional `prom-client` peer dep, custom registry supported, warns once and no-ops if absent (LAB-517) · ❌ Workers — `prom-client` is CI-excluded from the edge bundle¹ | ❌ | | Structured logging | ✅ JSON ring-buffer logger with sensitive-data masking (`logging.py`) | ✅ `cachekit-rs` 0.8.0+ — `tracing` events ([cachekit-rs#81](https://github.com/cachekit-io/cachekit-rs/pull/81)). Opt-in `tracing` cargo feature: one `debug` event per get/set/delete, carrying `key_hash` (unkeyed Blake2b-128 of the storage key: a correlator, not a redaction), plus breaker transitions, to the host's subscriber (LAB-521) | ⚠️ Pluggable error-logger hook (`setLogger`, default `console.error`) — a logging seam, not a structured logger (LAB-517) | ❌ | | Distributed tracing (OTel) | ❌ The span-shaped API accepts spans and discards them (`NoOpSpan` in `FeatureOrchestrator.create_span`, `decorators/orchestrator.py`) — instrumentation built against it silently produces nothing | ❌ | ❌ | ❌ | -| SaaS session telemetry headers (`X-CacheKit-Session-*`, `-L1-Hits`, `-L2-Hits`, `-Misses`, `-L1-Hit-Rate`) | ✅ Auto. The decorators count one outcome per call ([Counting outcomes](spec/saas-api.md#counting-outcomes)) · ⚠️ sends `X-CacheKit-L1-Hit-Rate` as L1-Hits / (L1-Hits + L2-Hits), not the share of all counted operations [API-78](spec/saas-api.md#api-78) pins | ✅ `cachekit-rs` 0.8.0+ ([cachekit-rs#81](https://github.com/cachekit-io/cachekit-rs/pull/81)). Auto-wired from live counters; an explicit `.metrics_provider()` still wins (LAB-521) · ⚠️ through 0.13.0 a `#[cachekit]` call can count up to about 51 misses ([API-76](spec/saas-api.md#api-76)); fix: [cachekit-rs#196](https://github.com/cachekit-io/cachekit-rs/pull/196) | ✅ Auto-wired from the live L1/L2 hit/miss counters; an explicit user `metricsProvider` still wins · ⚠️ through npm 0.2.1 a `wrap()` call can count two outcomes or none ([API-76](spec/saas-api.md#api-76)); fix: [cachekit-ts#265](https://github.com/cachekit-io/cachekit-ts/pull/265) | ❌ | +| SaaS session telemetry headers (`X-CacheKit-Session-*`, `-L1-Hits`, `-L2-Hits`, `-Misses`, `-L1-Hit-Rate`) | ✅ Auto. The decorators count one outcome per call ([Counting outcomes](spec/saas-api.md#counting-outcomes)) · ⚠️ sends `X-CacheKit-L1-Hit-Rate` as L1-Hits / (L1-Hits + L2-Hits), not the share of all counted operations [API-78](spec/saas-api.md#api-78) pins | ✅ `cachekit-rs` 0.8.0+ ([cachekit-rs#81](https://github.com/cachekit-io/cachekit-rs/pull/81)). Auto-wired from live counters; an explicit `.metrics_provider()` still wins (LAB-521) · one outcome per `#[cachekit]` call ([API-76](spec/saas-api.md#api-76)) from 0.13.1 ([cachekit-rs#196](https://github.com/cachekit-io/cachekit-rs/pull/196); `cachekit-macros` 0.13.1 `.crate` inspected 2026-11-10); through 0.13.0 one call can count up to about 51 misses | ✅ Auto-wired from the live L1/L2 hit/miss counters; an explicit user `metricsProvider` still wins · one outcome per `wrap()` call ([API-76](spec/saas-api.md#api-76)) from npm 0.2.2 ([cachekit-ts#265](https://github.com/cachekit-io/cachekit-ts/pull/265); `.tgz` inspected 2026-11-10); through 0.2.1 one call can count two outcomes or none | ❌ | | SaaS L1 hit-latency headers (`X-CacheKit-L1-Latency-*`) | ❌ Specified ([L1 hit latency](spec/saas-api.md#l1-hit-latency)), not shipped. Backed-mode L1 hits are timed only for the local Prometheus histogram | ❌ Specified, not shipped. No L1 timer; never on the `workers` feature, whose clock cannot time an L1 hit ([API-82](spec/saas-api.md#api-82)) | ❌ Specified, not shipped. No L1 timer; never on the Workers entry, whose clock cannot time an L1 hit ([API-82](spec/saas-api.md#api-82)) | ❌ | | Telemetry switch (`telemetry` setting, `CACHEKIT_TELEMETRY`) | ❌ Specified ([Telemetry switch](spec/saas-api.md#telemetry-switch)), not shipped: no switch; the session headers ride every request made inside a decorated call | ❌ Specified, not shipped: the session headers are always sent | ❌ Specified, not shipped: the session headers are always sent | ❌ |