From e51295002601eefb837e3d0b8657eaf7bab82fa1 Mon Sep 17 00:00:00 2001 From: Ray Walker Date: Tue, 22 Sep 2026 19:47:20 +1000 Subject: [PATCH 1/6] docs(matrix): hardware-acceleration detection rs/ts cells to in-review (LAB-523) The Hardware acceleration detection row said rs is core-internal and ts exposes nothing. Both are now being surfaced in open PRs; the published artifacts (crates.io 0.7.0, npm 0.1.5, checked 2026-09-22) are unchanged, so the cells move to 'in review' with the PR links, not to a checkmark, per decisions/matrix-version-verification.md. Footnote 6 rewritten to name the core accessor, its per-architecture behaviour, the informational-only contract, and the executed tests behind the wasm32/x86_64 claims. --- CHANGELOG.md | 19 +++++++++++++++++++ sdk-feature-matrix.md | 6 +++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91a0485..4e0750c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,25 @@ All notable changes to the CacheKit Protocol Specification. ## [Unreleased] +### Encryption β€” hardware-acceleration detection surfacing in rs/ts (LAB-523) + +- [Feature matrix](sdk-feature-matrix.md#encryption) Hardware acceleration + detection row: Rust and TypeScript move from "core-internal, not re-exported" / + "not exposed" to 🚧 in review β€” [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80) + (`EncryptionLayer::hardware_acceleration_enabled()`, `SecureCache` forwarder) + and [cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132) + (`TenantKeys.hardwareAccelerationEnabled()` on both bindings, + `EncryptionManagerCore.isHardwareAccelerated()`). Published artifacts are + unchanged: crates.io 0.7.0 and npm 0.1.5 (checked 2026-09-22) still expose + nothing, so the cells are not βœ… β€” they flip to 🚧 unreleased on merge and to + βœ… with a version floor on release, per + [decisions/matrix-version-verification.md](decisions/matrix-version-verification.md). +- Footnote ⁢ rewritten: names the core accessor and its per-architecture + behaviour (runtime probe on x86/x86_64, compile-time on aarch64, always `false` + on wasm32), states the flag is informational only, drops the stale line + numbers, and cites the executed tests behind the wasm32 and x86_64 claims + rather than a traced mechanism. + ### Encryption β€” keyring conformance vectors + status reconciliation (LAB-687) - [`test-vectors/encryption.json`](test-vectors/encryption.json) gains a `keyring` diff --git a/sdk-feature-matrix.md b/sdk-feature-matrix.md index 8c8e0f9..05765a4 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-09-02 β€” LAB-687 keyring conformance and documentation reconciliation (following LAB-1400's matrix baseline correction). 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-09-22 β€” LAB-523 hardware-acceleration detection: Rust and TypeScript cells to 🚧 in review (following LAB-687's keyring reconciliation and LAB-1400's matrix baseline correction). 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 `::secure` preset and Rust sync support (both βœ… β†’ do not exist), Builder API (py/ts βœ… β†’ ❌), Hardware acceleration (rs βœ… β†’ not re-exported, ts N/A β†’ ❌), TypeScript Arrow (πŸ”œ β†’ ❌), Python's encrypted read path (documented fail-closed β†’ **fail-open by default**), and `cache.secure.wrap()` in TypeScript (implied encryption β†’ **no guarantee**). The TypeScript protocol-1.1 `bin` rollout also reversed twice in two days: it is **not** shipped on either ts path (per-artifact evidence in the [cachekit-core architecture note](#architecture-notes)).* @@ -69,7 +69,7 @@ | Key rotation | βœ… 0.18.0+ β€” keyring; derived-key fingerprint selection⁡ | 🚧 unreleased β€” keyring on `main` ([cachekit-rs#63](https://github.com/cachekit-io/cachekit-rs/pull/63)); absent from crates.io 0.7.0⁡ | 🚧 unreleased β€” keyring on `main` ([cachekit-ts#103](https://github.com/cachekit-io/cachekit-ts/pull/103)); absent from npm 0.1.5⁡ | ❌ | | **Tamper / wrong-key failure mode** | ⚠️ **fail-OPEN by default** β€” warn + recompute; switchable with `CACHEKIT_ENCRYPTION_FAIL_CLOSED=true`¹⁸ | βœ… **Fails closed** β€” `decrypt(…)?` propagates (`client.rs:830`, `:847`), and `#[cachekit(secure)]` emits no fail-open arm (`cachekit-macros/src/lib.rs:439-451`) | ⚠️ **fail-OPEN on reads, silently drops writes, not switchable**⁸ | β€” | | **Does the `secure` API enforce encryption?** | βœ… Raises without a key | βœ… `secure()` returns `Err` | ❌ **`cache.secure.wrap()` is an unconditional alias for `wrap()`** β€” silently caches plaintext on any instance not built by `createCache.secure()` (LAB-513, CWE-311); see [Intent-preset semantics](#intent-preset-semantics-parity-not-presence) | β€” | -| Hardware acceleration detection | βœ… surfaced (`hardware_acceleration_enabled()`) | ⚠️ core-internal, not re-exported⁢ | ❌ not exposed⁢ | N/A | +| Hardware acceleration detection | βœ… surfaced (`hardware_acceleration_enabled()`) | 🚧 in review β€” `EncryptionLayer::hardware_acceleration_enabled()` + `SecureCache` forwarder in [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80); crates.io 0.7.0 has only the core-internal probe⁢ | 🚧 in review β€” `TenantKeys.hardwareAccelerationEnabled()` + `isHardwareAccelerated()` in [cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132); npm 0.1.5 exposes nothing⁢ | N/A | | Counter-based nonces | βœ… via Rust | βœ… | βœ… via NAPI (Rust) | ❌ use random | > [!IMPORTANT] @@ -90,7 +90,7 @@ > > Degradation is on unless explicitly disabled (`degradationEnabled = config.degradation !== false`, `reliability/executor.ts:39`) and `createCache.secure()` / `.production()` / `.io()` all set it `true` (`intents-core.ts:186`); only `minimal` sets `false`, and `minimal` carries no encryption. **There is no `failClosed` option anywhere in cachekit-ts** β€” Python's `CACHEKIT_ENCRYPTION_FAIL_CLOSED` has no counterpart, so the only lever is `reliability: { degradation: false }`, which also gives up backend-outage degradation. If you rely on a thrown error as your tamper, wrong-key or nonce alarm, TypeScript raises none; the sole signal is the `errors_total` counter. > -> ⁢ Runtime AES detection (`is_x86_feature_detected!("aes")`, `cachekit-core/src/encryption/core.rs:243`) lives in the shared core and is **surfaced only by Python** (`encryption_wrapper.py:583`). cachekit-rs never re-exports it β€” the SDK calls the non-metrics encrypt/decrypt entry points β€” and the TypeScript NAPI layer exposes nothing β€” `N/A` there was wrong, since ts runs the same Rust core. Tracked as LAB-523. +> ⁢ AES hardware detection lives in the shared core β€” `ZeroKnowledgeEncryptor::hardware_acceleration_enabled()` in `cachekit-core/src/encryption/core.rs`: a runtime `is_x86_feature_detected!("aes")` probe on x86/x86_64, compile-time target features on aarch64, always `false` on wasm32 (no AES instructions to detect). It is **informational only** β€” `ring`/`aes-gcm` choose their implementation independently of the flag. Published artifacts (registries checked 2026-09-22): Python surfaces it (`EncryptionWrapper.hardware_acceleration_enabled`, in `get_info()` and the init log); cachekit-rs 0.7.0 never re-exports it and `@cachekit-io/cachekit` 0.1.5 exposes nothing on either binding β€” `N/A` for TypeScript was wrong, since both bindings run the same Rust core. The Rust re-export (`EncryptionLayer::hardware_acceleration_enabled()`, forwarded by `SecureCache`, carried in the layer's `Debug` output) and the TypeScript surface (`TenantKeys.hardwareAccelerationEnabled()` on the NAPI and wasm bindings; `EncryptionManagerCore.isHardwareAccelerated()`, which initialises on demand and returns `null` β€” unknown, not `false` β€” when the installed binding predates the accessor) are open in [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80) and [cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132): not on `main`, not released. The wasm32 always-`false` claim is asserted by cachekit-ts's workerd test (`encryption.protocol.workers.test.ts`), and the Rust accessor is pinned to `is_x86_feature_detected!("aes")` on x86_64 in `encryption.rs`'s unit tests. Cells flip to 🚧 unreleased on merge and to βœ… with a version floor on release, per [decisions/matrix-version-verification.md](decisions/matrix-version-verification.md). Tracked as LAB-523. --- From 526910cc410affb8383fb774bde228483bee99e4 Mon Sep 17 00:00:00 2001 From: Ray Walker Date: Tue, 22 Sep 2026 20:01:30 +1000 Subject: [PATCH 2/6] docs(matrix): state the aarch64 detection caveat in footnote 6 (LAB-523) Review of the SDK PRs found core's aarch64 branch returns cfg!(target_feature = "neon"), which every aarch64 target enables, so the flag is true on every aarch64 build regardless of the Crypto Extension. The footnote said 'compile-time target features on aarch64', which is technically what it is and practically misleading; it now says what a reader on a Cortex-A72 board needs to know and names the core follow-up. --- CHANGELOG.md | 9 +++++---- sdk-feature-matrix.md | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e0750c..22fa8f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,10 +18,11 @@ All notable changes to the CacheKit Protocol Specification. βœ… with a version floor on release, per [decisions/matrix-version-verification.md](decisions/matrix-version-verification.md). - Footnote ⁢ rewritten: names the core accessor and its per-architecture - behaviour (runtime probe on x86/x86_64, compile-time on aarch64, always `false` - on wasm32), states the flag is informational only, drops the stale line - numbers, and cites the executed tests behind the wasm32 and x86_64 claims - rather than a traced mechanism. + behaviour (runtime probe on x86/x86_64; `true` on every aarch64 build because + core tests NEON, not the Crypto Extension β€” core fix tracked as LAB-4650; + always `false` on wasm32), states the flag is informational only, drops the + stale line numbers, and cites the executed tests behind the wasm32 and x86_64 + claims rather than a traced mechanism. ### Encryption β€” keyring conformance vectors + status reconciliation (LAB-687) diff --git a/sdk-feature-matrix.md b/sdk-feature-matrix.md index 05765a4..0632445 100644 --- a/sdk-feature-matrix.md +++ b/sdk-feature-matrix.md @@ -90,7 +90,7 @@ > > Degradation is on unless explicitly disabled (`degradationEnabled = config.degradation !== false`, `reliability/executor.ts:39`) and `createCache.secure()` / `.production()` / `.io()` all set it `true` (`intents-core.ts:186`); only `minimal` sets `false`, and `minimal` carries no encryption. **There is no `failClosed` option anywhere in cachekit-ts** β€” Python's `CACHEKIT_ENCRYPTION_FAIL_CLOSED` has no counterpart, so the only lever is `reliability: { degradation: false }`, which also gives up backend-outage degradation. If you rely on a thrown error as your tamper, wrong-key or nonce alarm, TypeScript raises none; the sole signal is the `errors_total` counter. > -> ⁢ AES hardware detection lives in the shared core β€” `ZeroKnowledgeEncryptor::hardware_acceleration_enabled()` in `cachekit-core/src/encryption/core.rs`: a runtime `is_x86_feature_detected!("aes")` probe on x86/x86_64, compile-time target features on aarch64, always `false` on wasm32 (no AES instructions to detect). It is **informational only** β€” `ring`/`aes-gcm` choose their implementation independently of the flag. Published artifacts (registries checked 2026-09-22): Python surfaces it (`EncryptionWrapper.hardware_acceleration_enabled`, in `get_info()` and the init log); cachekit-rs 0.7.0 never re-exports it and `@cachekit-io/cachekit` 0.1.5 exposes nothing on either binding β€” `N/A` for TypeScript was wrong, since both bindings run the same Rust core. The Rust re-export (`EncryptionLayer::hardware_acceleration_enabled()`, forwarded by `SecureCache`, carried in the layer's `Debug` output) and the TypeScript surface (`TenantKeys.hardwareAccelerationEnabled()` on the NAPI and wasm bindings; `EncryptionManagerCore.isHardwareAccelerated()`, which initialises on demand and returns `null` β€” unknown, not `false` β€” when the installed binding predates the accessor) are open in [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80) and [cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132): not on `main`, not released. The wasm32 always-`false` claim is asserted by cachekit-ts's workerd test (`encryption.protocol.workers.test.ts`), and the Rust accessor is pinned to `is_x86_feature_detected!("aes")` on x86_64 in `encryption.rs`'s unit tests. Cells flip to 🚧 unreleased on merge and to βœ… with a version floor on release, per [decisions/matrix-version-verification.md](decisions/matrix-version-verification.md). Tracked as LAB-523. +> ⁢ AES hardware detection lives in the shared core β€” `ZeroKnowledgeEncryptor::hardware_acceleration_enabled()` in `cachekit-core/src/encryption/core.rs`: a runtime `is_x86_feature_detected!("aes")` probe on x86/x86_64; on aarch64 it returns `cfg!(target_feature = "neon")`, which every aarch64 target enables, so it is `true` on every aarch64 build whether or not the CPU has the Crypto Extension β€” a Cortex-A72-class board reports `true` while `ring` runs software AES (core fix tracked as LAB-4650); always `false` on wasm32 (no AES instructions to detect). It is **informational only** β€” `ring`/`aes-gcm` choose their implementation independently of the flag. Published artifacts (registries checked 2026-09-22): Python surfaces it (`EncryptionWrapper.hardware_acceleration_enabled`, in `get_info()` and the init log); cachekit-rs 0.7.0 never re-exports it and `@cachekit-io/cachekit` 0.1.5 exposes nothing on either binding β€” `N/A` for TypeScript was wrong, since both bindings run the same Rust core. The Rust re-export (`EncryptionLayer::hardware_acceleration_enabled()`, forwarded by `SecureCache`) and the TypeScript surface (`TenantKeys.hardwareAccelerationEnabled()` on the NAPI and wasm bindings; `EncryptionManagerCore.isHardwareAccelerated()`, which initialises on demand and returns `null` β€” unknown, not `false` β€” when the installed binding predates the accessor) are open in [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80) and [cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132): not on `main`, not released. The wasm32 always-`false` claim is asserted by cachekit-ts's workerd test (`encryption.protocol.workers.test.ts`), and the Rust accessor is pinned to `is_x86_feature_detected!("aes")` on x86_64 in `encryption.rs`'s unit tests. Cells flip to 🚧 unreleased on merge and to βœ… with a version floor on release, per [decisions/matrix-version-verification.md](decisions/matrix-version-verification.md). Tracked as LAB-523. --- From be6261e3870a70f98a4d71e7be1cd833ac507cc9 Mon Sep 17 00:00:00 2001 From: Ray Walker Date: Wed, 23 Sep 2026 17:08:29 +1000 Subject: [PATCH 3/6] =?UTF-8?q?fix:=20address=20coderabbit=20review=20?= =?UTF-8?q?=E2=80=94=20scope=20aarch64=20NEON=20caveat=20to=20published=20?= =?UTF-8?q?core=20through=200.6.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CodeRabbit-Resolved: sdk-feature-matrix.md:93:Update the hardware-detectio --- CHANGELOG.md | 3 ++- sdk-feature-matrix.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b323bba..e34b4ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,8 @@ All notable changes to the CacheKit Protocol Specification. [decisions/matrix-version-verification.md](decisions/matrix-version-verification.md). - Footnote ⁢ rewritten: names the core accessor and its per-architecture behaviour (runtime probe on x86/x86_64; `true` on every aarch64 build because - core tests NEON, not the Crypto Extension β€” core fix tracked as LAB-4650; + core tests NEON, not the Crypto Extension β€” true of every published core + through 0.6.0; the LAB-4650 fix is merged to core `main` but unreleased; always `false` on wasm32), states the flag is informational only, drops the stale line numbers, and cites the executed tests behind the wasm32 and x86_64 claims rather than a traced mechanism. diff --git a/sdk-feature-matrix.md b/sdk-feature-matrix.md index b339d57..408569f 100644 --- a/sdk-feature-matrix.md +++ b/sdk-feature-matrix.md @@ -90,7 +90,7 @@ > > Degradation is on unless explicitly disabled (`degradationEnabled = config.degradation !== false`, `reliability/executor.ts:39`) and `createCache.secure()` / `.production()` / `.io()` all set it `true` (`intents-core.ts:186`); only `minimal` sets `false`, and `minimal` carries no encryption. **There is no `failClosed` option anywhere in cachekit-ts** β€” Python's `CACHEKIT_ENCRYPTION_FAIL_CLOSED` has no counterpart, so the only lever is `reliability: { degradation: false }`, which also gives up backend-outage degradation. If you rely on a thrown error as your tamper, wrong-key or nonce alarm, TypeScript raises none; the sole signal is the `errors_total` counter. > -> ⁢ AES hardware detection lives in the shared core β€” `ZeroKnowledgeEncryptor::hardware_acceleration_enabled()` in `cachekit-core/src/encryption/core.rs`: a runtime `is_x86_feature_detected!("aes")` probe on x86/x86_64; on aarch64 it returns `cfg!(target_feature = "neon")`, which every aarch64 target enables, so it is `true` on every aarch64 build whether or not the CPU has the Crypto Extension β€” a Cortex-A72-class board reports `true` while `ring` runs software AES (core fix tracked as LAB-4650); always `false` on wasm32 (no AES instructions to detect). It is **informational only** β€” `ring`/`aes-gcm` choose their implementation independently of the flag. Published artifacts (registries checked 2026-09-22): Python surfaces it (`EncryptionWrapper.hardware_acceleration_enabled`, in `get_info()` and the init log); cachekit-rs 0.7.0 never re-exports it and `@cachekit-io/cachekit` 0.1.5 exposes nothing on either binding β€” `N/A` for TypeScript was wrong, since both bindings run the same Rust core. The Rust re-export (`EncryptionLayer::hardware_acceleration_enabled()`, forwarded by `SecureCache`) and the TypeScript surface (`TenantKeys.hardwareAccelerationEnabled()` on the NAPI and wasm bindings; `EncryptionManagerCore.isHardwareAccelerated()`, which initialises on demand and returns `null` β€” unknown, not `false` β€” when the installed binding predates the accessor) are open in [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80) and [cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132): not on `main`, not released. The wasm32 always-`false` claim is asserted by cachekit-ts's workerd test (`encryption.protocol.workers.test.ts`), and the Rust accessor is pinned to `is_x86_feature_detected!("aes")` on x86_64 in `encryption.rs`'s unit tests. Cells flip to 🚧 unreleased on merge and to βœ… with a version floor on release, per [decisions/matrix-version-verification.md](decisions/matrix-version-verification.md). Tracked as LAB-523. +> ⁢ AES hardware detection lives in the shared core β€” `ZeroKnowledgeEncryptor::hardware_acceleration_enabled()` in `cachekit-core/src/encryption/core.rs`: a runtime `is_x86_feature_detected!("aes")` probe on x86/x86_64; on aarch64 it returns `cfg!(target_feature = "neon")`, which every aarch64 target enables, so it is `true` on every aarch64 build whether or not the CPU has the Crypto Extension β€” a Cortex-A72-class board reports `true` while `ring` runs software AES. That holds for every published `cachekit-core` through 0.6.0 (0.4.0 and 0.6.0 included); the fix, [cachekit-core#77](https://github.com/cachekit-io/cachekit-core/pull/77) (LAB-4650), is merged to core `main` but unreleased; always `false` on wasm32 (no AES instructions to detect). It is **informational only** β€” `ring`/`aes-gcm` choose their implementation independently of the flag. Published artifacts (registries checked 2026-09-22): Python surfaces it (`EncryptionWrapper.hardware_acceleration_enabled`, in `get_info()` and the init log); cachekit-rs 0.7.0 never re-exports it and `@cachekit-io/cachekit` 0.1.5 exposes nothing on either binding β€” `N/A` for TypeScript was wrong, since both bindings run the same Rust core. The Rust re-export (`EncryptionLayer::hardware_acceleration_enabled()`, forwarded by `SecureCache`) and the TypeScript surface (`TenantKeys.hardwareAccelerationEnabled()` on the NAPI and wasm bindings; `EncryptionManagerCore.isHardwareAccelerated()`, which initialises on demand and returns `null` β€” unknown, not `false` β€” when the installed binding predates the accessor) are open in [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80) and [cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132): not on `main`, not released. The wasm32 always-`false` claim is asserted by cachekit-ts's workerd test (`encryption.protocol.workers.test.ts`), and the Rust accessor is pinned to `is_x86_feature_detected!("aes")` on x86_64 in `encryption.rs`'s unit tests. Cells flip to 🚧 unreleased on merge and to βœ… with a version floor on release, per [decisions/matrix-version-verification.md](decisions/matrix-version-verification.md). Tracked as LAB-523. --- From 34e5bea6ad83fc191a634fed94045f033c8d2440 Mon Sep 17 00:00:00 2001 From: Ray Walker Date: Sun, 27 Sep 2026 19:08:21 +1000 Subject: [PATCH 4/6] docs(matrix): TypeScript hardware-acceleration cell to unreleased (LAB-523) cachekit-ts#132 merged to main on 2026-09-25, so the TypeScript cell, footnote 6 and the CHANGELOG entry no longer describe it as in review or "not on main". npm still ships 0.1.5, which has no accessor, so the cell moves to unreleased rather than to a version floor. cachekit-rs#80 is still open, so the Rust cell stays in review. Published artifacts were re-checked on 2026-09-27: crates.io cachekit-rs 0.7.0, cachekit-core 0.6.0, npm 0.1.5. --- CHANGELOG.md | 17 +++++++++-------- sdk-feature-matrix.md | 6 +++--- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f6adaa3..283163a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,15 +7,16 @@ All notable changes to the CacheKit Protocol Specification. ### Encryption β€” hardware-acceleration detection surfacing in rs/ts (LAB-523) - [Feature matrix](sdk-feature-matrix.md#encryption) Hardware acceleration - detection row: Rust and TypeScript move from "core-internal, not re-exported" / - "not exposed" to 🚧 in review β€” [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80) - (`EncryptionLayer::hardware_acceleration_enabled()`, `SecureCache` forwarder) - and [cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132) + detection row: Rust moves from "core-internal, not re-exported" to 🚧 in + review β€” [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80) + (`EncryptionLayer::hardware_acceleration_enabled()`, `SecureCache` forwarder); + TypeScript moves from "not exposed" to 🚧 unreleased β€” + [cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132) (`TenantKeys.hardwareAccelerationEnabled()` on both bindings, - `EncryptionManagerCore.isHardwareAccelerated()`). Published artifacts are - unchanged: crates.io 0.7.0 and npm 0.1.5 (checked 2026-09-22) still expose - nothing, so the cells are not βœ… β€” they flip to 🚧 unreleased on merge and to - βœ… with a version floor on release, per + `EncryptionManagerCore.isHardwareAccelerated()`) is merged to `main`. + Published artifacts are unchanged: crates.io 0.7.0 and npm 0.1.5 (checked + 2026-09-27) still expose nothing, so neither cell is βœ… β€” Rust flips to 🚧 + unreleased on merge, and each flips to βœ… with a version floor on release, per [decisions/matrix-version-verification.md](decisions/matrix-version-verification.md). - Footnote ⁢ rewritten: names the core accessor and its per-architecture behaviour (runtime probe on x86/x86_64; `true` on every aarch64 build because diff --git a/sdk-feature-matrix.md b/sdk-feature-matrix.md index 9bfd8ac..85ff161 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-09-22 β€” LAB-523 hardware-acceleration detection: Rust and TypeScript cells to 🚧 in review (following LAB-687's keyring reconciliation and LAB-1400's matrix baseline correction). 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-09-27 β€” LAB-523 hardware-acceleration detection: Rust cell to 🚧 in review, TypeScript to 🚧 unreleased (following LAB-687's keyring reconciliation and LAB-1400's matrix baseline correction). 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 `::secure` preset and Rust sync support (both βœ… β†’ do not exist), Builder API (py/ts βœ… β†’ ❌), Hardware acceleration (rs βœ… β†’ not re-exported, ts N/A β†’ ❌), 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 is **not** shipped on either ts path (per-artifact evidence in the [cachekit-core architecture note](#architecture-notes)).* @@ -83,7 +83,7 @@ | Key rotation | βœ… 0.18.0+ β€” keyring; derived-key fingerprint selection⁡ | 🚧 unreleased β€” keyring on `main` ([cachekit-rs#63](https://github.com/cachekit-io/cachekit-rs/pull/63)); absent from crates.io 0.7.0⁡ | 🚧 unreleased β€” keyring on `main` ([cachekit-ts#103](https://github.com/cachekit-io/cachekit-ts/pull/103)); absent from npm 0.1.5⁡ | ❌ | | **Tamper / wrong-key failure mode** | ⚠️ **fail-OPEN by default** β€” warn + recompute; switchable with `CACHEKIT_ENCRYPTION_FAIL_CLOSED=true`¹⁸ | βœ… **Fails closed** β€” `decrypt(…)?` propagates (`client.rs:830`, `:847`), and `#[cachekit(secure)]` emits no fail-open arm (`cachekit-macros/src/lib.rs:439-451`) | ⚠️ **fail-OPEN on reads, silently drops writes, not switchable**⁸ | β€” | | **Does the `secure` API enforce encryption?** | βœ… Raises without a key | βœ… `secure()` returns `Err` | βœ… **`cache.secure.wrap()` throws `ConfigurationError` at wrap time** on any instance without `encryption` configured β€” instance and `withExecutionContext(ctx)` view alike (LAB-513; before it, an unconditional alias for `wrap()`, so on an instance without configured encryption a "secure" registration cached plaintext, CWE-311); see [Intent-preset semantics](#intent-preset-semantics-parity-not-presence) | β€” | -| Hardware acceleration detection | βœ… surfaced (`hardware_acceleration_enabled()`) | 🚧 in review β€” `EncryptionLayer::hardware_acceleration_enabled()` + `SecureCache` forwarder in [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80); crates.io 0.7.0 has only the core-internal probe⁢ | 🚧 in review β€” `TenantKeys.hardwareAccelerationEnabled()` + `isHardwareAccelerated()` in [cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132); npm 0.1.5 exposes nothing⁢ | N/A | +| Hardware acceleration detection | βœ… surfaced (`hardware_acceleration_enabled()`) | 🚧 in review β€” `EncryptionLayer::hardware_acceleration_enabled()` + `SecureCache` forwarder in [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80); crates.io 0.7.0 has only the core-internal probe⁢ | 🚧 unreleased β€” `TenantKeys.hardwareAccelerationEnabled()` + `isHardwareAccelerated()` on `main` ([cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132)); absent from npm 0.1.5⁢ | N/A | | Counter-based nonces | βœ… via Rust | βœ… | βœ… via NAPI (Rust) | ❌ use random | > [!IMPORTANT] @@ -104,7 +104,7 @@ > > Degradation is on unless explicitly disabled (`degradationEnabled = config.degradation !== false`, `reliability/executor.ts:39`) and `createCache.secure()` / `.production()` / `.io()` all set it `true` (`intents-core.ts:186`); only `minimal` sets `false`, and `minimal` carries no encryption. **There is no `failClosed` option anywhere in cachekit-ts** β€” Python's `CACHEKIT_ENCRYPTION_FAIL_CLOSED` has no counterpart, so the only lever is `reliability: { degradation: false }`, which also gives up backend-outage degradation. If you rely on a thrown error as your tamper, wrong-key or nonce alarm, TypeScript raises none; the sole signal is the `errors_total` counter. > -> ⁢ AES hardware detection lives in the shared core β€” `ZeroKnowledgeEncryptor::hardware_acceleration_enabled()` in `cachekit-core/src/encryption/core.rs`: a runtime `is_x86_feature_detected!("aes")` probe on x86/x86_64; on aarch64 it returns `cfg!(target_feature = "neon")`, which every aarch64 target enables, so it is `true` on every aarch64 build whether or not the CPU has the Crypto Extension β€” a Cortex-A72-class board reports `true` while `ring` runs software AES. That holds for every published `cachekit-core` through 0.6.0 (0.4.0 and 0.6.0 included); the fix, [cachekit-core#77](https://github.com/cachekit-io/cachekit-core/pull/77) (LAB-4650), is merged to core `main` but unreleased; always `false` on wasm32 (no AES instructions to detect). It is **informational only** β€” `ring`/`aes-gcm` choose their implementation independently of the flag. Published artifacts (registries checked 2026-09-22): Python surfaces it (`EncryptionWrapper.hardware_acceleration_enabled`, in `get_info()` and the init log); cachekit-rs 0.7.0 never re-exports it and `@cachekit-io/cachekit` 0.1.5 exposes nothing on either binding β€” `N/A` for TypeScript was wrong, since both bindings run the same Rust core. The Rust re-export (`EncryptionLayer::hardware_acceleration_enabled()`, forwarded by `SecureCache`) and the TypeScript surface (`TenantKeys.hardwareAccelerationEnabled()` on the NAPI and wasm bindings; `EncryptionManagerCore.isHardwareAccelerated()`, which initialises on demand and returns `null` β€” unknown, not `false` β€” when the installed binding predates the accessor) are open in [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80) and [cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132): not on `main`, not released. The wasm32 always-`false` claim is asserted by cachekit-ts's workerd test (`encryption.protocol.workers.test.ts`), and the Rust accessor is pinned to `is_x86_feature_detected!("aes")` on x86_64 in `encryption.rs`'s unit tests. Cells flip to 🚧 unreleased on merge and to βœ… with a version floor on release, per [decisions/matrix-version-verification.md](decisions/matrix-version-verification.md). Tracked as LAB-523. +> ⁢ AES hardware detection lives in the shared core β€” `ZeroKnowledgeEncryptor::hardware_acceleration_enabled()` in `cachekit-core/src/encryption/core.rs`: a runtime `is_x86_feature_detected!("aes")` probe on x86/x86_64; on aarch64 it returns `cfg!(target_feature = "neon")`, which every aarch64 target enables, so it is `true` on every aarch64 build whether or not the CPU has the Crypto Extension β€” a Cortex-A72-class board reports `true` while `ring` runs software AES. That holds for every published `cachekit-core` through 0.6.0 (0.4.0 and 0.6.0 included); the fix, [cachekit-core#77](https://github.com/cachekit-io/cachekit-core/pull/77) (LAB-4650), is merged to core `main` but unreleased; always `false` on wasm32 (no AES instructions to detect). It is **informational only** β€” `ring`/`aes-gcm` choose their implementation independently of the flag. Published artifacts (registries checked 2026-09-22): Python surfaces it (`EncryptionWrapper.hardware_acceleration_enabled`, in `get_info()` and the init log); cachekit-rs 0.7.0 never re-exports it and `@cachekit-io/cachekit` 0.1.5 exposes nothing on either binding β€” `N/A` for TypeScript was wrong, since both bindings run the same Rust core. The Rust re-export (`EncryptionLayer::hardware_acceleration_enabled()`, forwarded by `SecureCache`) is open in [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80): not on `main`, not released. The TypeScript surface (`TenantKeys.hardwareAccelerationEnabled()` on the NAPI and wasm bindings; `EncryptionManagerCore.isHardwareAccelerated()`, which initialises on demand and returns `null` β€” unknown, not `false` β€” when the installed binding predates the accessor) is merged to `main` in [cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132) but not released. The wasm32 always-`false` claim is asserted by cachekit-ts's workerd test (`encryption.protocol.workers.test.ts`), and the Rust accessor is pinned to `is_x86_feature_detected!("aes")` on x86_64 in `encryption.rs`'s unit tests. Cells flip to 🚧 unreleased on merge and to βœ… with a version floor on release, per [decisions/matrix-version-verification.md](decisions/matrix-version-verification.md). Tracked as LAB-523. --- From 63aebd9604b559f374c56900055114f1c01b12ac Mon Sep 17 00:00:00 2001 From: Ray Walker Date: Tue, 29 Sep 2026 14:00:05 +1000 Subject: [PATCH 5/6] docs(matrix): correct hardware-acceleration row names, dates and caveat reach (LAB-523) - Python cell: name the property EncryptionWrapper.hardware_acceleration_enabled and mark it with footnote 6. Python calls the same core accessor, so the aarch64 caveat applies to it too. - TypeScript: name the exported EncryptionManager, not EncryptionManagerCore. - One registry re-check date (2026-09-29) across footnote 6, the fragment and the last-updated line. - Footnote 6: the Rust test is on cachekit-rs#80, not main; name the Raspberry Pi 4 rather than all Cortex-A72 parts; only the Rust cell still flips on merge. - Drop the accessor names from the rs/ts cells (footnote 6 carries them) and the restated cell states from the last-updated line and the fragment. --- changelog.d/20260929_lab-523.md | 16 +++++----------- sdk-feature-matrix.md | 6 +++--- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/changelog.d/20260929_lab-523.md b/changelog.d/20260929_lab-523.md index dc71eb5..2b850f4 100644 --- a/changelog.d/20260929_lab-523.md +++ b/changelog.d/20260929_lab-523.md @@ -7,15 +7,9 @@ TypeScript moves from "not exposed" to 🚧 unreleased β€” [cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132) (`TenantKeys.hardwareAccelerationEnabled()` on both bindings, - `EncryptionManagerCore.isHardwareAccelerated()`) is merged to `main`. + `EncryptionManager.isHardwareAccelerated()`) is merged to `main`. Published artifacts are unchanged: crates.io 0.7.0 and npm 0.1.5 (checked - 2026-09-27) still expose nothing, so neither cell is βœ… β€” Rust flips to 🚧 - unreleased on merge, and each flips to βœ… with a version floor on release, per - [decisions/matrix-version-verification.md](decisions/matrix-version-verification.md). -- Footnote ⁢ rewritten: names the core accessor and its per-architecture - behaviour (runtime probe on x86/x86_64; `true` on every aarch64 build because - core tests NEON, not the Crypto Extension β€” true of every published core - through 0.6.0; the LAB-4650 fix is merged to core `main` but unreleased; - always `false` on wasm32), states the flag is informational only, drops the - stale line numbers, and cites the executed tests behind the wasm32 and x86_64 - claims rather than a traced mechanism. + 2026-09-29) still expose nothing, so neither cell is βœ…. +- Footnote ⁢, now also marked on the Python cell: the flag is informational + only, and it reads `true` on every aarch64 build through `cachekit-core` 0.6.0; + the fix is merged to core `main` but unreleased. diff --git a/sdk-feature-matrix.md b/sdk-feature-matrix.md index 5e56700..6a774c5 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-09-27 β€” LAB-523 hardware-acceleration detection: Rust cell to 🚧 in review, TypeScript to 🚧 unreleased (following LAB-687's keyring reconciliation and LAB-1400's matrix baseline correction). 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-09-29 β€” LAB-523 hardware-acceleration detection (following LAB-687's keyring reconciliation and LAB-1400's matrix baseline correction). 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 `::secure` preset and Rust sync support (both βœ… β†’ do not exist), Builder API (py/ts βœ… β†’ ❌), Hardware acceleration (rs βœ… β†’ not re-exported, ts N/A β†’ ❌), 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 is **not** shipped on either ts path (per-artifact evidence in the [cachekit-core architecture note](#architecture-notes)).* @@ -83,7 +83,7 @@ | Key rotation | βœ… 0.18.0+ β€” keyring; derived-key fingerprint selection⁡ | 🚧 unreleased β€” keyring on `main` ([cachekit-rs#63](https://github.com/cachekit-io/cachekit-rs/pull/63)); absent from crates.io 0.7.0⁡ | 🚧 unreleased β€” keyring on `main` ([cachekit-ts#103](https://github.com/cachekit-io/cachekit-ts/pull/103)); absent from npm 0.1.5⁡ | ❌ | | **Tamper / wrong-key failure mode** | ⚠️ **fail-OPEN by default** β€” warn + recompute; switchable with `CACHEKIT_ENCRYPTION_FAIL_CLOSED=true`¹⁸ | βœ… **Fails closed** β€” `decrypt(…)?` propagates (`client.rs:830`, `:847`), and `#[cachekit(secure)]` emits no fail-open arm (`cachekit-macros/src/lib.rs:439-451`) | ⚠️ **fail-OPEN on reads, silently drops writes, not switchable**⁸ | β€” | | **Does the `secure` API enforce encryption?** | βœ… Raises without a key | βœ… `secure()` returns `Err` | βœ… **`cache.secure.wrap()` throws `ConfigurationError` at wrap time** on any instance without `encryption` configured β€” instance and `withExecutionContext(ctx)` view alike (LAB-513; before it, an unconditional alias for `wrap()`, so on an instance without configured encryption a "secure" registration cached plaintext, CWE-311); see [Intent-preset semantics](#intent-preset-semantics-parity-not-presence) | β€” | -| Hardware acceleration detection | βœ… surfaced (`hardware_acceleration_enabled()`) | 🚧 in review β€” `EncryptionLayer::hardware_acceleration_enabled()` + `SecureCache` forwarder in [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80); crates.io 0.7.0 has only the core-internal probe⁢ | 🚧 unreleased β€” `TenantKeys.hardwareAccelerationEnabled()` + `isHardwareAccelerated()` on `main` ([cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132)); absent from npm 0.1.5⁢ | N/A | +| Hardware acceleration detection | βœ… surfaced (`EncryptionWrapper.hardware_acceleration_enabled`)⁢ | 🚧 in review β€” [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80); absent from crates.io 0.7.0⁢ | 🚧 unreleased β€” on `main` ([cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132)); absent from npm 0.1.5⁢ | N/A | | Counter-based nonces | βœ… via Rust | βœ… | βœ… via NAPI (Rust) | ❌ use random | > [!IMPORTANT] @@ -104,7 +104,7 @@ > > Degradation is on unless explicitly disabled (`degradationEnabled = config.degradation !== false`, `reliability/executor.ts:39`) and `createCache.secure()` / `.production()` / `.io()` all set it `true` (`intents-core.ts:186`); only `minimal` sets `false`, and `minimal` carries no encryption. **There is no `failClosed` option anywhere in cachekit-ts** β€” Python's `CACHEKIT_ENCRYPTION_FAIL_CLOSED` has no counterpart, so the only lever is `reliability: { degradation: false }`, which also gives up backend-outage degradation. If you rely on a thrown error as your tamper, wrong-key or nonce alarm, TypeScript raises none; the sole signal is the `errors_total` counter. > -> ⁢ AES hardware detection lives in the shared core β€” `ZeroKnowledgeEncryptor::hardware_acceleration_enabled()` in `cachekit-core/src/encryption/core.rs`: a runtime `is_x86_feature_detected!("aes")` probe on x86/x86_64; on aarch64 it returns `cfg!(target_feature = "neon")`, which every aarch64 target enables, so it is `true` on every aarch64 build whether or not the CPU has the Crypto Extension β€” a Cortex-A72-class board reports `true` while `ring` runs software AES. That holds for every published `cachekit-core` through 0.6.0 (0.4.0 and 0.6.0 included); the fix, [cachekit-core#77](https://github.com/cachekit-io/cachekit-core/pull/77) (LAB-4650), is merged to core `main` but unreleased; always `false` on wasm32 (no AES instructions to detect). It is **informational only** β€” `ring`/`aes-gcm` choose their implementation independently of the flag. Published artifacts (registries checked 2026-09-22): Python surfaces it (`EncryptionWrapper.hardware_acceleration_enabled`, in `get_info()` and the init log); cachekit-rs 0.7.0 never re-exports it and `@cachekit-io/cachekit` 0.1.5 exposes nothing on either binding β€” `N/A` for TypeScript was wrong, since both bindings run the same Rust core. The Rust re-export (`EncryptionLayer::hardware_acceleration_enabled()`, forwarded by `SecureCache`) is open in [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80): not on `main`, not released. The TypeScript surface (`TenantKeys.hardwareAccelerationEnabled()` on the NAPI and wasm bindings; `EncryptionManagerCore.isHardwareAccelerated()`, which initialises on demand and returns `null` β€” unknown, not `false` β€” when the installed binding predates the accessor) is merged to `main` in [cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132) but not released. The wasm32 always-`false` claim is asserted by cachekit-ts's workerd test (`encryption.protocol.workers.test.ts`), and the Rust accessor is pinned to `is_x86_feature_detected!("aes")` on x86_64 in `encryption.rs`'s unit tests. Cells flip to 🚧 unreleased on merge and to βœ… with a version floor on release, per [decisions/matrix-version-verification.md](decisions/matrix-version-verification.md). Tracked as LAB-523. +> ⁢ AES hardware detection lives in the shared core β€” `ZeroKnowledgeEncryptor::hardware_acceleration_enabled()` in `cachekit-core/src/encryption/core.rs`: a runtime `is_x86_feature_detected!("aes")` probe on x86/x86_64; on aarch64 it returns `cfg!(target_feature = "neon")`, which every aarch64 target enables, so it is `true` on every aarch64 build whether or not the CPU has the Crypto Extension β€” a Raspberry Pi 4 (Cortex-A72 without the Crypto Extension) reports `true` while `ring` runs software AES. That holds for every published `cachekit-core` through 0.6.0 (0.4.0 and 0.6.0 included); the fix, [cachekit-core#77](https://github.com/cachekit-io/cachekit-core/pull/77) (LAB-4650), is merged to core `main` but unreleased; always `false` on wasm32 (no AES instructions to detect). It is **informational only** β€” `ring`/`aes-gcm` choose their implementation independently of the flag. Published artifacts (registries checked 2026-09-29): Python surfaces it (`EncryptionWrapper.hardware_acceleration_enabled`, in `get_info()` and the init log); cachekit-rs 0.7.0 never re-exports it and `@cachekit-io/cachekit` 0.1.5 exposes nothing on either binding β€” `N/A` for TypeScript was wrong, since both bindings run the same Rust core. The Rust re-export (`EncryptionLayer::hardware_acceleration_enabled()`, forwarded by `SecureCache`) is open in [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80): not on `main`, not released. The TypeScript surface (`TenantKeys.hardwareAccelerationEnabled()` on the NAPI and wasm bindings; `EncryptionManager.isHardwareAccelerated()`, which initialises on demand and returns `null` β€” unknown, not `false` β€” when the installed binding predates the accessor) is merged to `main` in [cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132) but not released. The wasm32 always-`false` claim is asserted by cachekit-ts's workerd test (`encryption.protocol.workers.test.ts`), and the Rust accessor is pinned to `is_x86_feature_detected!("aes")` on x86_64 in [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80)'s `encryption.rs` tests (not on `main`). The Rust cell flips to 🚧 unreleased when [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80) merges; each flips to βœ… with a version floor on release, per [decisions/matrix-version-verification.md](decisions/matrix-version-verification.md). Tracked as LAB-523. --- From 359140a99dd3a2e3b17fb7b673a2f117e18a47e0 Mon Sep 17 00:00:00 2001 From: Ray Walker Date: Tue, 29 Sep 2026 15:04:33 +1000 Subject: [PATCH 6/6] docs(matrix): footnote 6 names get_encryption_info(), lists core 0.5.0 (LAB-523) - Python's EncryptionWrapper has get_encryption_info(), not get_info(); the footnote sent readers to a method that does not exist. - The published-core list for the aarch64 caveat now includes 0.5.0, the core the released Python package embeds. --- 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 6a774c5..1cfbba4 100644 --- a/sdk-feature-matrix.md +++ b/sdk-feature-matrix.md @@ -104,7 +104,7 @@ > > Degradation is on unless explicitly disabled (`degradationEnabled = config.degradation !== false`, `reliability/executor.ts:39`) and `createCache.secure()` / `.production()` / `.io()` all set it `true` (`intents-core.ts:186`); only `minimal` sets `false`, and `minimal` carries no encryption. **There is no `failClosed` option anywhere in cachekit-ts** β€” Python's `CACHEKIT_ENCRYPTION_FAIL_CLOSED` has no counterpart, so the only lever is `reliability: { degradation: false }`, which also gives up backend-outage degradation. If you rely on a thrown error as your tamper, wrong-key or nonce alarm, TypeScript raises none; the sole signal is the `errors_total` counter. > -> ⁢ AES hardware detection lives in the shared core β€” `ZeroKnowledgeEncryptor::hardware_acceleration_enabled()` in `cachekit-core/src/encryption/core.rs`: a runtime `is_x86_feature_detected!("aes")` probe on x86/x86_64; on aarch64 it returns `cfg!(target_feature = "neon")`, which every aarch64 target enables, so it is `true` on every aarch64 build whether or not the CPU has the Crypto Extension β€” a Raspberry Pi 4 (Cortex-A72 without the Crypto Extension) reports `true` while `ring` runs software AES. That holds for every published `cachekit-core` through 0.6.0 (0.4.0 and 0.6.0 included); the fix, [cachekit-core#77](https://github.com/cachekit-io/cachekit-core/pull/77) (LAB-4650), is merged to core `main` but unreleased; always `false` on wasm32 (no AES instructions to detect). It is **informational only** β€” `ring`/`aes-gcm` choose their implementation independently of the flag. Published artifacts (registries checked 2026-09-29): Python surfaces it (`EncryptionWrapper.hardware_acceleration_enabled`, in `get_info()` and the init log); cachekit-rs 0.7.0 never re-exports it and `@cachekit-io/cachekit` 0.1.5 exposes nothing on either binding β€” `N/A` for TypeScript was wrong, since both bindings run the same Rust core. The Rust re-export (`EncryptionLayer::hardware_acceleration_enabled()`, forwarded by `SecureCache`) is open in [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80): not on `main`, not released. The TypeScript surface (`TenantKeys.hardwareAccelerationEnabled()` on the NAPI and wasm bindings; `EncryptionManager.isHardwareAccelerated()`, which initialises on demand and returns `null` β€” unknown, not `false` β€” when the installed binding predates the accessor) is merged to `main` in [cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132) but not released. The wasm32 always-`false` claim is asserted by cachekit-ts's workerd test (`encryption.protocol.workers.test.ts`), and the Rust accessor is pinned to `is_x86_feature_detected!("aes")` on x86_64 in [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80)'s `encryption.rs` tests (not on `main`). The Rust cell flips to 🚧 unreleased when [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80) merges; each flips to βœ… with a version floor on release, per [decisions/matrix-version-verification.md](decisions/matrix-version-verification.md). Tracked as LAB-523. +> ⁢ AES hardware detection lives in the shared core β€” `ZeroKnowledgeEncryptor::hardware_acceleration_enabled()` in `cachekit-core/src/encryption/core.rs`: a runtime `is_x86_feature_detected!("aes")` probe on x86/x86_64; on aarch64 it returns `cfg!(target_feature = "neon")`, which every aarch64 target enables, so it is `true` on every aarch64 build whether or not the CPU has the Crypto Extension β€” a Raspberry Pi 4 (Cortex-A72 without the Crypto Extension) reports `true` while `ring` runs software AES. That holds for every published `cachekit-core` through 0.6.0 (0.4.0, 0.5.0 and 0.6.0 included); the fix, [cachekit-core#77](https://github.com/cachekit-io/cachekit-core/pull/77) (LAB-4650), is merged to core `main` but unreleased; always `false` on wasm32 (no AES instructions to detect). It is **informational only** β€” `ring`/`aes-gcm` choose their implementation independently of the flag. Published artifacts (registries checked 2026-09-29): Python surfaces it (`EncryptionWrapper.hardware_acceleration_enabled`, in `get_encryption_info()` and the init log); cachekit-rs 0.7.0 never re-exports it and `@cachekit-io/cachekit` 0.1.5 exposes nothing on either binding β€” `N/A` for TypeScript was wrong, since both bindings run the same Rust core. The Rust re-export (`EncryptionLayer::hardware_acceleration_enabled()`, forwarded by `SecureCache`) is open in [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80): not on `main`, not released. The TypeScript surface (`TenantKeys.hardwareAccelerationEnabled()` on the NAPI and wasm bindings; `EncryptionManager.isHardwareAccelerated()`, which initialises on demand and returns `null` β€” unknown, not `false` β€” when the installed binding predates the accessor) is merged to `main` in [cachekit-ts#132](https://github.com/cachekit-io/cachekit-ts/pull/132) but not released. The wasm32 always-`false` claim is asserted by cachekit-ts's workerd test (`encryption.protocol.workers.test.ts`), and the Rust accessor is pinned to `is_x86_feature_detected!("aes")` on x86_64 in [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80)'s `encryption.rs` tests (not on `main`). The Rust cell flips to 🚧 unreleased when [cachekit-rs#80](https://github.com/cachekit-io/cachekit-rs/pull/80) merges; each flips to βœ… with a version floor on release, per [decisions/matrix-version-verification.md](decisions/matrix-version-verification.md). Tracked as LAB-523. ---