diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,13 @@
 
 ## [Unreleased]
 
+## 0.21.0.0 — 2026-10-14
+
+### Other Changes
+
+- No user-facing changes this release. Version and internal dependency bounds
+  advance with the shared 0.21.0.0 release.
+
 ## 0.20.0.0 — 2026-10-12
 
 ### Breaking Changes
diff --git a/keiro.cabal b/keiro.cabal
--- a/keiro.cabal
+++ b/keiro.cabal
@@ -1,6 +1,6 @@
 cabal-version: 3.0
 name: keiro
-version: 0.20.0.0
+version: 0.21.0.0
 synopsis: Event sourcing framework and workflow engine
 description:
   A library that composes kiroku, keiki, and shibuya into an
@@ -170,7 +170,7 @@
     hs-opentelemetry-semantic-conventions >=1.40 && <2,
     keiki >=0.9 && <0.10,
     keiki-codec-json >=0.9 && <0.10,
-    keiro-core ^>=0.20.0.0,
+    keiro-core ^>=0.21.0.0,
     kiroku-store ^>=0.11.0.0,
     lens >=5.2 && <5.4,
     mmzk-typeid >=0.7 && <0.8,
@@ -240,7 +240,8 @@
     keiki,
     keiki-codec-json,
     keiro,
-    keiro-test-support ^>=0.20.0.0,
+    keiro-migrations ^>=0.21.0.0,
+    keiro-test-support ^>=0.21.0.0,
     kiroku-store ^>=0.11.0.0,
     process >=1.6 && <1.7,
     shibuya-core ^>=0.10.0.1,
@@ -276,8 +277,8 @@
     keiki >=0.9 && <0.10,
     keiki-codec-json >=0.9 && <0.10,
     keiro,
-    keiro-core ^>=0.20.0.0,
-    keiro-test-support ^>=0.20.0.0,
+    keiro-core ^>=0.21.0.0,
+    keiro-test-support ^>=0.21.0.0,
     kiroku-store ^>=0.11.0.0,
     shibuya-core ^>=0.10.0.1,
     shibuya-kiroku-adapter ^>=0.6.0.1,
@@ -324,8 +325,8 @@
     hs-opentelemetry-sdk >=1.0 && <1.1,
     keiki >=0.9 && <0.10,
     keiro,
-    keiro-core ^>=0.20.0.0,
-    keiro-test-support ^>=0.20.0.0,
+    keiro-core ^>=0.21.0.0,
+    keiro-test-support ^>=0.21.0.0,
     kiroku-store ^>=0.11.0.0,
     process >=1.6 && <1.7,
     shibuya-core ^>=0.10.0.1,
diff --git a/test/ExternalReadSpec.hs b/test/ExternalReadSpec.hs
--- a/test/ExternalReadSpec.hs
+++ b/test/ExternalReadSpec.hs
@@ -24,6 +24,7 @@
 import Hasql.Statement (Statement, preparable)
 import Hasql.Transaction qualified as Tx
 import Hasql.Transaction.Sessions qualified as TxSessions
+import Keiro.Migrations.SchemaCheck (renderSchemaDrift, verifyExpectedSchema)
 import Keiro.Prelude
 import Keiro.Projection.Catalog
 import Keiro.ReadModel.External
@@ -40,6 +41,21 @@
   describe "managed external read contracts"
     $ around (withFreshDatabase fixture)
     $ do
+      it "leaves schema verification clean after reconciling an all-rows contract" $ \connectionString ->
+        withPool connectionString $ \pool ->
+          Store.withStore (Store.defaultConnectionSettings connectionString) $ \store -> do
+            let settings = ConnectionSettings.connectionString connectionString
+            runScript pool allRowsFixtureSql
+            beforeDrifts <- verifyExpectedSchema settings >>= expectUsage
+            (renderSchemaDrift <$> beforeDrifts) `shouldBe` []
+            catalog <- expectValid Catalog.bridgeCatalog
+            register store catalog
+            runScript pool activateV1Sql
+            expectStore store (reconcileExternalReadContracts catalog) >>= shouldBeRight
+            runStatement pool () bindingExistsStmt `shouldReturn` True
+            afterDrifts <- verifyExpectedSchema settings >>= expectUsage
+            (renderSchemaDrift <$> afterDrifts) `shouldBe` []
+
       it "fences lifecycle transitions, holds cutover behind readers, and enforces execute-only grants" $ \connectionString ->
         withPool connectionString $ \pool ->
           Store.withStore (Store.defaultConnectionSettings connectionString) $ \store -> do
@@ -788,3 +804,10 @@
     "EXPLAIN (COSTS OFF) SELECT ROW(counter.id, counter.total)::app_contract.counter_row_v1 FROM app.counter AS counter WHERE counter.id = 2"
     E.noParams
     (D.rowList (D.column (D.nonNullable D.text)))
+
+bindingExistsStmt :: Statement () Bool
+bindingExistsStmt =
+  preparable
+    "SELECT to_regclass('keiro.external_read_counter_reader_v1_binding') IS NOT NULL"
+    E.noParams
+    (D.singleRow (D.column (D.nonNullable D.bool)))
