diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,23 @@
 
 ## Unreleased
 
+## 0.2.0.3 — 2026-08-29
+
+### Changed
+
+- Every library dependency now carries a PVP upper bound: `aeson`, `bytestring`,
+  `containers`, `effectful`, `generic-lens`, `tasty`, `tasty-golden`, `vector`.
+  `cabal check` reported these under `missing-upper-bounds`. Without one, a
+  future breaking release of a dependency enters a consumer's build plan
+  unchecked — which is the failure the bound exists to prevent.
+
+  Each bound admits the version this package is built and tested against and
+  stops below the next major.
+
+  `aeson` stops at `<2.3` rather than `<2.4`: baikai-openai 0.5 constrains it to
+  `^>=2.2`, so aeson 2.3 is not reachable for this cohort and a wider bound
+  would assert compatibility that cannot be exercised here.
+
 ## 0.2.0.2 — 2026-08-07
 
 ### Changed
diff --git a/shikumi-eval.cabal b/shikumi-eval.cabal
--- a/shikumi-eval.cabal
+++ b/shikumi-eval.cabal
@@ -1,6 +1,6 @@
 cabal-version:   3.4
 name:            shikumi-eval
-version:         0.2.0.2
+version:         0.2.0.3
 synopsis:        Typed evaluation framework for shikumi LM programs (EP-8)
 category:        AI
 description:
@@ -45,19 +45,19 @@
     Shikumi.Eval.Usage
 
   build-depends:
-    , aeson
-    , baikai        >=0.5      && <0.6
+    , aeson         >=2.2      && <2.3
+    , baikai        >=0.6      && <0.7
     , base          >=4.20     && <5
-    , bytestring
-    , containers
-    , effectful
-    , generic-lens
+    , bytestring    >=0.11     && <0.13
+    , containers    >=0.6      && <0.9
+    , effectful     >=2.5      && <2.7
+    , generic-lens  >=2.2      && <2.4
     , lens          ^>=5.3
     , shikumi       ^>=0.3.0.0
-    , tasty
-    , tasty-golden
+    , tasty         >=1.4      && <1.6
+    , tasty-golden  >=2.3      && <2.4
     , text          ^>=2.1
-    , vector
+    , vector        >=0.13     && <0.14
 
 test-suite shikumi-eval-test
   import:         common-options
@@ -79,7 +79,7 @@
 
   build-depends:
     , aeson
-    , baikai        >=0.5      && <0.6
+    , baikai        >=0.6      && <0.7
     , base
     , effectful
     , generic-lens
diff --git a/test/EvalFixtures.hs b/test/EvalFixtures.hs
--- a/test/EvalFixtures.hs
+++ b/test/EvalFixtures.hs
@@ -36,8 +36,8 @@
     Response,
     StopReason (..),
     doneTerminal,
-    _Response,
-    _TextContent,
+    emptyResponse,
+    emptyTextContent,
   )
 import Control.Lens ((&), (.~), (^.))
 import Data.Generics.Labels ()
@@ -145,7 +145,7 @@
 -- | An assistant 'Response' carrying @t@ as its single text block.
 mkResponse :: Text -> Response
 mkResponse t =
-  _Response & #message . #content .~ V.singleton (AssistantText (_TextContent & #text .~ t))
+  emptyResponse & #message . #content .~ V.singleton (AssistantText (emptyTextContent & #text .~ t))
 
 -- ---------------------------------------------------------------------------
 -- Mock LLM interpreters
diff --git a/test/UsageSpec.hs b/test/UsageSpec.hs
--- a/test/UsageSpec.hs
+++ b/test/UsageSpec.hs
@@ -1,7 +1,7 @@
 -- | Usage-accounting tests for both blocking and streamed LM calls.
 module UsageSpec (tests) where
 
-import Baikai (_Context, _Model, _Options)
+import Baikai (emptyContext, emptyModel, emptyOptions)
 import Effectful (runEff)
 import Effectful.Concurrent (runConcurrent)
 import Effectful.Error.Static (runErrorNoCallStack)
@@ -48,7 +48,7 @@
         result <-
           runEff . runPrim $
             runStreamLLM events $
-              withUsageTotals (stream _Model _Context _Options)
+              withUsageTotals (stream emptyModel emptyContext emptyOptions)
         snd result @?= usageTotalsPerCall,
       testCase "evaluate reports non-zero usage end-to-end" $ do
         let ds =
