fix(disk-cache): bind snapshot identity to model+config (manifest hardening)#361
Merged
davide221 merged 2 commits intoJun 10, 2026
Merged
Conversation
…dening) Salt = sha1(gguf_path+stat, max_ctx, chat_template) prepended to layout hash; DRY sha1 extracted to common/sha1.h (replaces two file-statics); all-zero salt is back-compat; composes with Luce-Org#352 lazy verify unchanged; 2 new tests.
Contributor
There was a problem hiding this comment.
3 issues found across 7 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="server/src/server/http_server.cpp">
<violation number="1" location="server/src/server/http_server.cpp:779">
P2: Model fingerprint uses second-resolution mtime; fast same-size file replacement can collide and reuse invalid disk KV. Include sub-second timestamp (or stronger file identity) in the salted hash input.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| int64_t file_mtime = 0; | ||
| if (::stat(path.c_str(), &st) == 0) { | ||
| file_size = (int64_t)st.st_size; | ||
| file_mtime = (int64_t)st.st_mtime; |
Contributor
There was a problem hiding this comment.
P2: Model fingerprint uses second-resolution mtime; fast same-size file replacement can collide and reuse invalid disk KV. Include sub-second timestamp (or stronger file identity) in the salted hash input.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At server/src/server/http_server.cpp, line 779:
<comment>Model fingerprint uses second-resolution mtime; fast same-size file replacement can collide and reuse invalid disk KV. Include sub-second timestamp (or stronger file identity) in the salted hash input.</comment>
<file context>
@@ -758,6 +761,48 @@ std::vector<ChatMessage> normalize_chat_messages(
+ int64_t file_mtime = 0;
+ if (::stat(path.c_str(), &st) == 0) {
+ file_size = (int64_t)st.st_size;
+ file_mtime = (int64_t)st.st_mtime;
+ } else {
+ std::fprintf(stderr, "[disk-cache] salt: stat(%s) failed — path-only fingerprint\n",
</file context>
Suggested change
| file_mtime = (int64_t)st.st_mtime; | |
| file_mtime = (int64_t)st.st_mtime * 1000000000LL + (int64_t)st.st_mtim.tv_nsec; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Re-carved from #274 (commit
4d12bca) onto current main, reconciled with #352's lazy layout verify, plus a DRY sha1 consolidation.The disk KV-cache identity (
layout_id) hashed only tensor name+type+shape, so restarting over the same--kv-cache-dirwith a different model /max_ctx/ chat_template could serve stale, invalid KV → corruption.compute_layout_idnow prepends a 16-byte salt =sha1(GGUF path+size+mtime, max_ctx, chat_template). rope/yarn are GGUF-derived (covered by the file stat); kv_dtype already lives in tensor types. All-zero salt (the default) is byte-for-byte back-compatible; composes with #352 (both the live-learn and lazy-verify paths call the saltedcompute_layout_id).DRY:
sha1_hashwas a file-static indisk_prefix_cache.cppandprefix_cache.cpp; #274 cloned a third intohttp_server.cpp. Consolidated to oneserver/src/common/sha1.h— three copies → one.Unit-tested (different config → different layout_id; identical → identical; all-zero back-compat; existing layout-verify regression). 1866 assertions green.
End-to-end validated (real server +
--kv-cache-diracross restarts): same config → disk hit, samelayout_id(reuse, no regression);max_ctx8192→4096 → newlayout_id, the stale entry is rejected at the layout-mismatch guard (disk_hit=false), response coherent; different model path → a third distinctlayout_id. The salt lives inDiskPrefixCache(config-derived, backend-agnostic).7 files, +349/-120. Folding
max_ctxalso makes the planned gemma4 cross-session (WS2) disk reuse collision-safe.