From 49beaaef1fd768d55611447cf8603b6b001e98d2 Mon Sep 17 00:00:00 2001 From: Ray Walker Date: Tue, 28 Jul 2026 22:11:06 +1000 Subject: [PATCH] =?UTF-8?q?docs(protocol):=20correct=20interop/v1=20ship-s?= =?UTF-8?q?tatus=20=E2=80=94=20released=20in=20all=20three=20SDKs=20(LAB-9?= =?UTF-8?q?98)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The repo that this project calls the source of truth for cross-SDK interop still told readers interop/v1 was unimplemented. It has been released in every SDK since 2026-07-24, and the public docs site was already corrected (LAB-996 / cachekit-io/docs#24) — so the normative spec and the docs site contradicted each other, with the spec carrying the false half. Under the project's documentation gate that is a trust bug, not a stale nicety. Three surfaces corrected: - spec/interop-mode.md STATUS header: no longer "NOT yet implemented in any SDK"; states normative + shipped opt-in, with per-registry version floors. - README.md spec table: the "(specified, not yet implemented in any SDK)" parenthetical now points at the feature matrix for per-SDK floors, so the version numbers live in exactly one place. - sdk-feature-matrix.md interop row: "Merged (…, unreleased)" becomes "Released" with floors; Last updated preamble gets this change's entry. Availability is stated as FLOORS (PyPI 0.14.0+, crates.io 0.4.0+, npm 0.1.3+) rather than point-in-time snapshots. This is the lesson from LAB-663, whose seven per-registry snapshots were falsified within 25 minutes of being written when npm published 0.1.3 mid-review. A floor stays true as new versions publish; a snapshot rots on contact. Python's floor is 0.14.0, not the 0.13.0 its changelog implies: interop merged under the v0.13.0 tag, but neither 0.12.0 nor 0.13.0 was ever published to PyPI (verified against the PyPI JSON API — no release keys exist for either), so 0.14.0 is the earliest installable release containing it. Footnote 4 records this so a future reader does not "correct" the floor back to an uninstallable version from the changelog alone. Floors verified 2026-07-28 against live registries and each SDK's release notes: cachekit-py #220 in the v0.13.0 tag (first on PyPI at 0.14.0), cachekit-ts #71 in npm 0.1.3, cachekit-rs #33/#35 in crates.io 0.4.0. Deliberately NOT touched — these say "not yet implemented" and are TRUE: decisions/key-rotation.md, spec/encryption.md:346 and CHANGELOG.md:19 (key rotation, genuinely unimplemented, LAB-516), and the auto-mode non-readability statements in spec/interop-mode.md:50 and spec/wire-format.md (auto-mode is SDK-internal by design). Editing those would introduce a lie. No normative claim changed — availability wording only. No key format, AAD construction, encryption, or wire-format change, so the crypto/protocol expert-panel gate does not apply (same ruling the panel made for this class of edit on LAB-663). verify.yml's full test-vector suite was run locally and is green, as expected for a prose-only diff. Closes LAB-998 Co-authored-by: multica-agent --- README.md | 2 +- sdk-feature-matrix.md | 6 ++++-- spec/interop-mode.md | 6 +++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fe20fed..a79fe5d 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ layer's own store/retrieve flows are specified in | [spec/wire-format.md](spec/wire-format.md) | ByteStorage envelope — LZ4 block compression, xxHash3-64 integrity, decompression bomb protection | | [spec/encryption.md](spec/encryption.md) | AES-256-GCM encryption, HKDF-SHA256 key derivation, AAD v0x03, counter-based nonces, key rotation | | [spec/saas-api.md](spec/saas-api.md) | REST API endpoints, binary wire protocol, error codes, metrics headers | -| [spec/interop-mode.md](spec/interop-mode.md) | Cross-SDK cache sharing — language-neutral key format, canonical argument normalization *(specified, not yet implemented in any SDK)* | +| [spec/interop-mode.md](spec/interop-mode.md) | Cross-SDK cache sharing — language-neutral key format, canonical argument normalization *(normative; shipped opt-in in all three SDKs — see the [feature matrix](sdk-feature-matrix.md#compliance-status) for per-SDK version floors)* | | [spec/file-backend-format.md](spec/file-backend-format.md) | Shared local File backend filename, header, expiry, and fail-closed flag negotiation | | [sdk-feature-matrix.md](sdk-feature-matrix.md) | Feature parity tracking across Python, Rust, TypeScript, and PHP SDKs | | [decisions/key-rotation.md](decisions/key-rotation.md) | Decision records — master-key rotation via client-side keyring (rationale, rejected options, operator runbooks) | diff --git a/sdk-feature-matrix.md b/sdk-feature-matrix.md index 0cd3ff0..4b10d29 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-28 — 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-28 — 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* @@ -195,7 +195,7 @@ its spec: | 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) | ✅ 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 | +| Interop mode ([spec](spec/interop-mode.md), opt-in) | ✅ Released — PyPI 0.14.0+⁴ ([#220](https://github.com/cachekit-io/cachekit-py/pull/220)) | ✅ Released — crates.io 0.4.0+ ([#33](https://github.com/cachekit-io/cachekit-rs/pull/33)) | ✅ Released — npm 0.1.3+ ([#71](https://github.com/cachekit-io/cachekit-ts/pull/71)) | ❌ Not implemented | > [!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. @@ -203,6 +203,8 @@ 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). > > ³ "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). +> +> ⁴ Version cells are **floors** (`X+`), not snapshots — they stay true as new versions publish; check the registry for the current release. Python's floor is the first *installable* one: interop merged under the `v0.13.0` tag, but neither `0.12.0` nor `0.13.0` was ever published to PyPI, so `0.14.0` is the earliest PyPI release containing interop mode. Do not "correct" this to 0.13.0 from the cachekit-py changelog alone. --- diff --git a/spec/interop-mode.md b/spec/interop-mode.md index ddf50ab..3c190d6 100644 --- a/spec/interop-mode.md +++ b/spec/interop-mode.md @@ -6,7 +6,11 @@ **Language-neutral key format and plain-MessagePack value format for sharing cache entries across SDK implementations.** -> **Status**: SPECIFIED (interop/v1) — normative, NOT yet implemented in any SDK. +> **Status**: SPECIFIED (interop/v1) — normative, and **shipped opt-in in all three SDKs**: +> Python on [PyPI](https://pypi.org/project/cachekit/) 0.14.0+, TypeScript on +> [npm](https://www.npmjs.com/package/@cachekit-io/cachekit) 0.1.3+, Rust on +> [crates.io](https://crates.io/crates/cachekit-rs) 0.4.0+ — floors, not snapshots; consult +> each registry or the [SDK feature matrix](../sdk-feature-matrix.md#compliance-status) for current versions. > Design discussion: [Issue #1](https://github.com/cachekit-io/protocol/issues/1) · > Test vectors: [`test-vectors/interop-mode.json`](../test-vectors/interop-mode.json) · > Reference implementation: [`tools/interop-reference.py`](../tools/interop-reference.py)