Class NaruCacheKeyChain

java.lang.Object
net.thevpc.naru.ext.models.cache.NaruCacheKeyChain

public final class NaruCacheKeyChain extends Object
Computes the cache identity of a segmented context as a hash chain rather than as a set of independent per-segment hashes.

Why a chain and not per-segment hashes

Every provider cache in play is a prefix cache: what matters is not whether a given block of text is unchanged, but whether everything before it is also unchanged and in the same order. NARU makes this awkward because conversation history is not append-only — /history delete removes messages at arbitrary positions.

With independent hashes, deleting the middle message of [a, b, c] yields [a, c]. Segment c still hashes to the same value, so a naive implementation would happily treat it as a cache hit and claim the cached prefix "a c" was seen before. It was not: the cached prefix was "a b c", and the bytes now differ from position 1 onward. The cache would be reported as valid while serving context that was never cached — a correctness bug, not a missed optimisation.

Chaining removes the ambiguity. Each key commits to everything before it:

   key[0] = H(seg[0])
   key[i] = H(key[i-1] + seg[i])
 
so a change anywhere shifts every key after it. Comparing two chains finds the true edit point, and the edit point is the same thing regardless of whether the edit was an append, a deletion, or a mid-history insertion.
  • Method Details

    • chain

      public static List<String> chain(List<NaruContextSegment> segments)
      The hash chain over the given segments, in order.

      Returned keys are what gets persisted between turns. The chain is content-addressed, so the same context always produces the same keys on any machine and in any JVM run — which is what allows the state to be written to disk and trusted after a restart.

    • validPrefixLength

      public static int validPrefixLength(List<String> previousKeys, List<String> currentKeys)
      How many leading segments are still a valid continuation of the previously cached prefix.

      Everything in [0, validPrefix) can keep whatever cache state it had. Everything from validPrefix onward is a cache miss and must be sent as fresh content.

      With no baseline the answer is always 0: absence of evidence is treated as evidence of change, because the alternative is trusting a cache reference that may describe context this session never sent.

    • sha256

      public static String sha256(String value)
      SHA-256, hex encoded.

      Deliberately a cryptographic hash rather than a fast 64-bit one: a collision here is a false cache hit, which means serving context that was never sent. That failure is silent and user-visible, and it is not worth trading for microseconds next to a network-bound model call.