Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
7333973
docs(cache-key): serializer code must be derived, and per-identity (L…
27Bslash6 Sep 21, 2026
ebc56e8
fix: address coderabbit review — serializer-code provenance, collisio…
27Bslash6 Sep 21, 2026
4cfdd80
docs(cache-key): mark the alias map and identity normalisation SDK-su…
27Bslash6 Sep 21, 2026
aa4de19
docs(cache-key): state that the vectors' "std" is read as canonical "…
27Bslash6 Sep 21, 2026
3a59b56
docs(cache-key): fix Test Vectors byte-for-byte matching scope
27Bslash6 Sep 21, 2026
1c1c51b
docs(cache-key): scope vector byte-match to implemented suffix; requi…
27Bslash6 Sep 21, 2026
0c8917a
Merge main: resolve Test Vectors against the Python-SDK-only reframe
27Bslash6 Sep 25, 2026
77c52e1
docs(cache-key): separate key identity from recorded serializer name
27Bslash6 Sep 25, 2026
5cf553f
docs(cache-key): the 16-bit code is not a collision-resistant separat…
27Bslash6 Sep 25, 2026
80b1dc2
docs(cache-key): one uniqueness rule, required serializer_type, shipp…
27Bslash6 Sep 25, 2026
54cffcb
docs(cache-key): scope the read-side name check, state identity rules…
27Bslash6 Sep 26, 2026
5200ca1
Merge main: union the CHANGELOG with the SaaS API entries
27Bslash6 Sep 27, 2026
13db174
docs(cache-key): scope the collision guarantee to honest writers; AAD…
27Bslash6 Sep 27, 2026
469e303
docs(cache-key): the serializer name is unauthenticated because it is…
27Bslash6 Sep 27, 2026
3b960ce
Merge main: union the CHANGELOG with the default-tenant vector entry
27Bslash6 Sep 27, 2026
f5df2cd
Merge main: union the CHANGELOG with the vendored-fixture coverage entry
27Bslash6 Sep 28, 2026
f9cff44
fix: address coderabbit review — point the bare-class-name s row at t…
27Bslash6 Sep 28, 2026
b8834c8
Merge main: move this branch's changelog entries into changelog.d/
27Bslash6 Sep 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ Building a new SDK? Implement in this order:

**1. Key Generation** — [spec/cache-key-format.md](spec/cache-key-format.md)

Generate deterministic cache keys from function identity + arguments. Keys must match across SDKs for cross-language cache sharing.
Generate deterministic cache keys from function identity + arguments. These auto-mode keys are SDK-specific (the 7-segment format is the Python SDK's convention); keys shared across SDKs use [interop mode](spec/interop-mode.md).

**2. Wire Format** — [spec/wire-format.md](spec/wire-format.md)

Expand Down
18 changes: 18 additions & 0 deletions changelog.d/20260924_server-side-requirements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
### Cache key — 7-segment format is Python SDK convention; server-side requirements

- [`spec/cache-key-format.md`](spec/cache-key-format.md): the 7-segment key
structure is marked the Python SDK's internal convention, not a server
contract. A new
[Server-Side Requirements](spec/cache-key-format.md#server-side-requirements)
section lists the only checks the CachekitIO backend enforces and which API
key classes may write each key space — including the open `default` space
that unprefixed keys (TypeScript/Rust `{ns}:{hash}`, interop, bare hashes)
fall in.
- Test Vectors: `test-vectors/cache-keys.json` is Python-SDK-only. The rule
that a cross-SDK implementation substitutes its own module path and matches
the args-hash segment byte-for-byte is withdrawn for these vectors; cross-SDK
conformance uses `test-vectors/interop-mode.json`. The fixture's `note` and
`key_format` fields now say so; no vector changed.
- [`spec/interop-mode.md`](spec/interop-mode.md): the deployed validator
accepts interop-format keys (`{namespace}:{operation}:{args_hash}`, in the
`default` namespace), replacing the warning that it would reject them.
57 changes: 57 additions & 0 deletions changelog.d/20260929_lab-4351.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
### Cache key — serializer code MUST be derived, and per-identity (LAB-4351)

- [`spec/cache-key-format.md`](spec/cache-key-format.md): the `{serializer_code}`
suffix MUST be derived from the configured serializer, never a constant, and
two identities the wire format records differently MUST NOT be mapped onto
one code by construction. An identity outside the code table gets `x` + the
2-byte `blake2b` digest of its UTF-8 identity as 4 lowercase hex characters;
the collision guarantee is stated as probabilistic (16 bits). Between honestly
written entries a collision costs hit rate only, never a wrong value; the
recorded serializer name is not an integrity control against a writer with
backend write access. An SDK that
offers more than one serializer identity MUST record the serializer name in
the container of each serialized entry under a key in this format, and MUST
compare it against its own on every read of one, before decoding; for such an
SDK, an entry recording no name is a mismatch. An SDK offering a single
identity (`cachekit-ts`, `cachekit-rs`) is exempt from both; Interop Mode
entries and in-process live-object caches are outside both rules.
Identity-derivation rules that lived only in pseudocode comments (alias
resolution, the object-identity marker, rejecting an empty identity) are now
normative prose, and alias resolution now also binds the writer: the code,
the recorded name and the serializer that writes the bytes MUST all resolve
to one canonical name. One uniqueness rule: an SDK SHOULD make
the identity distinguish configurations that write different bytes, and
wherever it does not, those configurations MUST be keyed under different
`ns:` namespaces (the 16-bit code is not a collision-resistant separator). The
`cache_key` AAD component is identical for serializers sharing a code, and a
reader takes `format` from the stored entry, so the cipher is no backstop
between serializers sharing a code.
The table gains `l` (reference caching — shipped, never documented) and a
`Canonical name` column, and drops its `Cross-language?` column: no
serializer code makes these keys shareable across SDKs, and the Cross-SDK Key
Generation Strategy section (and the README's implementor Quick Start) now
route all cross-SDK sharing through Interop Mode instead of namespace-matched
keys. Alias spellings (`std`, `pythonic`) and
the instance identity (`<custom>:` + bare class name, so one class with
different constructor arguments shares one identity) are documented in a new
Python SDK note, which points at that rule.
Documents the defect corrected by
[cachekit-io/cachekit-py#311](https://github.com/cachekit-io/cachekit-py/pull/311)
(merged as `ee65250`; ships in cachekit-py 0.20.0): through v0.19.0 every
auto-mode key ended in `s` regardless of serializer, so two caches over one
function differing only in serializer shared a key and evicted each other on
every read.
- SDK-implementor pseudocode: the block previously defaulted `serializer_type`
to cachekit-py's `std` spelling and indexed a code table it never defined. It
now defines the table and `serializer_code()`, and adds an alias map and a
`normalize_identity()` hook, both marked SDK-supplied; the hook runs before
alias and table lookup, with the purity constraint the one-identity-one-code
rule already requires. `serializer_type` is a required parameter, and
`serializer_code()` rejects an empty or non-string identity with an error
rather than mapping it to a code.
- [`spec/wire-format.md`](spec/wire-format.md): the CK v3 frame's header `s`
table adds a serializer instance's bare class name, and the framing statement
excepts the two in-process modes that store no bytes: reference caching (`l`)
and `backend=None`.
- Provenance: no vector changed; the derived codes are not yet covered by
vectors.
Loading
Loading