diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,16 @@
 `arch-hs` uses [PVP Versioning][1].
 The changelog is available [on GitHub][2].
 
+## 0.12.3
+
+- Teach `arch-hs-rdepcheck` to validate a candidate version against reverse dependency ranges
+
+- Use the newest cached Hackage index when multiple mirrors are available
+
+- Update supported GHC/Cabal dependency bounds
+
+- Update name preset
+
 ## 0.12.2
 
 - Fail `arch-hs-sync submit` when Hackage returns an unsuccessful upload status
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -511,7 +511,29 @@
 ✔ Success!
 ```
 
-`arch-hs-diff` does not require hackage db, it downloads cabal files from hackage server instead. 
+`arch-hs-diff` does not require hackage db, it downloads cabal files from hackage server instead.
+
+## Reverse dependency checks
+
+`arch-hs-rdepcheck` lists Haskell reverse dependencies in [extra] and the Cabal version ranges they require:
+
+```
+$ arch-hs-rdepcheck aeson
+Reverse dependency: agda
+  Depends: >=1.1.2.0 && <2.3
+...
+```
+
+Pass an optional version to check whether that version satisfies every listed range. Out-of-range entries are printed as errors, and the command exits with a non-zero status if any range fails:
+
+```
+$ arch-hs-rdepcheck aeson 3.0
+Reverse dependency: agda
+  Depends: >=1.1.2.0 && <2.3
+  Error: 3.0 is outside Depends range (>=1.1.2.0 && <2.3)
+...
+68 reverse dependency range check(s) failed.
+```
 
 ## Sync
 
diff --git a/arch-hs.cabal b/arch-hs.cabal
--- a/arch-hs.cabal
+++ b/arch-hs.cabal
@@ -1,6 +1,6 @@
 cabal-version:      2.4
 name:               arch-hs
-version:            0.12.2
+version:            0.12.3
 synopsis:           Distribute hackage packages to archlinux
 description:
   @arch-hs@ is a command-line program, which simplifies the process of producing
@@ -23,7 +23,7 @@
   CHANGELOG.md
   README.md
 
-tested-with:        GHC ==8.10.7 || ==9.0.2 || ==9.2.3
+tested-with:        GHC ==9.2.8 || ==9.4.8 || ==9.6.7 || ==9.8.4
 
 source-repository head
   type:     git
@@ -41,7 +41,7 @@
     , arch-web                     ^>=0.3.2
     , base                         >=4.12     && <5
     , bytestring
-    , Cabal                        >=3.2      && <3.11
+    , Cabal                        >=3.8      && <3.11
     , conduit                      ^>=1.3.2
     , conduit-extra                ^>=1.3.5
     , containers
@@ -64,7 +64,7 @@
     , servant-client               >=0.18.2   && <0.21
     , split                        ^>=0.2.3
     , tar-conduit                  ^>=0.3.2   || ^>=0.4.0
-    , template-haskell             ^>=2.16.0  || ^>=2.17.0 || ^>=2.18.0 || ^>=2.19.0 || ^>=2.20.0 || ^>=2.21.0
+    , template-haskell             ^>=2.18.0  || ^>=2.19.0 || ^>=2.20.0 || ^>=2.21.0
     , text
 
   ghc-options:
diff --git a/data/NAME_PRESET.json b/data/NAME_PRESET.json
--- a/data/NAME_PRESET.json
+++ b/data/NAME_PRESET.json
@@ -8,6 +8,7 @@
   "c2hs": "c2hs",
   "haskell-cabal": "Cabal",
   "cabal-install": "cabal-install",
+  "cabal-fmt": "cabal-fmt",
   "cabal-plan": "cabal-plan",
   "haskell-cabal-syntax": "Cabal-syntax",
   "cbor-tool": "cbor-tool",
@@ -15,6 +16,7 @@
   "clash-ghc": "clash-ghc",
   "cryptol": "cryptol",
   "darcs": "darcs",
+  "dice": "dice",
   "dhall": "dhall",
   "dhall-bash": "dhall-bash",
   "dhall-docs": "dhall-docs",
@@ -26,16 +28,15 @@
   "gitit": "gitit",
   "glirc": "glirc",
   "happy": "happy",
+  "haskell-bindings-dsl": "bindings-DSL",
   "haskell-boolean": "Boolean",
   "haskell-boundedchan": "BoundedChan",
   "haskell-chasingbottoms": "ChasingBottoms",
   "haskell-ci": "haskell-ci",
-  "haskell-configfile": "ConfigFile",
   "haskell-cracknum": "crackNum",
   "haskell-dav": "DAV",
   "haskell-decimal": "Decimal",
   "haskell-diff": "Diff",
-  "haskell-drbg": "DRBG",
   "haskell-edisonapi": "EdisonAPI",
   "haskell-edisoncore": "EdisonCore",
   "haskell-findbin": "FindBin",
@@ -113,11 +114,11 @@
   "stylish-haskell": "stylish-haskell",
   "taffybar": "taffybar",
   "tamarin-prover": "tamarin-prover",
-  "tidalcycles": "tidal",
   "unlambda": "unlambda",
   "uusi": "uusi",
   "xmobar": "xmobar",
   "xmonad": "xmonad",
+  "xmonad-dbus": "xmonad-dbus",
   "xmonad-contrib": "xmonad-contrib",
   "xmonad-extras": "xmonad-extras",
   "xmonad-utils": "xmonad-utils"
diff --git a/rdepcheck/Args.hs b/rdepcheck/Args.hs
--- a/rdepcheck/Args.hs
+++ b/rdepcheck/Args.hs
@@ -14,7 +14,8 @@
   { optFlags :: FlagAssignments,
     optExtraDB :: ExtraDBOptions,
     optHackage :: HackageDBOptions,
-    optPackageName :: PackageName
+    optPackageName :: PackageName,
+    optCheckVersion :: Maybe Version
   }
 
 cmdOptions :: Parser Options
@@ -24,14 +25,15 @@
     <*> extraDBOptionsParser
     <*> hackageDBOptionsParser
     <*> argument optPackageNameReader (metavar "TARGET")
+    <*> optional (argument optVersionReader (metavar "VERSION"))
 
 runArgsParser :: IO Options
 runArgsParser = do
   (x, ()) <-
     simpleOptions
       archHsVersion
-      "arch-hs-rdepcheck - check the version of a dependent Haskell package"
-      "arch-hs-rdepcheck is a CLI tool that shows all reverse dependencies of a Haskell package in [extra], giving the version range how it is depended on"
+      "arch-hs-rdepcheck - inspect reverse dependency version ranges"
+      "arch-hs-rdepcheck shows all reverse dependencies of a Haskell package in [extra] and the version ranges they require. If VERSION is provided, it reports ranges that do not accept VERSION and exits with failure."
       cmdOptions
       empty
   pure x
diff --git a/rdepcheck/Check.hs b/rdepcheck/Check.hs
--- a/rdepcheck/Check.hs
+++ b/rdepcheck/Check.hs
@@ -6,7 +6,7 @@
 
 module Check (check) where
 
-import Control.Monad (forM_, unless)
+import Control.Monad (forM, unless)
 import Data.List (find)
 import qualified Data.Map.Strict as Map
 import Data.Maybe (catMaybes)
@@ -41,9 +41,10 @@
       Embed IO
     ]
     r =>
+  Maybe Version ->
   PackageName ->
-  Sem r ()
-check target = do
+  Sem r Int
+check mVersion target = do
   let aTarget = toArchLinuxName target
   exists <- isInExtra aTarget
   unless exists $ throw $ PkgNotFound target
@@ -65,7 +66,7 @@
       )
       . Map.toList
       <$> ask @ExtraDB
-  forM_ reverseDeps $ \(PkgDesc {..}, src) -> do
+  failures <- forM reverseDeps $ \(PkgDesc {..}, src) -> do
     eCabal <-
       try @MyException $
         getCabal (toHackageName _name) =<< case simpleParsec _version of
@@ -74,15 +75,46 @@
     case eCabal of
       Right cabal -> do
         result <- getDepVersion cabal target src
+        let failedRanges = versionFailures mVersion result
         embed . putDoc $
           vsep
             ( annMagneta "Reverse dependency" <> colon
                 <+> pretty (unArchLinuxName _name)
-                : [indent 2 $ pretty s <> colon <+> viaPretty r | (s, r) <- result]
+                : (rangeDocs result <> versionErrors mVersion failedRanges)
             )
             <> line
-      Left e ->
+        pure $ length failedRanges
+      Left e -> do
         printWarn $ "Skip" <+> pretty (unArchLinuxName _name) <> colon <+> viaShow e
+        pure 0
+  pure $ sum failures
+
+rangeDocs :: [(DepSrc, VersionRange)] -> [Doc AnsiStyle]
+rangeDocs result =
+  [ indent 2 $ pretty s <> colon <+> viaPretty r
+    | (s, r) <- result
+  ]
+
+versionFailures :: Maybe Version -> [(DepSrc, VersionRange)] -> [(DepSrc, VersionRange)]
+versionFailures Nothing _ = []
+versionFailures (Just version) result =
+  [ (src, range)
+    | (src, range) <- result,
+      not $ withinRange version range
+  ]
+
+versionErrors :: Maybe Version -> [(DepSrc, VersionRange)] -> [Doc AnsiStyle]
+versionErrors Nothing _ = []
+versionErrors (Just version) result =
+  [ indent 2 $
+      annRed "Error:"
+        <+> viaPretty version
+        <+> "is outside"
+        <+> pretty src
+        <+> "range"
+        <+> parens (viaPretty range)
+    | (src, range) <- result
+  ]
 
 getDepVersion ::
   Members
diff --git a/rdepcheck/Main.hs b/rdepcheck/Main.hs
--- a/rdepcheck/Main.hs
+++ b/rdepcheck/Main.hs
@@ -16,6 +16,7 @@
 import Distribution.ArchHs.Types
 import GHC.IO.Encoding (setLocaleEncoding)
 import GHC.IO.Encoding.UTF8 (utf8)
+import System.Exit (exitFailure)
 
 main :: IO ()
 main = printHandledIOException $
@@ -32,7 +33,19 @@
     extra <- loadExtraDBFromOptions optExtraDB
 
     printInfo "Start running..."
-    runCheck hackage extra optFlags (subsumeGHCVersion $ check optPackageName) & printAppResult
+    runCheck hackage extra optFlags (subsumeGHCVersion $ check optCheckVersion optPackageName) & printRdepcheckResult
+
+printRdepcheckResult :: IO (Either MyException Int) -> IO ()
+printRdepcheckResult io = do
+  result <- io
+  case result of
+    Left x -> do
+      printError $ "Runtime Exception" <> colon <+> viaShow x
+      exitFailure
+    Right 0 -> printSuccess "Success!"
+    Right n -> do
+      printError $ pretty n <+> "reverse dependency range check(s) failed."
+      exitFailure
 
 runCheck ::
   HackageDB ->
diff --git a/src/Distribution/ArchHs/Hackage.hs b/src/Distribution/ArchHs/Hackage.hs
--- a/src/Distribution/ArchHs/Hackage.hs
+++ b/src/Distribution/ArchHs/Hackage.hs
@@ -20,29 +20,60 @@
   )
 where
 
+import Control.Monad (filterM)
 import qualified Data.ByteString as BS
+import Data.List (maximumBy)
 import qualified Data.Map as Map
-import Data.Maybe (fromJust)
+import Data.Maybe (catMaybes, fromJust)
+import Data.Ord (comparing)
 import Distribution.ArchHs.Exception
 import Distribution.ArchHs.Internal.Prelude
 import Distribution.ArchHs.Types
 import Distribution.ArchHs.Utils (getPkgName, getPkgVersion)
 import Distribution.Hackage.DB (HackageDB, VersionData (VersionData, cabalFile), readTarball, tarballHashes)
+import Distribution.Hackage.DB.Path (cabalStateDir)
 import Distribution.PackageDescription.Parsec (parseGenericPackageDescriptionMaybe)
-import System.Directory (findFile, getHomeDirectory, listDirectory)
+import System.Directory (doesDirectoryExist, doesFileExist, getModificationTime, listDirectory)
 
--- | Look up hackage tarball path from @~/.cabal@.
--- Arbitrary hackage mirror is potential to be selected.
--- Preferred to @01-index.tar@, whereas fallback to @00-index.tar@.
+-- | Look up hackage tarball path from Cabal's package index cache.
+-- Preferred to the newest @01-index.tar@, whereas fallback to the newest @00-index.tar@.
 lookupHackagePath :: IO FilePath
 lookupHackagePath = do
-  home <- (\d -> d </> ".cabal" </> "packages") <$> getHomeDirectory
-  subs <- fmap (home </>) <$> listDirectory home
-  legacy <- findFile subs "00-index.tar"
-  new <- findFile subs "01-index.tar"
-  case new <|> legacy of
+  root <- (</> "packages") <$> cabalStateDir
+  candidates <- hackageIndexCandidates root
+  case newestIndex "01-index.tar" candidates <|> newestIndex "00-index.tar" candidates of
     Just x -> return x
-    Nothing -> fail $ "Unable to find hackage index tarball from " <> show subs
+    Nothing -> fail $ "Unable to find hackage index tarball from " <> root
+  where
+    hackageIndexCandidates root = do
+      exists <- doesDirectoryExist root
+      if exists
+        then do
+          rootIndexes <- indexesIn root
+          dirs <- fmap (root </>) <$> listDirectory root
+          repoDirs <- filterM doesDirectoryExist dirs
+          repoIndexes <- concat <$> traverse indexesIn repoDirs
+          pure $ rootIndexes <> repoIndexes
+        else pure []
+
+    indexesIn dir =
+      catMaybes
+        <$> traverse
+          ( \name -> do
+              let path = dir </> name
+              exists <- doesFileExist path
+              if exists
+                then do
+                  time <- getModificationTime path
+                  pure $ Just (name, path, time)
+                else pure Nothing
+          )
+          ["01-index.tar", "00-index.tar"]
+
+    newestIndex name candidates =
+      case filter (\(candidateName, _, _) -> candidateName == name) candidates of
+        [] -> Nothing
+        xs -> Just $ (\(_, path, _) -> path) (maximumBy (comparing (\(_, _, time) -> time)) xs)
 
 -- | Read and parse hackage index tarball.
 loadHackageDB :: FilePath -> IO HackageDB
