diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,14 @@
 
 ## Unreleased
 
+## 0.2.1.0 — 2026-11-02
+
+### Changed
+
+- Upgrade `mori://shinzui/baikai/packages/baikai` to `>=0.10.0.0 && <0.11`.
+
+- Update internal dependency bounds for the breaking `shikumi 0.5.0.0` release.
+
 ## 0.2.0.2 — 2026-10-16
 
 ### Changed
diff --git a/shikumi-cache.cabal b/shikumi-cache.cabal
--- a/shikumi-cache.cabal
+++ b/shikumi-cache.cabal
@@ -1,6 +1,6 @@
 cabal-version: 3.4
 name: shikumi-cache
-version: 0.2.0.2
+version: 0.2.1.0
 synopsis: Content-addressed response caching for shikumi (EP-6)
 category: AI
 description:
@@ -51,7 +51,7 @@
 
   build-depends:
     aeson >=2.2 && <2.3,
-    baikai >=0.8.0.0 && <0.9,
+    baikai >=0.10.0.0 && <0.11,
     base >=4.20 && <5,
     blake3 >=0.3 && <0.4,
     bytestring >=0.11 && <0.13,
@@ -61,7 +61,7 @@
     generic-lens >=2.2 && <2.4,
     lens ^>=5.3,
     scientific >=0.3 && <0.4,
-    shikumi ^>=0.4.1.1,
+    shikumi ^>=0.5.0.0,
     stm >=2.5 && <2.6,
     text ^>=2.1,
     time >=1.12 && <1.17,
@@ -78,7 +78,7 @@
 
   build-depends:
     aeson,
-    baikai >=0.8.0.0 && <0.9,
+    baikai >=0.10.0.0 && <0.11,
     base,
     bytestring,
     containers,
@@ -89,8 +89,9 @@
     generic-lens,
     lens,
     process,
-    shikumi ^>=0.4.1.1,
-    shikumi-cache ^>=0.2.0.2,
+    shikumi ^>=0.5.0.0,
+    shikumi-cache ^>=0.2.1.0,
+    shikumi-testing,
     stm,
     tasty,
     tasty-hunit,
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -30,6 +30,7 @@
 import Baikai qualified as B
 import Baikai.Cost qualified as BC
 import Baikai.Evidence qualified as E
+import Baikai.Models.Generated (openai_gpt_4o_mini)
 import Baikai.Speed (Speed (..))
 import Baikai.ThinkingLevel (ThinkingLevel (..))
 import Baikai.Usage qualified as BU
@@ -66,12 +67,20 @@
 import Shikumi.Cache.Backend.SQLite (runCacheSQLite, withSQLiteCache)
 import Shikumi.Cache.Key (canonicalJSON, requestToCanonicalValueVersioned, stripMessageTimestamps)
 import Shikumi.Cache.ResponseJSON ()
+import Shikumi.Decision
+import Shikumi.Decision.Setting
 import Shikumi.Effect.Time (runTime)
 import Shikumi.Error (ShikumiError (..))
 import Shikumi.LLM (LLM (..), complete)
 import Shikumi.LLM.Continuation (contextIdentity, requestOrigin, stampContinuation)
 import Shikumi.LLM.Defaults
+import Shikumi.Program qualified as P
 import Shikumi.Routing (routeLLM, runRouting)
+import Shikumi.Schema (field)
+import Shikumi.Testing.DecisionFixtures
+import Shikumi.Testing.Response (evidenceJSONResponse, evidenceMarkerResponse)
+import Shikumi.Testing.StubLLM (captureLLMRequests)
+import Shikumi.Testing.SystemOne (systemOneModel, systemOneResponder, systemOneResponse)
 import System.Environment (getEnvironment, getExecutablePath, lookupEnv)
 import System.Exit (ExitCode (ExitSuccess), exitFailure, exitSuccess)
 import System.FilePath ((</>))
@@ -140,7 +149,34 @@
       defaultMain $
         testGroup
           "shikumi-cache"
-          [ defaultsTests,
+          [ testCase "Decision settings reuse evidence with identical cache keys on all backends" $ do
+              let fields = [("urgent", FieldNoul (NoulEvidence 0.6)), ("severity", FieldScore (ScoreEvidence (V.fromList [0.1, 0.3, 0.6]) (Just 0.8))), ("category", FieldChoice (ChoiceEvidence (Map.fromList [("billing", 0.2), ("technical", 0.8)]) (Just 0.8)))]
+                  payload = \case FieldNoul e -> toJSON e; FieldChoice e -> toJSON e; FieldScore e -> toJSON e
+                  values = [(k, payload e) | (k, e) <- fields]
+              mapM_
+                ( \(model, response) -> do
+                    cache <- newMemoryCache
+                    calls <- newIORef 0
+                    seen <- newIORef []
+                    let program = P.Predict assessmentSig P.emptyParams
+                    result <- runEff . runConcurrent . runTime . runErrorNoCallStack @ShikumiError . runRouting model . runCountingLLM calls response . runCacheMemory cache . cachedLLM . captureLLMRequests seen . routeLLM $ do
+                      a <- P.runProgram program (Ticket (field "x"))
+                      b <- P.runProgram (P.mapParams (P.setDecisionSetting "urgent" (NoulSetting 0.7)) program) (Ticket (field "x"))
+                      pure (a, b)
+                    case result of
+                      Right (a, b) -> assertBool "threshold flips result" (a /= b)
+                      Left err -> assertFailure (show err)
+                    readIORef calls >>= (@?= 1)
+                    requests <- readIORef seen
+                    case [cacheKey m c o | (m, c, o) <- requests] of
+                      [a, b] -> a @?= b
+                      _ -> assertFailure "expected two logical requests"
+                )
+                [(systemOneModel "jev-latest", systemOneResponse fields), (openai_gpt_4o_mini, evidenceJSONResponse values), (emptyModel, evidenceMarkerResponse values)],
+            testCase "Decision AssistantData cache codec round-trip" $ do
+              let response = systemOneResponse [("flag", FieldNoul (NoulEvidence 0.8))]
+              eitherDecode (encode response) @?= Right response,
+            defaultsTests,
             keyTests,
             memoryTests,
             sqliteTests,
