From f0ae021f659d283aaafd2a03ad3958cf58aaa609 Mon Sep 17 00:00:00 2001 From: Ray Walker Date: Tue, 21 Jul 2026 01:06:04 +1000 Subject: [PATCH 1/6] docs: correct SDK feature matrix to code-verified protocol-adherence reality (LAB-272) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Audit of py/rs/ts main branches against the four protocol requirements: - Interop mode: merged in cachekit-py (#220) and cachekit-ts (#71), in review for cachekit-rs (#33) — the '❌ Not implemented' row was stale. - Test vectors row now states what each SDK's CI actually executes; wire-format.json and cache-keys.json are verified by no CI anywhere (LAB-423, LAB-425). - Rust keygen cell: caller-supplied keys remain N/A, but the crate exports an unused legacy generate_cache_key matching no protocol format (LAB-424); conformant keygen arrives with cachekit-rs#33. - AAD v0x03 cells record component arity per SDK (py auto serializers emit the optional fifth original_type component; rs/ts/interop are four-component) — byte-identity code-verified per protocol#12. - cachekit-py fleet version 0.11.1 -> 0.12.0. Co-authored-by: multica-agent --- sdk-feature-matrix.md | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/sdk-feature-matrix.md b/sdk-feature-matrix.md index 05c5fce..80f415f 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-20 — LAB-381 stale-while-revalidate (server stale-grace) specified in [spec/saas-api.md](spec/saas-api.md#stale-while-revalidate)* +*Last updated: 2026-07-21 — LAB-272 code-verified protocol-adherence audit: interop/v1 merged in Python ([cachekit-py#220](https://github.com/cachekit-io/cachekit-py/pull/220)) and TypeScript ([cachekit-ts#71](https://github.com/cachekit-io/cachekit-ts/pull/71)), Rust in review ([cachekit-rs#33](https://github.com/cachekit-io/cachekit-rs/pull/33)); test-vector CI coverage corrected* @@ -29,7 +29,7 @@ | SDK | Package | Version | Language | Status | | :--- | :--- | :---: | :--- | :---: | -| cachekit-py | `cachekit` (PyPI) | 0.11.1 | Python 3.10+ | ✅ Production | +| cachekit-py | `cachekit` (PyPI) | 0.12.0 | Python 3.10+ | ✅ Production | | cachekit-rs | `cachekit-rs` (crates.io) | 0.3.0 | Rust 1.82+ | ✅ Production | | cachekit-core | `cachekit-core` (crates.io) | 0.3.0 | Rust (shared core) | ✅ Production | | cachekit-ts | `@cachekit-io/cachekit` (npm) | 0.1.2 | TypeScript | ✅ Production | @@ -62,7 +62,7 @@ | Counter-based nonces | ✅ via Rust | ✅ | ✅ via NAPI (Rust) | ❌ use random | > [!IMPORTANT] -> AAD v0x03 is required for protocol compliance. SDKs without it cannot safely interoperate with encrypted payloads from compliant SDKs — the auth tag will fail verification. See [spec/encryption.md](spec/encryption.md#additional-authenticated-data-aad). Python, Rust, and TypeScript SDKs are compliant as of 2026-04-06. +> AAD v0x03 is required for protocol compliance. SDKs without it cannot safely interoperate with encrypted payloads from compliant SDKs — the auth tag will fail verification. See [spec/encryption.md](spec/encryption.md#additional-authenticated-data-aad). Python, Rust, and TypeScript construction was code-verified byte-identical on 2026-07-21 (LAB-272): identical `[0x03][4-byte BE length][component]` layout with the frozen `True`/`False` compressed tokens (protocol#12). Python's auto serializers append the optional `original_type` fifth component; Rust, TypeScript, and interop mode always emit exactly four. Python's read path fails closed when encryption is enabled but a stored entry claims plaintext ([cachekit-py#215](https://github.com/cachekit-io/cachekit-py/pull/215)). --- @@ -129,20 +129,23 @@ its spec: | Requirement | Python | Rust | TypeScript | PHP | | :--- | :---: | :---: | :---: | :---: | -| Key generation (Blake2b) | ✅ Compliant | N/A (SDK-level, not in core) | ✅ Compliant | ⚠️ Untested | +| Key generation (Blake2b) | ✅ Compliant | N/A auto mode (caller-supplied keys)² — interop keygen 🚧 [#33](https://github.com/cachekit-io/cachekit-rs/pull/33) | ✅ Compliant | ⚠️ Untested | | Wire format (ByteStorage) | ✅ Compliant¹ | ✅ Canonical (`cachekit-core`) — unused for stored values¹ | ✅ Compliant | ⚠️ Untested | | Storage container (auto mode)¹ | CK v3 frame (Python-internal) | Plain MessagePack (`rmp` named) — no envelope | Bare ByteStorage envelope (default) | — | | Encryption (AES-256-GCM) | ✅ Compliant | ✅ Canonical (cachekit-core) | ✅ Compliant | ⚠️ Untested | -| AAD v0x03 | ✅ Compliant | ✅ Compliant | ✅ Compliant | ❌ Not implemented | +| AAD v0x03 | ✅ Compliant (4 components; +`original_type` 5th on auto serializers) | ✅ Compliant (4 components) | ✅ Compliant (4 components) | ❌ Not implemented | | SaaS API | ✅ Compliant | ✅ Compliant (CachekitIO backend) | ✅ Compliant | ❌ Not implemented | -| Test vectors | ⚠️ Pending | ⚠️ Pending | ✅ Python cross-SDK vectors | ⚠️ Pending | -| Interop mode ([spec](spec/interop-mode.md), opt-in) | ❌ Not implemented | ❌ Not implemented | ❌ Not implemented | ❌ Not implemented | +| Test vectors in CI³ | ✅ interop/v1 (full set, incl. AAD + encryption through the real stack) | ❌ None on `main` — interop vectors land with [#33](https://github.com/cachekit-io/cachekit-rs/pull/33) | ✅ interop/v1 (full set) + inline Python-generated key/AAD vectors | ⚠️ Pending | +| Interop mode ([spec](spec/interop-mode.md), opt-in) | ✅ Merged ([#220](https://github.com/cachekit-io/cachekit-py/pull/220), unreleased) | 🚧 In review ([#33](https://github.com/cachekit-io/cachekit-rs/pull/33)) | ✅ Merged ([#71](https://github.com/cachekit-io/cachekit-ts/pull/71), unreleased) | ❌ Not implemented | > [!NOTE] -> "N/A" for Rust key generation means `cachekit-core` is a protocol primitive library. Key generation (Blake2b) is an SDK-level concern — `cachekit-rs` delegates cache key construction to the caller via the `key` parameter on `get`/`set`/`#[cachekit]`. +> ¹ Auto-mode **stored bytes** are SDK-internal and differ per SDK — see [wire-format.md → SDK Storage Containers](spec/wire-format.md#sdk-storage-containers-auto-mode). Python stores the ByteStorage envelope *inside* its CK v3 frame; `cachekit-rs` does not use the envelope for values at all (it uses `cachekit-core` only for encryption). Cross-SDK value compatibility is exclusively an [interop-mode](spec/interop-mode.md) property (protocol#11). > [!NOTE] -> ¹ Auto-mode **stored bytes** are SDK-internal and differ per SDK — see [wire-format.md → SDK Storage Containers](spec/wire-format.md#sdk-storage-containers-auto-mode). Python stores the ByteStorage envelope *inside* its CK v3 frame; `cachekit-rs` does not use the envelope for values at all (it uses `cachekit-core` only for encryption). Cross-SDK value compatibility is exclusively an [interop-mode](spec/interop-mode.md) property (protocol#11). +> ² "N/A" for Rust key generation means auto-mode `cachekit-rs` delegates cache key construction to the caller via the `key` parameter on `get`/`set`/`#[cachekit]`; `cachekit-core` is a protocol primitive library with no keygen. The crate does export an unused legacy `key::generate_cache_key` that matches **no** protocol key format — do not use it for cross-SDK keys (removal/replacement tracked as LAB-424). Spec-conformant Rust keygen arrives with interop mode ([cachekit-rs#33](https://github.com/cachekit-io/cachekit-rs/pull/33)). + +> [!NOTE] +> ³ "Test vectors in CI" = vectors the SDK's own default CI executes. Beyond the SDKs, this repo's `verify.yml` CI-verifies `interop-mode.json`, `encryption.json`, and `python-frame.json` against reference implementations. **Not verified by any CI anywhere**: `wire-format.json` (tracked as LAB-423) and `cache-keys.json` (generated by cachekit-py v0.5.0; tracked as LAB-425). --- From fa218079cb96170953b4ff3a43dc1377332ff869 Mon Sep 17 00:00:00 2001 From: Ray Walker Date: Tue, 21 Jul 2026 01:42:03 +1000 Subject: [PATCH 2/6] =?UTF-8?q?docs(matrix):=20correct=20Rust=20keygen=20f?= =?UTF-8?q?ootnote=20=E2=80=94=20#[cachekit]=20has=20no=20key=20param=20an?= =?UTF-8?q?d=20generate=5Fcache=5Fkey=20is=20not=20unused=20[LAB-424]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The footnote claimed cachekit-rs delegates key construction via a 'key' parameter on #[cachekit] (no such parameter exists) and called key::generate_cache_key 'unused' (it is called at runtime by every #[cachekit] expansion — proc-macro call sites are invisible to grep). Rewritten to the verified posture: get/set caller-supplied; macro derives an SDK-internal legacy RFC-shape key, made private in cachekit-rs#35 (LAB-424); conformant keygen arrives with #33. Co-authored-by: multica-agent --- sdk-feature-matrix.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk-feature-matrix.md b/sdk-feature-matrix.md index 80f415f..c8a45a7 100644 --- a/sdk-feature-matrix.md +++ b/sdk-feature-matrix.md @@ -129,7 +129,7 @@ its spec: | Requirement | Python | Rust | TypeScript | PHP | | :--- | :---: | :---: | :---: | :---: | -| Key generation (Blake2b) | ✅ Compliant | N/A auto mode (caller-supplied keys)² — interop keygen 🚧 [#33](https://github.com/cachekit-io/cachekit-rs/pull/33) | ✅ Compliant | ⚠️ Untested | +| Key generation (Blake2b) | ✅ Compliant | N/A auto mode (no spec'd keygen)² — interop keygen 🚧 [#33](https://github.com/cachekit-io/cachekit-rs/pull/33) | ✅ Compliant | ⚠️ Untested | | Wire format (ByteStorage) | ✅ Compliant¹ | ✅ Canonical (`cachekit-core`) — unused for stored values¹ | ✅ Compliant | ⚠️ Untested | | Storage container (auto mode)¹ | CK v3 frame (Python-internal) | Plain MessagePack (`rmp` named) — no envelope | Bare ByteStorage envelope (default) | — | | Encryption (AES-256-GCM) | ✅ Compliant | ✅ Canonical (cachekit-core) | ✅ Compliant | ⚠️ Untested | @@ -142,7 +142,7 @@ its spec: > ¹ Auto-mode **stored bytes** are SDK-internal and differ per SDK — see [wire-format.md → SDK Storage Containers](spec/wire-format.md#sdk-storage-containers-auto-mode). Python stores the ByteStorage envelope *inside* its CK v3 frame; `cachekit-rs` does not use the envelope for values at all (it uses `cachekit-core` only for encryption). Cross-SDK value compatibility is exclusively an [interop-mode](spec/interop-mode.md) property (protocol#11). > [!NOTE] -> ² "N/A" for Rust key generation means auto-mode `cachekit-rs` delegates cache key construction to the caller via the `key` parameter on `get`/`set`/`#[cachekit]`; `cachekit-core` is a protocol primitive library with no keygen. The crate does export an unused legacy `key::generate_cache_key` that matches **no** protocol key format — do not use it for cross-SDK keys (removal/replacement tracked as LAB-424). Spec-conformant Rust keygen arrives with interop mode ([cachekit-rs#33](https://github.com/cachekit-io/cachekit-rs/pull/33)). +> ² "N/A" for Rust key generation means `cachekit-rs` implements no spec'd key format: `get`/`set` take caller-supplied keys, and the `#[cachekit]` macro (which has **no** `key` parameter) derives an SDK-internal legacy key — `{namespace}:{blake2b256-hex}` over the *unqualified* function name, the obsolete RFC §3.1.5 shape matching **no** current protocol key format, never usable cross-SDK. That derivation is macro-internal plumbing (it IS called at runtime by every `#[cachekit]` expansion — the LAB-424 "unused" premise was a grep miss), removed from the public API in [cachekit-rs#35](https://github.com/cachekit-io/cachekit-rs/pull/35). `cachekit-core` is a protocol primitive library with no keygen. Spec-conformant Rust keygen arrives with interop mode ([cachekit-rs#33](https://github.com/cachekit-io/cachekit-rs/pull/33)). > [!NOTE] > ³ "Test vectors in CI" = vectors the SDK's own default CI executes. Beyond the SDKs, this repo's `verify.yml` CI-verifies `interop-mode.json`, `encryption.json`, and `python-frame.json` against reference implementations. **Not verified by any CI anywhere**: `wire-format.json` (tracked as LAB-423) and `cache-keys.json` (generated by cachekit-py v0.5.0; tracked as LAB-425). From 8f616e9b62996ee1057df1ee536eac03038f7d08 Mon Sep 17 00:00:00 2001 From: Ray Walker Date: Tue, 21 Jul 2026 11:22:38 +1000 Subject: [PATCH 3/6] =?UTF-8?q?docs(matrix):=20presentation-clarity=20fixe?= =?UTF-8?q?s=20=E2=80=94=20Python=20AAD=20norm,=20footnote=20order,=20TS?= =?UTF-8?q?=20vector=20wording=20[LAB-445]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four clarity nits flagged by the LAB-272 expert-panel review of #24; no factual claim changes (verdicts, marks, versions, byte constants preserved): - Python AAD cell: 5-component is the Python norm (every auto serializer appends original_type); interop mode is the sole 4-component path — matches the line-65 callout framing instead of reading like an edge case. - Footnotes renumbered so first appearance runs 1, 2, 3 in reading order (keygen note was 2 but appeared before 1); note blocks reordered to match. - TS test-vectors cell: 'key/AAD' disambiguated to what CI actually runs — inline Python-generated AAD-construction + encryption (decrypt-Python- ciphertext) vectors. 'key' dropped: key-generation.protocol.test.ts holds property checks only, no Python-generated key values; key-vector coverage is the interop/v1 set (33 key vectors), now credited explicitly. - AAD byte-layout detail deduped out of the matrix callout: layout, frozen True/False tokens, and the protocol#12 decision are already normative in spec/encryption.md, which stays linked — matrix keeps parity altitude. Co-authored-by: multica-agent --- sdk-feature-matrix.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/sdk-feature-matrix.md b/sdk-feature-matrix.md index c8a45a7..149753d 100644 --- a/sdk-feature-matrix.md +++ b/sdk-feature-matrix.md @@ -62,7 +62,7 @@ | Counter-based nonces | ✅ via Rust | ✅ | ✅ via NAPI (Rust) | ❌ use random | > [!IMPORTANT] -> AAD v0x03 is required for protocol compliance. SDKs without it cannot safely interoperate with encrypted payloads from compliant SDKs — the auth tag will fail verification. See [spec/encryption.md](spec/encryption.md#additional-authenticated-data-aad). Python, Rust, and TypeScript construction was code-verified byte-identical on 2026-07-21 (LAB-272): identical `[0x03][4-byte BE length][component]` layout with the frozen `True`/`False` compressed tokens (protocol#12). Python's auto serializers append the optional `original_type` fifth component; Rust, TypeScript, and interop mode always emit exactly four. Python's read path fails closed when encryption is enabled but a stored entry claims plaintext ([cachekit-py#215](https://github.com/cachekit-io/cachekit-py/pull/215)). +> AAD v0x03 is required for protocol compliance. SDKs without it cannot safely interoperate with encrypted payloads from compliant SDKs — the auth tag will fail verification. Python, Rust, and TypeScript construction was code-verified byte-identical on 2026-07-21 (LAB-272); the normative byte layout and the frozen `True`/`False` compressed tokens (protocol#12) are defined in [spec/encryption.md](spec/encryption.md#additional-authenticated-data-aad). Python's auto serializers append the optional `original_type` fifth component; Rust, TypeScript, and interop mode always emit exactly four. Python's read path fails closed when encryption is enabled but a stored entry claims plaintext ([cachekit-py#215](https://github.com/cachekit-io/cachekit-py/pull/215)). --- @@ -129,20 +129,20 @@ its spec: | Requirement | Python | Rust | TypeScript | PHP | | :--- | :---: | :---: | :---: | :---: | -| Key generation (Blake2b) | ✅ Compliant | N/A auto mode (no spec'd keygen)² — interop keygen 🚧 [#33](https://github.com/cachekit-io/cachekit-rs/pull/33) | ✅ Compliant | ⚠️ Untested | -| Wire format (ByteStorage) | ✅ Compliant¹ | ✅ Canonical (`cachekit-core`) — unused for stored values¹ | ✅ Compliant | ⚠️ Untested | -| Storage container (auto mode)¹ | CK v3 frame (Python-internal) | Plain MessagePack (`rmp` named) — no envelope | Bare ByteStorage envelope (default) | — | +| Key generation (Blake2b) | ✅ Compliant | N/A auto mode (no spec'd keygen)¹ — interop keygen 🚧 [#33](https://github.com/cachekit-io/cachekit-rs/pull/33) | ✅ Compliant | ⚠️ Untested | +| Wire format (ByteStorage) | ✅ Compliant² | ✅ Canonical (`cachekit-core`) — unused for stored values² | ✅ Compliant | ⚠️ Untested | +| Storage container (auto mode)² | CK v3 frame (Python-internal) | Plain MessagePack (`rmp` named) — no envelope | Bare ByteStorage envelope (default) | — | | Encryption (AES-256-GCM) | ✅ Compliant | ✅ Canonical (cachekit-core) | ✅ Compliant | ⚠️ Untested | -| AAD v0x03 | ✅ Compliant (4 components; +`original_type` 5th on auto serializers) | ✅ Compliant (4 components) | ✅ Compliant (4 components) | ❌ Not implemented | +| AAD v0x03 | ✅ Compliant (5 components — every auto serializer appends `original_type`; interop mode is the sole 4-component path) | ✅ Compliant (4 components) | ✅ Compliant (4 components) | ❌ Not implemented | | SaaS API | ✅ Compliant | ✅ Compliant (CachekitIO backend) | ✅ Compliant | ❌ Not implemented | -| Test vectors in CI³ | ✅ interop/v1 (full set, incl. AAD + encryption through the real stack) | ❌ None on `main` — interop vectors land with [#33](https://github.com/cachekit-io/cachekit-rs/pull/33) | ✅ interop/v1 (full set) + inline Python-generated key/AAD vectors | ⚠️ Pending | +| Test vectors in CI³ | ✅ interop/v1 (full set, incl. AAD + encryption through the real stack) | ❌ None on `main` — interop vectors land with [#33](https://github.com/cachekit-io/cachekit-rs/pull/33) | ✅ interop/v1 (full set, incl. its key vectors) + inline Python-generated AAD-construction and encryption (decrypt-Python-ciphertext) vectors | ⚠️ Pending | | Interop mode ([spec](spec/interop-mode.md), opt-in) | ✅ Merged ([#220](https://github.com/cachekit-io/cachekit-py/pull/220), unreleased) | 🚧 In review ([#33](https://github.com/cachekit-io/cachekit-rs/pull/33)) | ✅ Merged ([#71](https://github.com/cachekit-io/cachekit-ts/pull/71), unreleased) | ❌ Not implemented | > [!NOTE] -> ¹ Auto-mode **stored bytes** are SDK-internal and differ per SDK — see [wire-format.md → SDK Storage Containers](spec/wire-format.md#sdk-storage-containers-auto-mode). Python stores the ByteStorage envelope *inside* its CK v3 frame; `cachekit-rs` does not use the envelope for values at all (it uses `cachekit-core` only for encryption). Cross-SDK value compatibility is exclusively an [interop-mode](spec/interop-mode.md) property (protocol#11). +> ¹ "N/A" for Rust key generation means `cachekit-rs` implements no spec'd key format: `get`/`set` take caller-supplied keys, and the `#[cachekit]` macro (which has **no** `key` parameter) derives an SDK-internal legacy key — `{namespace}:{blake2b256-hex}` over the *unqualified* function name, the obsolete RFC §3.1.5 shape matching **no** current protocol key format, never usable cross-SDK. That derivation is macro-internal plumbing (it IS called at runtime by every `#[cachekit]` expansion — the LAB-424 "unused" premise was a grep miss), removed from the public API in [cachekit-rs#35](https://github.com/cachekit-io/cachekit-rs/pull/35). `cachekit-core` is a protocol primitive library with no keygen. Spec-conformant Rust keygen arrives with interop mode ([cachekit-rs#33](https://github.com/cachekit-io/cachekit-rs/pull/33)). > [!NOTE] -> ² "N/A" for Rust key generation means `cachekit-rs` implements no spec'd key format: `get`/`set` take caller-supplied keys, and the `#[cachekit]` macro (which has **no** `key` parameter) derives an SDK-internal legacy key — `{namespace}:{blake2b256-hex}` over the *unqualified* function name, the obsolete RFC §3.1.5 shape matching **no** current protocol key format, never usable cross-SDK. That derivation is macro-internal plumbing (it IS called at runtime by every `#[cachekit]` expansion — the LAB-424 "unused" premise was a grep miss), removed from the public API in [cachekit-rs#35](https://github.com/cachekit-io/cachekit-rs/pull/35). `cachekit-core` is a protocol primitive library with no keygen. Spec-conformant Rust keygen arrives with interop mode ([cachekit-rs#33](https://github.com/cachekit-io/cachekit-rs/pull/33)). +> ² Auto-mode **stored bytes** are SDK-internal and differ per SDK — see [wire-format.md → SDK Storage Containers](spec/wire-format.md#sdk-storage-containers-auto-mode). Python stores the ByteStorage envelope *inside* its CK v3 frame; `cachekit-rs` does not use the envelope for values at all (it uses `cachekit-core` only for encryption). Cross-SDK value compatibility is exclusively an [interop-mode](spec/interop-mode.md) property (protocol#11). > [!NOTE] > ³ "Test vectors in CI" = vectors the SDK's own default CI executes. Beyond the SDKs, this repo's `verify.yml` CI-verifies `interop-mode.json`, `encryption.json`, and `python-frame.json` against reference implementations. **Not verified by any CI anywhere**: `wire-format.json` (tracked as LAB-423) and `cache-keys.json` (generated by cachekit-py v0.5.0; tracked as LAB-425). From f85f90f1f602ee0e5777a11a5cec706010575b85 Mon Sep 17 00:00:00 2001 From: Ray Walker Date: Wed, 22 Jul 2026 12:28:28 +1000 Subject: [PATCH 4/6] docs(matrix): Rust #[cachekit] now mints interop/v1 keys; #33 merged [LAB-424] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit cachekit-rs#35 pivoted from hiding the legacy keygen to deleting it: the macro now delegates to interop_key with required explicit interop/namespace attributes (owner call — greenfield, no byte-stability constraint). Interop row: rs #33 merged (unreleased), matching py/ts. Footnote ¹ rewritten to the shipped posture and notes the upgrade is a full cache invalidation for #[cachekit] users. Co-authored-by: multica-agent --- sdk-feature-matrix.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk-feature-matrix.md b/sdk-feature-matrix.md index 149753d..0d02a71 100644 --- a/sdk-feature-matrix.md +++ b/sdk-feature-matrix.md @@ -129,17 +129,17 @@ its spec: | Requirement | Python | Rust | TypeScript | PHP | | :--- | :---: | :---: | :---: | :---: | -| Key generation (Blake2b) | ✅ Compliant | N/A auto mode (no spec'd keygen)¹ — interop keygen 🚧 [#33](https://github.com/cachekit-io/cachekit-rs/pull/33) | ✅ Compliant | ⚠️ Untested | +| Key generation (Blake2b) | ✅ Compliant | N/A auto mode¹ — interop/v1 keygen ✅ merged ([#33](https://github.com/cachekit-io/cachekit-rs/pull/33)); `#[cachekit]` mints interop keys ([#35](https://github.com/cachekit-io/cachekit-rs/pull/35)) | ✅ Compliant | ⚠️ Untested | | Wire format (ByteStorage) | ✅ Compliant² | ✅ Canonical (`cachekit-core`) — unused for stored values² | ✅ Compliant | ⚠️ Untested | | Storage container (auto mode)² | CK v3 frame (Python-internal) | Plain MessagePack (`rmp` named) — no envelope | Bare ByteStorage envelope (default) | — | | Encryption (AES-256-GCM) | ✅ Compliant | ✅ Canonical (cachekit-core) | ✅ Compliant | ⚠️ Untested | | AAD v0x03 | ✅ Compliant (5 components — every auto serializer appends `original_type`; interop mode is the sole 4-component path) | ✅ Compliant (4 components) | ✅ Compliant (4 components) | ❌ Not implemented | | SaaS API | ✅ Compliant | ✅ Compliant (CachekitIO backend) | ✅ Compliant | ❌ Not implemented | | Test vectors in CI³ | ✅ interop/v1 (full set, incl. AAD + encryption through the real stack) | ❌ None on `main` — interop vectors land with [#33](https://github.com/cachekit-io/cachekit-rs/pull/33) | ✅ interop/v1 (full set, incl. its key vectors) + inline Python-generated AAD-construction and encryption (decrypt-Python-ciphertext) vectors | ⚠️ Pending | -| Interop mode ([spec](spec/interop-mode.md), opt-in) | ✅ Merged ([#220](https://github.com/cachekit-io/cachekit-py/pull/220), unreleased) | 🚧 In review ([#33](https://github.com/cachekit-io/cachekit-rs/pull/33)) | ✅ Merged ([#71](https://github.com/cachekit-io/cachekit-ts/pull/71), unreleased) | ❌ Not implemented | +| Interop mode ([spec](spec/interop-mode.md), opt-in) | ✅ Merged ([#220](https://github.com/cachekit-io/cachekit-py/pull/220), unreleased) | ✅ Merged ([#33](https://github.com/cachekit-io/cachekit-rs/pull/33), unreleased) | ✅ Merged ([#71](https://github.com/cachekit-io/cachekit-ts/pull/71), unreleased) | ❌ Not implemented | > [!NOTE] -> ¹ "N/A" for Rust key generation means `cachekit-rs` implements no spec'd key format: `get`/`set` take caller-supplied keys, and the `#[cachekit]` macro (which has **no** `key` parameter) derives an SDK-internal legacy key — `{namespace}:{blake2b256-hex}` over the *unqualified* function name, the obsolete RFC §3.1.5 shape matching **no** current protocol key format, never usable cross-SDK. That derivation is macro-internal plumbing (it IS called at runtime by every `#[cachekit]` expansion — the LAB-424 "unused" premise was a grep miss), removed from the public API in [cachekit-rs#35](https://github.com/cachekit-io/cachekit-rs/pull/35). `cachekit-core` is a protocol primitive library with no keygen. Spec-conformant Rust keygen arrives with interop mode ([cachekit-rs#33](https://github.com/cachekit-io/cachekit-rs/pull/33)). +> ¹ "N/A" for Rust *auto-mode* key generation means `cachekit-rs` implements no auto-mode key format: `get`/`set` take caller-supplied keys. The `#[cachekit]` macro mints **interop/v1** keys via `interop_key` — required, compile-time-validated `interop = "operation"` and `namespace` attributes, byte-identical across SDKs ([cachekit-rs#35](https://github.com/cachekit-io/cachekit-rs/pull/35) / LAB-424; keygen itself merged in [#33](https://github.com/cachekit-io/cachekit-rs/pull/33)). The legacy RFC §3.1.5 keygen (`key::generate_cache_key`, `{namespace}:{blake2b256-hex}` — matched no protocol format, and WAS live in every `#[cachekit]` expansion despite the audit's "unused" premise, a proc-macro grep miss) is deleted outright in #35; upgrading is a full cache invalidation for `#[cachekit]` users. `cachekit-core` is a protocol primitive library with no keygen. > [!NOTE] > ² Auto-mode **stored bytes** are SDK-internal and differ per SDK — see [wire-format.md → SDK Storage Containers](spec/wire-format.md#sdk-storage-containers-auto-mode). Python stores the ByteStorage envelope *inside* its CK v3 frame; `cachekit-rs` does not use the envelope for values at all (it uses `cachekit-core` only for encryption). Cross-SDK value compatibility is exclusively an [interop-mode](spec/interop-mode.md) property (protocol#11). From 903805e4ca2b46bdf9b6ee7622a7d07ee25ac665 Mon Sep 17 00:00:00 2001 From: Ray Walker Date: Wed, 22 Jul 2026 12:29:18 +1000 Subject: [PATCH 5/6] docs(matrix): rs runs the interop vector set in CI on main since #33 merged [LAB-424] Co-authored-by: multica-agent --- sdk-feature-matrix.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk-feature-matrix.md b/sdk-feature-matrix.md index 0d02a71..7f06198 100644 --- a/sdk-feature-matrix.md +++ b/sdk-feature-matrix.md @@ -135,7 +135,7 @@ its spec: | Encryption (AES-256-GCM) | ✅ Compliant | ✅ Canonical (cachekit-core) | ✅ Compliant | ⚠️ Untested | | AAD v0x03 | ✅ Compliant (5 components — every auto serializer appends `original_type`; interop mode is the sole 4-component path) | ✅ Compliant (4 components) | ✅ Compliant (4 components) | ❌ Not implemented | | SaaS API | ✅ Compliant | ✅ Compliant (CachekitIO backend) | ✅ Compliant | ❌ Not implemented | -| Test vectors in CI³ | ✅ interop/v1 (full set, incl. AAD + encryption through the real stack) | ❌ None on `main` — interop vectors land with [#33](https://github.com/cachekit-io/cachekit-rs/pull/33) | ✅ interop/v1 (full set, incl. its key vectors) + inline Python-generated AAD-construction and encryption (decrypt-Python-ciphertext) vectors | ⚠️ Pending | +| Test vectors in CI³ | ✅ interop/v1 (full set, incl. AAD + encryption through the real stack) | ✅ interop/v1 (full set) since [#33](https://github.com/cachekit-io/cachekit-rs/pull/33) | ✅ interop/v1 (full set, incl. its key vectors) + inline Python-generated AAD-construction and encryption (decrypt-Python-ciphertext) vectors | ⚠️ Pending | | Interop mode ([spec](spec/interop-mode.md), opt-in) | ✅ Merged ([#220](https://github.com/cachekit-io/cachekit-py/pull/220), unreleased) | ✅ Merged ([#33](https://github.com/cachekit-io/cachekit-rs/pull/33), unreleased) | ✅ Merged ([#71](https://github.com/cachekit-io/cachekit-ts/pull/71), unreleased) | ❌ Not implemented | > [!NOTE] From 2b5c97c10742e0df209e10128a0eff5e64b358df Mon Sep 17 00:00:00 2001 From: Ray Walker Date: Sat, 25 Jul 2026 21:06:18 +1000 Subject: [PATCH 6/6] docs(matrix): keep footnotes inside one NOTE callout (MD028) + refresh vector-CI footnote to post-LAB-423/425 reality MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CodeRabbit r3650057657: blank lines between the three consecutive '> [!NOTE]' blockquotes trip markdownlint MD028 and can render note content outside the callout. Merged into a single callout with '>'-separated paragraphs; footnote markers unchanged. While in the block: footnote 3 still claimed wire-format.json and cache-keys.json were verified by no CI — both stale since LAB-423 (tools/wire-format-reference.py in verify.yml) and LAB-425 (cache-keys vendored + CI-verified in cachekit-py#229, regenerated at v0.12.0 byte-identical to the v0.5.0 originals) closed. Co-authored-by: multica-agent --- sdk-feature-matrix.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/sdk-feature-matrix.md b/sdk-feature-matrix.md index 1e20f4e..d0b8bf6 100644 --- a/sdk-feature-matrix.md +++ b/sdk-feature-matrix.md @@ -197,12 +197,10 @@ its spec: > [!NOTE] > ¹ "N/A" for Rust *auto-mode* key generation means `cachekit-rs` implements no auto-mode key format: `get`/`set` take caller-supplied keys. The `#[cachekit]` macro mints **interop/v1** keys via `interop_key` — required, compile-time-validated `interop = "operation"` and `namespace` attributes, byte-identical across SDKs ([cachekit-rs#35](https://github.com/cachekit-io/cachekit-rs/pull/35) / LAB-424; keygen itself merged in [#33](https://github.com/cachekit-io/cachekit-rs/pull/33)). The legacy RFC §3.1.5 keygen (`key::generate_cache_key`, `{namespace}:{blake2b256-hex}` — matched no protocol format, and WAS live in every `#[cachekit]` expansion despite the audit's "unused" premise, a proc-macro grep miss) is deleted outright in #35; upgrading is a full cache invalidation for `#[cachekit]` users. `cachekit-core` is a protocol primitive library with no keygen. - -> [!NOTE] +> > ² Auto-mode **stored bytes** are SDK-internal and differ per SDK — see [wire-format.md → SDK Storage Containers](spec/wire-format.md#sdk-storage-containers-auto-mode). Python stores the ByteStorage envelope *inside* its CK v3 frame; `cachekit-rs` does not use the envelope for values at all (it uses `cachekit-core` only for encryption). Cross-SDK value compatibility is exclusively an [interop-mode](spec/interop-mode.md) property (protocol#11). - -> [!NOTE] -> ³ "Test vectors in CI" = vectors the SDK's own default CI executes. Beyond the SDKs, this repo's `verify.yml` CI-verifies `interop-mode.json`, `encryption.json`, and `python-frame.json` against reference implementations. **Not verified by any CI anywhere**: `wire-format.json` (tracked as LAB-423) and `cache-keys.json` (generated by cachekit-py v0.5.0; tracked as LAB-425). +> +> ³ "Test vectors in CI" = vectors the SDK's own default CI executes. Beyond the SDKs, this repo's `verify.yml` CI-verifies `interop-mode.json`, `encryption.json`, `python-frame.json`, and — since LAB-423 — `wire-format.json` ([`tools/wire-format-reference.py`](tools/wire-format-reference.py)) against reference implementations. `cache-keys.json` (regenerated by cachekit-py v0.12.0, byte-identical to the v0.5.0 originals) is vendored and CI-verified in cachekit-py since [cachekit-py#229](https://github.com/cachekit-io/cachekit-py/pull/229) (LAB-425). ---