Merge branch 'master' into servlet-4

* master:
  gitrepo: update git-repo URL in javadocs
  RefDirectory#refreshPathToLooseRef: also refresh loose ref itself
  RefDirectory#refreshPathToLooseRef: also refresh loose ref itself
  ReceivePack: Add missing @since tag for new API method
  TreeWalkConnectivityChecker: Support non-commit objects in refs
  ReceivePack: make getClientShallowCommits protected
  DfsObjDatabase: Make createDfsPackFile public
  DfsPackCompactor: add a pre-commit hook to plug midx calculation
  Update bouncycastle to 1.84
  [ssh] Reject host certificates if the certified key is revoked
  Add new TreeWalkConnectivityChecker
  Make the PackParser.needNewObjectIds method public
  orbit: update org.apache.ant to 1.10.17.v20260410-1000
  MidxMetadataReader: add private constructor and adjust method visibility
  MidxWriter: Write to tmp files and use atomic rename to commit
  Instrument ReceivePack to track time spent in pre-receive hooks
  Prepare 7.7.0-SNAPSHOT builds
  JGit v7.7.0.202604061937-m1
  Update jetty to 12.1.8
  Update bytebuddy to 1.18.8
  push: Report fatal server errors during pack writing
  Revert "push: Report fatal server errors during pack writing"
  PushConnectionTest: Introducing the limitPackSize() test
  MidxWriter: Do not accept midx to build new midx
  PackDirectory: Integrate Multi-Pack Index (MIDX) support
  PackMidx: A Pack subclass that uses midx
  PackBitmapIndexRemapper: Throw exception with details in size mismatches
  Bazel: bump to 8.6.0 and switch to pure Bzlmod
  MidxMetadataReader: Helper to read only selected fields in the midx
  WindowCursor/Pack: Move bitmap coverage calculation to the pack
  [version.sh] Don't use the pager for the git diff command
  PackBitmapIndexRemapper: Do not remap if the object order is the same
  DfsMidxWriter: Do not accept midx as input to build midx
  javadoc: Mention midx order in the javadoc
  MidxPackList: getAllPlainPacks returns object-lookup order
  MidxPackListTest: Use fake packs for easier test setup
  Slightly reword prunePackExpire docs
  MultiPackIndex: write midx bitmaps from cli tool
  MidxWriter: write bitmaps with the midx
  Update org.tukaani:xz to 1.12
  Update mockito to 5.23.0
  Update Jetty to 12.1.7
  Update bytebuddy to 1.18.7
  Update commons-logging to 1.3.6
  Add jgit-4.40 target platform for next simrel 2026-06
  Use releases p2 repo in jgit-4.39 target platform
  Add timing metrics to ReceivedPackStatistics
  MultiPackIndexWriter: typo in logging (is chunks, not chuncks)
  Add CLAUDE.md to gitignore file

Change-Id: Ibeba788fcad8e71ff3a076f4c3419969ce12e2b8
diff --git a/.bazelrc b/.bazelrc
index 385a71d..2142af8 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -1,7 +1,4 @@
-# TODO(davido): Migrate all dependencies from WORKSPACE to MODULE.bazel
-# https://issues.gerritcodereview.com/issues/303819949
-common --enable_bzlmod --lockfile_mode=error
-common --enable_workspace
+common --lockfile_mode=error
 
 build --workspace_status_command="python3 ./tools/workspace_status.py"
 build --repository_cache=~/.gerritcodereview/bazel-cache/repository
diff --git a/.bazelversion b/.bazelversion
index e8be684..acd405b 100644
--- a/.bazelversion
+++ b/.bazelversion
@@ -1 +1 @@
-7.6.1
+8.6.0
diff --git a/.gitignore b/.gitignore
index 2fd1727..1bf6b52 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@
 target/
 infer-out
 bazel-*
+CLAUDE.md
 
 # Do not add editor- and OS-specific files like *~ (Emacs) and .DS_Store
 # (macOS). Instead, add them to $XDG_CONFIG_HOME/git/ignore
diff --git a/Documentation/config-options.md b/Documentation/config-options.md
index 3d48115..abf7864 100644
--- a/Documentation/config-options.md
+++ b/Documentation/config-options.md
@@ -82,7 +82,7 @@
 | `gc.logExpiry` | `1.day.ago` | ✅ | If the file `gc.log` exists, then auto gc will print its content and exit successfully instead of running unless that file is more than `gc.logExpiry` old. |
 | `gc.packRefs`| `true` | ✅ | This variable determines whether JGit garbage collection will also pack refs. This can be set to `notbare` to enable it within all non-bare repos or it can be set to a boolean value. |
 | `gc.pruneExpire` | `2.weeks.ago` | ✅ | Grace period after which unreachable objects will be pruned. |
-| `gc.prunePackExpire` | `1.hour.ago` |  ⃞ | Grace period after which packfiles only containing unreachable objects will be pruned. |
+| `gc.prunePackExpire` | `1.hour.ago` |  ⃞ | Grace period after which packfiles containing only unreachable objects will be pruned. |
 | `gc.writeChangedPaths` | `false`| ⃞ | Whether bloom filter should be written to commit-graph during a gc operation. |
 | `gc.writeCommitGraph`| `false` | ⃞ | If true, then gc will rewrite the commit-graph file when jgit gc is run. |
 
diff --git a/MODULE.bazel b/MODULE.bazel
index a0629e4..be8f56e 100644
--- a/MODULE.bazel
+++ b/MODULE.bazel
@@ -1,6 +1,8 @@
 module(name = "jgit")
 
-bazel_dep(name = "rules_java", version = "8.11.0")
+bazel_dep(name = "rules_go", version = "0.51.0-rc2")
+bazel_dep(name = "bazel_features", version = "1.39.0")
+bazel_dep(name = "rules_java", version = "8.16.1")
 bazel_dep(name = "rules_jvm_external", version = "6.10")
 bazel_dep(name = "rbe_autoconfig")
 git_override(
@@ -21,11 +23,11 @@
     remote = "https://gerrit.googlesource.com/bazlets",
 )
 
-BOUNCYCASTLE_VERSION = "1.83"
+BOUNCYCASTLE_VERSION = "1.84"
 
-BYTE_BUDDY_VERSION = "1.18.5"
+BYTE_BUDDY_VERSION = "1.18.8"
 
-JETTY_VERSION = "12.1.6"
+JETTY_VERSION = "12.1.8"
 
 JMH_VERSION = "1.37"
 
@@ -47,7 +49,7 @@
         "com.jcraft:jzlib:1.1.3",
         "commons-codec:commons-codec:1.21.0",
         "commons-io:commons-io:2.21.0",
-        "commons-logging:commons-logging:1.3.5",
+        "commons-logging:commons-logging:1.3.6",
         "javax.servlet:javax.servlet-api:4.0.1",
         "junit:junit:4.13.2",
         "net.bytebuddy:byte-buddy-agent:" + BYTE_BUDDY_VERSION,
@@ -78,14 +80,14 @@
         "org.eclipse.jetty.ee8:jetty-ee8-security:" + JETTY_VERSION,
         "org.eclipse.jetty.ee8:jetty-ee8-servlet:" + JETTY_VERSION,
         "org.hamcrest:hamcrest:3.0",
-        "org.mockito:mockito-core:5.21.0",
+        "org.mockito:mockito-core:5.23.0",
         "org.objenesis:objenesis:3.4",
         "org.openjdk.jmh:jmh-core:" + JMH_VERSION,
         "org.openjdk.jmh:jmh-generator-annprocess:" + JMH_VERSION,
         "org.slf4j:slf4j-api:" + SLF4J_VERSION,
         "org.slf4j:jcl-over-slf4j:" + SLF4J_VERSION,
         "org.slf4j:slf4j-simple:" + SLF4J_VERSION,
-        "org.tukaani:xz:1.11",
+        "org.tukaani:xz:1.12",
     ],
     duplicate_version_warning = "warn",
     fail_on_missing_checksum = True,
diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock
index 5717851..7faac96 100644
--- a/MODULE.bazel.lock
+++ b/MODULE.bazel.lock
@@ -1,5 +1,5 @@
 {
-  "lockFileVersion": 13,
+  "lockFileVersion": 24,
   "registryFileHashes": {
     "https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497",
     "https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2",
@@ -11,13 +11,16 @@
     "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/MODULE.bazel": "37bcdb4440fbb61df6a1c296ae01b327f19e9bb521f9b8e26ec854b6f97309ed",
     "https://bcr.bazel.build/modules/abseil-cpp/20240116.2/MODULE.bazel": "73939767a4686cd9a520d16af5ab440071ed75cec1a876bf2fcfaf1f71987a16",
     "https://bcr.bazel.build/modules/abseil-cpp/20250127.0/MODULE.bazel": "d1086e248cda6576862b4b3fe9ad76a214e08c189af5b42557a6e1888812c5d5",
-    "https://bcr.bazel.build/modules/abseil-cpp/20250127.0/source.json": "1b996859f840d8efc7c720efc61dcf2a84b1261cb3974cbbe9b6666ebf567775",
+    "https://bcr.bazel.build/modules/abseil-cpp/20250127.1/MODULE.bazel": "c4a89e7ceb9bf1e25cf84a9f830ff6b817b72874088bf5141b314726e46a57c1",
+    "https://bcr.bazel.build/modules/abseil-cpp/20250512.1/MODULE.bazel": "d209fdb6f36ffaf61c509fcc81b19e81b411a999a934a032e10cd009a0226215",
+    "https://bcr.bazel.build/modules/abseil-cpp/20250814.0/MODULE.bazel": "c43c16ca2c432566cdb78913964497259903ebe8fb7d9b57b38e9f1425b427b8",
+    "https://bcr.bazel.build/modules/abseil-cpp/20250814.0/source.json": "b88bff599ceaf0f56c264c749b1606f8485cec3b8c38ba30f88a4df9af142861",
     "https://bcr.bazel.build/modules/abseil-py/2.1.0/MODULE.bazel": "5ebe5bf853769c65707e5c28f216798f7a4b1042015e6a36e6d03094d94bec8a",
     "https://bcr.bazel.build/modules/abseil-py/2.1.0/source.json": "0e8fc4f088ce07099c1cd6594c20c7ddbb48b4b3c0849b7d94ba94be88ff042b",
     "https://bcr.bazel.build/modules/apple_support/1.11.1/MODULE.bazel": "1843d7cd8a58369a444fc6000e7304425fba600ff641592161d9f15b179fb896",
     "https://bcr.bazel.build/modules/apple_support/1.15.1/MODULE.bazel": "a0556fefca0b1bb2de8567b8827518f94db6a6e7e7d632b4c48dc5f865bc7c85",
-    "https://bcr.bazel.build/modules/apple_support/1.15.1/source.json": "517f2b77430084c541bc9be2db63fdcbb7102938c5f64c17ee60ffda2e5cf07b",
-    "https://bcr.bazel.build/modules/apple_support/1.5.0/MODULE.bazel": "50341a62efbc483e8a2a6aec30994a58749bd7b885e18dd96aa8c33031e558ef",
+    "https://bcr.bazel.build/modules/apple_support/1.23.1/MODULE.bazel": "53763fed456a968cf919b3240427cf3a9d5481ec5466abc9d5dc51bc70087442",
+    "https://bcr.bazel.build/modules/apple_support/1.23.1/source.json": "d888b44312eb0ad2c21a91d026753f330caa48a25c9b2102fae75eb2b0dcfdd2",
     "https://bcr.bazel.build/modules/bazel_features/1.1.0/MODULE.bazel": "cfd42ff3b815a5f39554d97182657f8c4b9719568eb7fded2b9135f084bf760b",
     "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd",
     "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8",
@@ -28,10 +31,12 @@
     "https://bcr.bazel.build/modules/bazel_features/1.19.0/MODULE.bazel": "59adcdf28230d220f0067b1f435b8537dd033bfff8db21335ef9217919c7fb58",
     "https://bcr.bazel.build/modules/bazel_features/1.21.0/MODULE.bazel": "675642261665d8eea09989aa3b8afb5c37627f1be178382c320d1b46afba5e3b",
     "https://bcr.bazel.build/modules/bazel_features/1.23.0/MODULE.bazel": "fd1ac84bc4e97a5a0816b7fd7d4d4f6d837b0047cf4cbd81652d616af3a6591a",
+    "https://bcr.bazel.build/modules/bazel_features/1.27.0/MODULE.bazel": "621eeee06c4458a9121d1f104efb80f39d34deff4984e778359c60eaf1a8cb65",
     "https://bcr.bazel.build/modules/bazel_features/1.28.0/MODULE.bazel": "4b4200e6cbf8fa335b2c3f43e1d6ef3e240319c33d43d60cc0fbd4b87ece299d",
     "https://bcr.bazel.build/modules/bazel_features/1.3.0/MODULE.bazel": "cdcafe83ec318cda34e02948e81d790aab8df7a929cec6f6969f13a489ccecd9",
     "https://bcr.bazel.build/modules/bazel_features/1.30.0/MODULE.bazel": "a14b62d05969a293b80257e72e597c2da7f717e1e69fa8b339703ed6731bec87",
-    "https://bcr.bazel.build/modules/bazel_features/1.30.0/source.json": "b07e17f067fe4f69f90b03b36ef1e08fe0d1f3cac254c1241a1818773e3423bc",
+    "https://bcr.bazel.build/modules/bazel_features/1.39.0/MODULE.bazel": "28739425c1fc283c91931619749c832b555e60bcd1010b40d8441ce0a5cf726d",
+    "https://bcr.bazel.build/modules/bazel_features/1.39.0/source.json": "f63cbeb4c602098484d57001e5a07d31cb02bbccde9b5e2c9bf0b29d05283e93",
     "https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7",
     "https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a",
     "https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8",
@@ -45,7 +50,8 @@
     "https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917",
     "https://bcr.bazel.build/modules/bazel_skylib/1.7.0/MODULE.bazel": "0db596f4563de7938de764cc8deeabec291f55e8ec15299718b93c4423e9796d",
     "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b",
-    "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/source.json": "f121b43eeefc7c29efbd51b83d08631e2347297c95aac9764a701f2a6a2bb953",
+    "https://bcr.bazel.build/modules/bazel_skylib/1.8.1/MODULE.bazel": "88ade7293becda963e0e3ea33e7d54d3425127e0a326e0d17da085a5f1f03ff6",
+    "https://bcr.bazel.build/modules/bazel_skylib/1.8.1/source.json": "7ebaefba0b03efe59cac88ed5bbc67bcf59a3eff33af937345ede2a38b2d368a",
     "https://bcr.bazel.build/modules/bazel_worker_api/0.0.1/MODULE.bazel": "02a13b77321773b2042e70ee5e4c5e099c8ddee4cf2da9cd420442c36938d4bd",
     "https://bcr.bazel.build/modules/bazel_worker_api/0.0.4/MODULE.bazel": "460aa12d01231a80cce03c548287b433b321d205b0028ae596728c35e5ee442e",
     "https://bcr.bazel.build/modules/bazel_worker_api/0.0.4/source.json": "d353c410d47a8b65d09fa98e83d57ebec257a2c2b9c6e42d6fda1cb25e5464a5",
@@ -64,7 +70,8 @@
     "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6",
     "https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f",
     "https://bcr.bazel.build/modules/googletest/1.15.2/MODULE.bazel": "6de1edc1d26cafb0ea1a6ab3f4d4192d91a312fd2d360b63adaa213cd00b2108",
-    "https://bcr.bazel.build/modules/googletest/1.15.2/source.json": "dbdda654dcb3a0d7a8bc5d0ac5fc7e150b58c2a986025ae5bc634bb2cb61f470",
+    "https://bcr.bazel.build/modules/googletest/1.17.0/MODULE.bazel": "dbec758171594a705933a29fcf69293d2468c49ec1f2ebca65c36f504d72df46",
+    "https://bcr.bazel.build/modules/googletest/1.17.0/source.json": "38e4454b25fc30f15439c0378e57909ab1fd0a443158aa35aec685da727cd713",
     "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075",
     "https://bcr.bazel.build/modules/jsoncpp/1.9.6/MODULE.bazel": "2f8d20d3b7d54143213c4dfc3d98225c42de7d666011528dc8fe91591e2e17b0",
     "https://bcr.bazel.build/modules/jsoncpp/1.9.6/source.json": "a04756d367a2126c3541682864ecec52f92cdee80a35735a3cb249ce015ca000",
@@ -75,13 +82,14 @@
     "https://bcr.bazel.build/modules/package_metadata/0.0.7/source.json": "50639625e937b56115012674c797cca7a05a96b4878c87d803c13dc2b31de8a0",
     "https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5",
     "https://bcr.bazel.build/modules/platforms/0.0.11/MODULE.bazel": "0daefc49732e227caa8bfa834d65dc52e8cc18a2faf80df25e8caea151a9413f",
-    "https://bcr.bazel.build/modules/platforms/0.0.11/source.json": "f7e188b79ebedebfe75e9e1d098b8845226c7992b307e28e1496f23112e8fc29",
     "https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee",
     "https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37",
     "https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615",
     "https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814",
     "https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": "9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d",
     "https://bcr.bazel.build/modules/platforms/0.0.9/MODULE.bazel": "4a87a60c927b56ddd67db50c89acaa62f4ce2a1d2149ccb63ffd871d5ce29ebc",
+    "https://bcr.bazel.build/modules/platforms/1.0.0/MODULE.bazel": "f05feb42b48f1b3c225e4ccf351f367be0371411a803198ec34a389fb22aa580",
+    "https://bcr.bazel.build/modules/platforms/1.0.0/source.json": "f4ff1fd412e0246fd38c82328eb209130ead81d62dcd5a9e40910f867f733d96",
     "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7",
     "https://bcr.bazel.build/modules/protobuf/23.1/MODULE.bazel": "88b393b3eb4101d18129e5db51847cd40a5517a53e81216144a8c32dfeeca52a",
     "https://bcr.bazel.build/modules/protobuf/24.4/MODULE.bazel": "7bc7ce5f2abf36b3b7b7c8218d3acdebb9426aeb35c2257c96445756f970eb12",
@@ -90,11 +98,14 @@
     "https://bcr.bazel.build/modules/protobuf/27.2/MODULE.bazel": "32450b50673882e4c8c3d10a83f3bc82161b213ed2f80d17e38bece8f165c295",
     "https://bcr.bazel.build/modules/protobuf/29.0-rc2/MODULE.bazel": "6241d35983510143049943fc0d57937937122baf1b287862f9dc8590fc4c37df",
     "https://bcr.bazel.build/modules/protobuf/29.0-rc3/MODULE.bazel": "33c2dfa286578573afc55a7acaea3cada4122b9631007c594bf0729f41c8de92",
+    "https://bcr.bazel.build/modules/protobuf/29.0/MODULE.bazel": "319dc8bf4c679ff87e71b1ccfb5a6e90a6dbc4693501d471f48662ac46d04e4e",
+    "https://bcr.bazel.build/modules/protobuf/29.1/MODULE.bazel": "557c3457560ff49e122ed76c0bc3397a64af9574691cb8201b4e46d4ab2ecb95",
     "https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0",
     "https://bcr.bazel.build/modules/protobuf/3.19.2/MODULE.bazel": "532ffe5f2186b69fdde039efe6df13ba726ff338c6bc82275ad433013fa10573",
     "https://bcr.bazel.build/modules/protobuf/3.19.6/MODULE.bazel": "9233edc5e1f2ee276a60de3eaa47ac4132302ef9643238f23128fea53ea12858",
     "https://bcr.bazel.build/modules/protobuf/31.1/MODULE.bazel": "379a389bb330b7b8c1cdf331cc90bf3e13de5614799b3b52cdb7c6f389f6b38e",
-    "https://bcr.bazel.build/modules/protobuf/31.1/source.json": "25af5d0219da0c0fc4d1191a24ce438e6ca7f49d2e1a94f354efeba6ef10426f",
+    "https://bcr.bazel.build/modules/protobuf/32.1/MODULE.bazel": "89cd2866a9cb07fee9ff74c41ceace11554f32e0d849de4e23ac55515cfada4d",
+    "https://bcr.bazel.build/modules/protobuf/32.1/source.json": "bd2664e90875c0cd755d1d9b7a103a4b027893ac8eafa3bba087557ffc244ad4",
     "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e",
     "https://bcr.bazel.build/modules/pybind11_bazel/2.12.0/MODULE.bazel": "e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34",
     "https://bcr.bazel.build/modules/pybind11_bazel/2.12.0/source.json": "6900fdc8a9e95866b8c0d4ad4aba4d4236317b5c1cd04c502df3f0d33afed680",
@@ -110,6 +121,7 @@
     "https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647",
     "https://bcr.bazel.build/modules/rules_cc/0.0.10/MODULE.bazel": "ec1705118f7eaedd6e118508d3d26deba2a4e76476ada7e0e3965211be012002",
     "https://bcr.bazel.build/modules/rules_cc/0.0.13/MODULE.bazel": "0e8529ed7b323dad0775ff924d2ae5af7640b23553dfcd4d34344c7e7a867191",
+    "https://bcr.bazel.build/modules/rules_cc/0.0.14/MODULE.bazel": "5e343a3aac88b8d7af3b1b6d2093b55c347b8eefc2e7d1442f7a02dc8fea48ac",
     "https://bcr.bazel.build/modules/rules_cc/0.0.15/MODULE.bazel": "6704c35f7b4a72502ee81f61bf88706b54f06b3cbe5558ac17e2e14666cd5dcc",
     "https://bcr.bazel.build/modules/rules_cc/0.0.16/MODULE.bazel": "7661303b8fc1b4d7f532e54e9d6565771fea666fbdf839e0a86affcd02defe87",
     "https://bcr.bazel.build/modules/rules_cc/0.0.17/MODULE.bazel": "2ae1d8f4238ec67d7185d8861cb0a2cdf4bc608697c331b95bf990e69b62e64a",
@@ -118,8 +130,10 @@
     "https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e",
     "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5",
     "https://bcr.bazel.build/modules/rules_cc/0.1.1/MODULE.bazel": "2f0222a6f229f0bf44cd711dc13c858dad98c62d52bd51d8fc3a764a83125513",
+    "https://bcr.bazel.build/modules/rules_cc/0.2.0/MODULE.bazel": "b5c17f90458caae90d2ccd114c81970062946f49f355610ed89bebf954f5783c",
     "https://bcr.bazel.build/modules/rules_cc/0.2.14/MODULE.bazel": "353c99ed148887ee89c54a17d4100ae7e7e436593d104b668476019023b58df8",
     "https://bcr.bazel.build/modules/rules_cc/0.2.14/source.json": "55d0a4587c5592fad350f6e698530f4faf0e7dd15e69d43f8d87e220c78bea54",
+    "https://bcr.bazel.build/modules/rules_cc/0.2.8/MODULE.bazel": "f1df20f0bf22c28192a794f29b501ee2018fa37a3862a1a2132ae2940a23a642",
     "https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6",
     "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8",
     "https://bcr.bazel.build/modules/rules_go/0.41.0/MODULE.bazel": "55861d8e8bb0e62cbd2896f60ff303f62ffcb0eddb74ecb0e5c0cbe36fc292c8",
@@ -130,18 +144,21 @@
     "https://bcr.bazel.build/modules/rules_go/0.51.0-rc2/source.json": "6b5cd0b3da2bd0e6949580851db990a04af0a285f072b9a0f059424457cd8cc9",
     "https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74",
     "https://bcr.bazel.build/modules/rules_java/5.3.5/MODULE.bazel": "a4ec4f2db570171e3e5eb753276ee4b389bae16b96207e9d3230895c99644b86",
+    "https://bcr.bazel.build/modules/rules_java/6.0.0/MODULE.bazel": "8a43b7df601a7ec1af61d79345c17b31ea1fedc6711fd4abfd013ea612978e39",
     "https://bcr.bazel.build/modules/rules_java/6.3.0/MODULE.bazel": "a97c7678c19f236a956ad260d59c86e10a463badb7eb2eda787490f4c969b963",
+    "https://bcr.bazel.build/modules/rules_java/6.4.0/MODULE.bazel": "e986a9fe25aeaa84ac17ca093ef13a4637f6107375f64667a15999f77db6c8f6",
     "https://bcr.bazel.build/modules/rules_java/6.5.2/MODULE.bazel": "1d440d262d0e08453fa0c4d8f699ba81609ed0e9a9a0f02cd10b3e7942e61e31",
     "https://bcr.bazel.build/modules/rules_java/7.1.0/MODULE.bazel": "30d9135a2b6561c761bd67bd4990da591e6bdc128790ce3e7afd6a3558b2fb64",
     "https://bcr.bazel.build/modules/rules_java/7.10.0/MODULE.bazel": "530c3beb3067e870561739f1144329a21c851ff771cd752a49e06e3dc9c2e71a",
     "https://bcr.bazel.build/modules/rules_java/7.12.2/MODULE.bazel": "579c505165ee757a4280ef83cda0150eea193eed3bef50b1004ba88b99da6de6",
     "https://bcr.bazel.build/modules/rules_java/7.2.0/MODULE.bazel": "06c0334c9be61e6cef2c8c84a7800cef502063269a5af25ceb100b192453d4ab",
+    "https://bcr.bazel.build/modules/rules_java/7.3.2/MODULE.bazel": "50dece891cfdf1741ea230d001aa9c14398062f2b7c066470accace78e412bc2",
     "https://bcr.bazel.build/modules/rules_java/7.4.0/MODULE.bazel": "a592852f8a3dd539e82ee6542013bf2cadfc4c6946be8941e189d224500a8934",
     "https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": "2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe",
-    "https://bcr.bazel.build/modules/rules_java/7.6.5/MODULE.bazel": "481164be5e02e4cab6e77a36927683263be56b7e36fef918b458d7a8a1ebadb1",
-    "https://bcr.bazel.build/modules/rules_java/8.11.0/MODULE.bazel": "c3d280bc5ff1038dcb3bacb95d3f6b83da8dd27bba57820ec89ea4085da767ad",
     "https://bcr.bazel.build/modules/rules_java/8.13.0/MODULE.bazel": "0444ebf737d144cf2bb2ccb368e7f1cce735264285f2a3711785827c1686625e",
-    "https://bcr.bazel.build/modules/rules_java/8.13.0/source.json": "4605c0f676b87dd9d1fabd4d743b71f04d97503bd1a79aad53f87399fb5396de",
+    "https://bcr.bazel.build/modules/rules_java/8.14.0/MODULE.bazel": "717717ed40cc69994596a45aec6ea78135ea434b8402fb91b009b9151dd65615",
+    "https://bcr.bazel.build/modules/rules_java/8.16.1/MODULE.bazel": "0f20b1cecaa8e52f60a8f071e59a20b4e3b9a67f6c56c802ea256f6face692d3",
+    "https://bcr.bazel.build/modules/rules_java/8.16.1/source.json": "072f8d11264edc499621be2dc9ea01d6395db5aa6f8799c034ae01a3e857f2e4",
     "https://bcr.bazel.build/modules/rules_java/8.3.2/MODULE.bazel": "7336d5511ad5af0b8615fdc7477535a2e4e723a357b6713af439fe8cf0195017",
     "https://bcr.bazel.build/modules/rules_java/8.5.1/MODULE.bazel": "d8a9e38cc5228881f7055a6079f6f7821a073df3744d441978e7a43e20226939",
     "https://bcr.bazel.build/modules/rules_java/8.6.0/MODULE.bazel": "9c064c434606d75a086f15ade5edb514308cccd1544c2b2a89bbac4310e41c71",
@@ -149,12 +166,15 @@
     "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7",
     "https://bcr.bazel.build/modules/rules_jvm_external/5.1/MODULE.bazel": "33f6f999e03183f7d088c9be518a63467dfd0be94a11d0055fe2d210f89aa909",
     "https://bcr.bazel.build/modules/rules_jvm_external/5.2/MODULE.bazel": "d9351ba35217ad0de03816ef3ed63f89d411349353077348a45348b096615036",
+    "https://bcr.bazel.build/modules/rules_jvm_external/5.3/MODULE.bazel": "bf93870767689637164657731849fb887ad086739bd5d360d90007a581d5527d",
+    "https://bcr.bazel.build/modules/rules_jvm_external/6.1/MODULE.bazel": "75b5fec090dbd46cf9b7d8ea08cf84a0472d92ba3585b476f44c326eda8059c4",
     "https://bcr.bazel.build/modules/rules_jvm_external/6.10/MODULE.bazel": "33e636ca6bc9ee0fa090a38aa33c631ded2d8cf6fead4124181d1b35dc474f7c",
     "https://bcr.bazel.build/modules/rules_jvm_external/6.10/source.json": "c191249787625db72616a3fb3cc2786ab57355a2e3b615402b8b3b66b0f995b7",
     "https://bcr.bazel.build/modules/rules_jvm_external/6.2/MODULE.bazel": "36a6e52487a855f33cb960724eb56547fa87e2c98a0474c3acad94339d7f8e99",
     "https://bcr.bazel.build/modules/rules_jvm_external/6.3/MODULE.bazel": "c998e060b85f71e00de5ec552019347c8bca255062c990ac02d051bb80a38df0",
     "https://bcr.bazel.build/modules/rules_jvm_external/6.6/MODULE.bazel": "153042249c7060536dc95b6bb9f9bb8063b8a0b0cb7acdb381bddbc2374aed55",
     "https://bcr.bazel.build/modules/rules_jvm_external/6.7/MODULE.bazel": "e717beabc4d091ecb2c803c2d341b88590e9116b8bf7947915eeb33aab4f96dd",
+    "https://bcr.bazel.build/modules/rules_kotlin/1.9.0/MODULE.bazel": "ef85697305025e5a61f395d4eaede272a5393cee479ace6686dba707de804d59",
     "https://bcr.bazel.build/modules/rules_kotlin/1.9.5/MODULE.bazel": "043a16a572f610558ec2030db3ff0c9938574e7dd9f58bded1bb07c0192ef025",
     "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/MODULE.bazel": "d269a01a18ee74d0335450b10f62c9ed81f2321d7958a2934e44272fe82dcef3",
     "https://bcr.bazel.build/modules/rules_kotlin/2.1.3/MODULE.bazel": "ce7def6d576aa8d3a9c6d10e13b4d157296229674371f67dbf788dae0afae3d5",
@@ -172,9 +192,9 @@
     "https://bcr.bazel.build/modules/rules_proto/6.0.0/MODULE.bazel": "b531d7f09f58dce456cd61b4579ce8c86b38544da75184eadaf0a7cb7966453f",
     "https://bcr.bazel.build/modules/rules_proto/6.0.2/MODULE.bazel": "ce916b775a62b90b61888052a416ccdda405212b6aaeb39522f7dc53431a5e73",
     "https://bcr.bazel.build/modules/rules_proto/7.0.2/MODULE.bazel": "bf81793bd6d2ad89a37a40693e56c61b0ee30f7a7fdbaf3eabbf5f39de47dea2",
-    "https://bcr.bazel.build/modules/rules_proto/7.0.2/source.json": "1e5e7260ae32ef4f2b52fd1d0de8d03b606a44c91b694d2f1afb1d3b28a48ce1",
+    "https://bcr.bazel.build/modules/rules_proto/7.1.0/MODULE.bazel": "002d62d9108f75bb807cd56245d45648f38275cb3a99dcd45dfb864c5d74cb96",
+    "https://bcr.bazel.build/modules/rules_proto/7.1.0/source.json": "39f89066c12c24097854e8f57ab8558929f9c8d474d34b2c00ac04630ad8940e",
     "https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f",
-    "https://bcr.bazel.build/modules/rules_python/0.22.1/MODULE.bazel": "26114f0c0b5e93018c0c066d6673f1a2c3737c7e90af95eff30cfee38d0bbac7",
     "https://bcr.bazel.build/modules/rules_python/0.23.1/MODULE.bazel": "49ffccf0511cb8414de28321f5fcf2a31312b47c40cc21577144b7447f2bf300",
     "https://bcr.bazel.build/modules/rules_python/0.25.0/MODULE.bazel": "72f1506841c920a1afec76975b35312410eea3aa7b63267436bfb1dd91d2d382",
     "https://bcr.bazel.build/modules/rules_python/0.28.0/MODULE.bazel": "cba2573d870babc976664a912539b320cbaa7114cd3e8f053c720171cde331ed",
@@ -183,8 +203,10 @@
     "https://bcr.bazel.build/modules/rules_python/0.37.1/MODULE.bazel": "3faeb2d9fa0a81f8980643ee33f212308f4d93eea4b9ce6f36d0b742e71e9500",
     "https://bcr.bazel.build/modules/rules_python/0.37.2/MODULE.bazel": "b5ffde91410745750b6c13be1c5dc4555ef5bc50562af4a89fd77807fdde626a",
     "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c",
+    "https://bcr.bazel.build/modules/rules_python/0.40.0/MODULE.bazel": "9d1a3cd88ed7d8e39583d9ffe56ae8a244f67783ae89b60caafc9f5cf318ada7",
     "https://bcr.bazel.build/modules/rules_python/1.0.0/MODULE.bazel": "898a3d999c22caa585eb062b600f88654bf92efb204fa346fb55f6f8edffca43",
-    "https://bcr.bazel.build/modules/rules_python/1.0.0/source.json": "b0162a65c6312e45e7912e39abd1a7f8856c2c7e41ecc9b6dc688a6f6400a917",
+    "https://bcr.bazel.build/modules/rules_python/1.4.1/MODULE.bazel": "8991ad45bdc25018301d6b7e1d3626afc3c8af8aaf4bc04f23d0b99c938b73a6",
+    "https://bcr.bazel.build/modules/rules_python/1.4.1/source.json": "8ec8c90c70ccacc4de8ca1b97f599e756fb59173e898ee08b733006650057c07",
     "https://bcr.bazel.build/modules/rules_robolectric/4.14.1.2/MODULE.bazel": "d44fec647d0aeb67b9f3b980cf68ba634976f3ae7ccd6c07d790b59b87a4f251",
     "https://bcr.bazel.build/modules/rules_robolectric/4.14.1.2/source.json": "37c10335f2361c337c5c1f34ed36d2da70534c23088062b33a8bdaab68aa9dea",
     "https://bcr.bazel.build/modules/rules_shell/0.1.2/MODULE.bazel": "66e4ca3ce084b04af0b9ff05ff14cab4e5df7503973818bb91cbc6cda08d32fc",
@@ -197,8 +219,10 @@
     "https://bcr.bazel.build/modules/rules_swift/2.1.1/source.json": "40fc69dfaac64deddbb75bd99cdac55f4427d9ca0afbe408576a65428427a186",
     "https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8",
     "https://bcr.bazel.build/modules/stardoc/0.5.3/MODULE.bazel": "c7f6948dae6999bf0db32c1858ae345f112cacf98f174c7a8bb707e41b974f1c",
+    "https://bcr.bazel.build/modules/stardoc/0.5.6/MODULE.bazel": "c43dabc564990eeab55e25ed61c07a1aadafe9ece96a4efabb3f8bf9063b71ef",
     "https://bcr.bazel.build/modules/stardoc/0.6.2/MODULE.bazel": "7060193196395f5dd668eda046ccbeacebfd98efc77fed418dbe2b82ffaa39fd",
     "https://bcr.bazel.build/modules/stardoc/0.7.0/MODULE.bazel": "05e3d6d30c099b6770e97da986c53bd31844d7f13d41412480ea265ac9e8079c",
+    "https://bcr.bazel.build/modules/stardoc/0.7.1/MODULE.bazel": "3548faea4ee5dda5580f9af150e79d0f6aea934fc60c1cc50f4efdd9420759e7",
     "https://bcr.bazel.build/modules/stardoc/0.7.2/MODULE.bazel": "fc152419aa2ea0f51c29583fab1e8c99ddefd5b3778421845606ee628629e0e5",
     "https://bcr.bazel.build/modules/stardoc/0.7.2/source.json": "58b029e5e901d6802967754adf0a9056747e8176f017cfe3607c0851f4d42216",
     "https://bcr.bazel.build/modules/swift_argument_parser/1.3.1.1/MODULE.bazel": "5e463fbfba7b1701d957555ed45097d7f984211330106ccd1352c6e0af0dcf91",
@@ -207,56 +231,26 @@
     "https://bcr.bazel.build/modules/upb/0.0.0-20230516-61a97ef/MODULE.bazel": "c0df5e35ad55e264160417fd0875932ee3c9dda63d9fccace35ac62f45e1b6f9",
     "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0",
     "https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27",
-    "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/MODULE.bazel": "af322bc08976524477c79d1e45e241b6efbeb918c497e8840b8ab116802dda79",
     "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca",
     "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/source.json": "22bc55c47af97246cfc093d0acf683a7869377de362b5d1c552c2c2e16b7a806",
     "https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198"
   },
   "selectedYankedVersions": {},
   "moduleExtensions": {
-    "@@apple_support~//crosstool:setup.bzl%apple_cc_configure_extension": {
+    "@@pybind11_bazel+//:internal_configure.bzl%internal_configure_extension": {
       "general": {
-        "bzlTransitiveDigest": "ltCGFbl/LQQZXn/LEMXfKX7pGwyqNiOCHcmiQW0tmjM=",
-        "usagesDigest": "eXsWd8YDJDt7+F94YtjKuTAIRMWBi9JLS8hUiqynRIY=",
-        "recordedFileInputs": {},
-        "recordedDirentsInputs": {},
-        "envVariables": {},
-        "generatedRepoSpecs": {
-          "local_config_apple_cc_toolchains": {
-            "bzlFile": "@@apple_support~//crosstool:setup.bzl",
-            "ruleClassName": "_apple_cc_autoconf_toolchains",
-            "attributes": {}
-          },
-          "local_config_apple_cc": {
-            "bzlFile": "@@apple_support~//crosstool:setup.bzl",
-            "ruleClassName": "_apple_cc_autoconf",
-            "attributes": {}
-          }
-        },
-        "recordedRepoMappingEntries": [
-          [
-            "apple_support~",
-            "bazel_tools",
-            "bazel_tools"
-          ]
-        ]
-      }
-    },
-    "@@pybind11_bazel~//:internal_configure.bzl%internal_configure_extension": {
-      "general": {
-        "bzlTransitiveDigest": "CyAKLVVonohnkTSqg9II/HA7M49sOlnMkgMHL3CmDuc=",
-        "usagesDigest": "mFrTHX5eCiNU/OIIGVHH3cOILY9Zmjqk8RQYv8o6Thk=",
+        "bzlTransitiveDigest": "NFQjcZF+fAvf5fDH+pqsx4JrfzP9PuHBz6S6ZutIbnw=",
+        "usagesDigest": "D1r3lfzMuUBFxgG8V6o0bQTLMk3GkaGOaPzw53wrwyw=",
         "recordedFileInputs": {
-          "@@pybind11_bazel~//MODULE.bazel": "e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34"
+          "@@pybind11_bazel+//MODULE.bazel": "e6f4c20442eaa7c90d7190d8dc539d0ab422f95c65a57cc59562170c58ae3d34"
         },
         "recordedDirentsInputs": {},
         "envVariables": {},
         "generatedRepoSpecs": {
           "pybind11": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
+            "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
             "attributes": {
-              "build_file": "@@pybind11_bazel~//:pybind11-BUILD.bazel",
+              "build_file": "@@pybind11_bazel+//:pybind11-BUILD.bazel",
               "strip_prefix": "pybind11-2.12.0",
               "urls": [
                 "https://github.com/pybind/pybind11/archive/v2.12.0.zip"
@@ -266,161 +260,181 @@
         },
         "recordedRepoMappingEntries": [
           [
-            "pybind11_bazel~",
+            "pybind11_bazel+",
             "bazel_tools",
             "bazel_tools"
           ]
         ]
       }
     },
-    "@@rules_android~//bzlmod_extensions:apksig.bzl%apksig_extension": {
+    "@@rules_android+//bzlmod_extensions:apksig.bzl%apksig_extension": {
       "general": {
-        "bzlTransitiveDigest": "+fNvC5PNWx1aA64JjkW33+1zGbG9xgfi70xQhxbglhY=",
-        "usagesDigest": "TaGkNxVMBZxl1ANdUNPmIjKrA33bO+BpI06yTlpHdos=",
+        "bzlTransitiveDigest": "By9qVNN7G4oL1vYOJXye7Dp/CbR2ar9oxAW8WXAVcVw=",
+        "usagesDigest": "xq6OVkELeJvOgYo3oY/sUBsGFbcqdV+9BYiNgSPV/po=",
         "recordedFileInputs": {},
         "recordedDirentsInputs": {},
         "envVariables": {},
         "generatedRepoSpecs": {
           "apksig": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
+            "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
             "attributes": {
               "url": "https://android.googlesource.com/platform/tools/apksig/+archive/24e3075e68ebe17c0b529bb24bfda819db5e2f3b.tar.gz",
-              "build_file": "@@rules_android~//bzlmod_extensions:apksig.BUILD"
+              "build_file": "@@rules_android+//bzlmod_extensions:apksig.BUILD"
             }
           }
         },
         "recordedRepoMappingEntries": [
           [
-            "rules_android~",
+            "rules_android+",
             "bazel_tools",
             "bazel_tools"
           ]
         ]
       }
     },
-    "@@rules_android~//bzlmod_extensions:com_android_dex.bzl%com_android_dex_extension": {
+    "@@rules_android+//bzlmod_extensions:com_android_dex.bzl%com_android_dex_extension": {
       "general": {
-        "bzlTransitiveDigest": "/KJvxHLYhvSLJihEHN0e5Uzdd7OOMvpFb0BFUl1RUTs=",
-        "usagesDigest": "fh77SU1OUlWN5ivrGpY93+t0MipuVj89/MMUgfTpSa8=",
+        "bzlTransitiveDigest": "rvWbJQc8jInfIAaXIMhSOqUlwM9HVeLey6q0ISvg08Y=",
+        "usagesDigest": "toF8IFMu98H/VU2p1sfVC5fVXVYJunpbbmtM6tOsQXY=",
         "recordedFileInputs": {},
         "recordedDirentsInputs": {},
         "envVariables": {},
         "generatedRepoSpecs": {
           "com_android_dex": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
+            "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
             "attributes": {
               "url": "https://android.googlesource.com/platform/dalvik/+archive/5a81c499a569731e2395f7c8d13c0e0d4e17a2b6.tar.gz",
-              "build_file": "@@rules_android~//bzlmod_extensions:com_android_dex.BUILD"
+              "build_file": "@@rules_android+//bzlmod_extensions:com_android_dex.BUILD"
             }
           }
         },
         "recordedRepoMappingEntries": [
           [
-            "rules_android~",
+            "rules_android+",
             "bazel_tools",
             "bazel_tools"
           ]
         ]
       }
     },
-    "@@rules_android~//rules/android_sdk_repository:rule.bzl%android_sdk_repository_extension": {
+    "@@rules_android+//rules/android_sdk_repository:rule.bzl%android_sdk_repository_extension": {
       "general": {
         "bzlTransitiveDigest": "NAy+0M15JNVEBb8Tny6t7j3lKqTnsAMjoBB6LJ+C370=",
-        "usagesDigest": "weZLGEpNa+fTJZ9CEljWxpN3/kuPzj/ULgebzOt2h4g=",
+        "usagesDigest": "g9Ur6X6qhf9a8MmY9qXU/jFjkyk/aZVBegI0yVMF0z4=",
         "recordedFileInputs": {},
         "recordedDirentsInputs": {},
         "envVariables": {},
         "generatedRepoSpecs": {
           "androidsdk": {
-            "bzlFile": "@@rules_android~//rules/android_sdk_repository:rule.bzl",
-            "ruleClassName": "_android_sdk_repository",
+            "repoRuleId": "@@rules_android+//rules/android_sdk_repository:rule.bzl%_android_sdk_repository",
             "attributes": {}
           }
         },
         "recordedRepoMappingEntries": []
       }
     },
-    "@@rules_apple~//apple:apple.bzl%provisioning_profile_repository_extension": {
+    "@@rules_apple+//apple:apple.bzl%provisioning_profile_repository_extension": {
       "general": {
-        "bzlTransitiveDigest": "OLmLOE2zg0CXXzAR24XTccdOw39pMG2gG6R1VFOgDsE=",
-        "usagesDigest": "cLx5XGjlbSDOpyA053y/jlr4GcaXFVTeHQic6eyG38E=",
+        "bzlTransitiveDigest": "LKT4eTNHatc2Ti8tCILPSTYqQAc4030bEjspG/P+3TI=",
+        "usagesDigest": "vsJl8Rw5NL+5Ag2wdUDoTeRF/5klkXO8545Iy7U1Q08=",
         "recordedFileInputs": {},
         "recordedDirentsInputs": {},
         "envVariables": {},
         "generatedRepoSpecs": {
           "local_provisioning_profiles": {
-            "bzlFile": "@@rules_apple~//apple/internal:local_provisioning_profiles.bzl",
-            "ruleClassName": "provisioning_profile_repository",
+            "repoRuleId": "@@rules_apple+//apple/internal:local_provisioning_profiles.bzl%provisioning_profile_repository",
             "attributes": {}
           }
         },
         "recordedRepoMappingEntries": [
           [
-            "apple_support~",
+            "apple_support+",
             "bazel_skylib",
-            "bazel_skylib~"
+            "bazel_skylib+"
           ],
           [
-            "rules_apple~",
-            "bazel_skylib",
-            "bazel_skylib~"
+            "bazel_tools",
+            "rules_cc",
+            "rules_cc+"
           ],
           [
-            "rules_apple~",
+            "rules_apple+",
+            "bazel_skylib",
+            "bazel_skylib+"
+          ],
+          [
+            "rules_apple+",
             "bazel_tools",
             "bazel_tools"
           ],
           [
-            "rules_apple~",
+            "rules_apple+",
             "build_bazel_apple_support",
-            "apple_support~"
+            "apple_support+"
           ],
           [
-            "rules_apple~",
+            "rules_apple+",
             "build_bazel_rules_swift",
-            "rules_swift~"
+            "rules_swift+"
           ],
           [
-            "rules_swift~",
-            "bazel_skylib",
-            "bazel_skylib~"
-          ],
-          [
-            "rules_swift~",
+            "rules_cc+",
             "bazel_tools",
             "bazel_tools"
           ],
           [
-            "rules_swift~",
+            "rules_cc+",
+            "cc_compatibility_proxy",
+            "rules_cc++compatibility_proxy+cc_compatibility_proxy"
+          ],
+          [
+            "rules_cc+",
+            "rules_cc",
+            "rules_cc+"
+          ],
+          [
+            "rules_cc++compatibility_proxy+cc_compatibility_proxy",
+            "rules_cc",
+            "rules_cc+"
+          ],
+          [
+            "rules_swift+",
+            "bazel_skylib",
+            "bazel_skylib+"
+          ],
+          [
+            "rules_swift+",
+            "bazel_tools",
+            "bazel_tools"
+          ],
+          [
+            "rules_swift+",
             "build_bazel_apple_support",
-            "apple_support~"
+            "apple_support+"
           ],
           [
-            "rules_swift~",
+            "rules_swift+",
             "build_bazel_rules_swift",
-            "rules_swift~"
+            "rules_swift+"
           ],
           [
-            "rules_swift~",
+            "rules_swift+",
             "build_bazel_rules_swift_local_config",
-            "rules_swift~~non_module_deps~build_bazel_rules_swift_local_config"
+            "rules_swift++non_module_deps+build_bazel_rules_swift_local_config"
           ]
         ]
       }
     },
-    "@@rules_apple~//apple:extensions.bzl%non_module_deps": {
+    "@@rules_apple+//apple:extensions.bzl%non_module_deps": {
       "general": {
-        "bzlTransitiveDigest": "LJ3bhNqfW9y6MZFgtKQoPJyUMg/aEZ8H9QXSzK1VOBk=",
-        "usagesDigest": "5FfEPy/Z0Y2V9RbdJRDabgADFdvlfIIrps/5XYOnMNI=",
+        "bzlTransitiveDigest": "4xtddSlWIQdtVNVuvOI62fJfQVETHZCVWFvYYwQHMR4=",
+        "usagesDigest": "M3VqFpeTCo4qmrNKGZw0dxBHvTYDrfV3cscGzlSAhQ4=",
         "recordedFileInputs": {},
         "recordedDirentsInputs": {},
         "envVariables": {},
         "generatedRepoSpecs": {
           "xctestrunner": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
+            "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
             "attributes": {
               "urls": [
                 "https://github.com/google/xctestrunner/archive/b7698df3d435b6491b4b4c0f9fc7a63fbed5e3a6.tar.gz"
@@ -432,24 +446,23 @@
         },
         "recordedRepoMappingEntries": [
           [
-            "rules_apple~",
+            "rules_apple+",
             "bazel_tools",
             "bazel_tools"
           ]
         ]
       }
     },
-    "@@rules_kotlin~//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": {
+    "@@rules_kotlin+//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": {
       "general": {
-        "bzlTransitiveDigest": "BSndOxBXlbe5qZf1NRxf828dpEK6tM429pCnaFoUFYs=",
-        "usagesDigest": "Dg5Nih77FaLAipQB7wgwsAy553a3po0eNGQVTZKgCM8=",
+        "bzlTransitiveDigest": "HJP3wKFbPhB1mSYjJS6kbXEiP+OQxvsBdqpvyJN6I3s=",
+        "usagesDigest": "qTwqmKKUfWcPdvM0waG+CPWrxsbeAWVeUxavm7tEk9E=",
         "recordedFileInputs": {},
         "recordedDirentsInputs": {},
         "envVariables": {},
         "generatedRepoSpecs": {
           "com_github_jetbrains_kotlin_git": {
-            "bzlFile": "@@rules_kotlin~//src/main/starlark/core/repositories:compiler.bzl",
-            "ruleClassName": "kotlin_compiler_git_repository",
+            "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_compiler_git_repository",
             "attributes": {
               "urls": [
                 "https://github.com/JetBrains/kotlin/releases/download/v2.1.0/kotlin-compiler-2.1.0.zip"
@@ -458,16 +471,14 @@
             }
           },
           "com_github_jetbrains_kotlin": {
-            "bzlFile": "@@rules_kotlin~//src/main/starlark/core/repositories:compiler.bzl",
-            "ruleClassName": "kotlin_capabilities_repository",
+            "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:compiler.bzl%kotlin_capabilities_repository",
             "attributes": {
               "git_repository_name": "com_github_jetbrains_kotlin_git",
               "compiler_version": "2.1.0"
             }
           },
           "com_github_google_ksp": {
-            "bzlFile": "@@rules_kotlin~//src/main/starlark/core/repositories:ksp.bzl",
-            "ruleClassName": "ksp_compiler_plugin_repository",
+            "repoRuleId": "@@rules_kotlin+//src/main/starlark/core/repositories:ksp.bzl%ksp_compiler_plugin_repository",
             "attributes": {
               "urls": [
                 "https://github.com/google/ksp/releases/download/2.1.0-1.0.28/artifacts.zip"
@@ -477,8 +488,7 @@
             }
           },
           "com_github_pinterest_ktlint": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_file",
+            "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_file",
             "attributes": {
               "sha256": "a9f923be58fbd32670a17f0b729b1df804af882fa57402165741cb26e5440ca1",
               "urls": [
@@ -488,8 +498,7 @@
             }
           },
           "kotlinx_serialization_core_jvm": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_jar",
+            "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_jar",
             "attributes": {
               "sha256": "29c821a8d4e25cbfe4f2ce96cdd4526f61f8f4e69a135f9612a34a81d93b65f1",
               "urls": [
@@ -498,8 +507,7 @@
             }
           },
           "kotlinx_serialization_json": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_jar",
+            "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_jar",
             "attributes": {
               "sha256": "8c0016890a79ab5980dd520a5ab1a6738023c29aa3b6437c482e0e5fdc06dab1",
               "urls": [
@@ -508,8 +516,7 @@
             }
           },
           "kotlinx_serialization_json_jvm": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_jar",
+            "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_jar",
             "attributes": {
               "sha256": "d3234179bcff1886d53d67c11eca47f7f3cf7b63c349d16965f6db51b7f3dd9a",
               "urls": [
@@ -520,2745 +527,182 @@
         },
         "recordedRepoMappingEntries": [
           [
-            "rules_kotlin~",
+            "rules_kotlin+",
             "bazel_tools",
             "bazel_tools"
           ]
         ]
       }
     },
-    "@@rules_python~//python/extensions:pip.bzl%pip": {
+    "@@rules_python+//python/uv:uv.bzl%uv": {
       "general": {
-        "bzlTransitiveDigest": "AMoojKsX4Iw9GcO0xHbXz11GhPs9wzQ+Ua4OZ3muUzw=",
-        "usagesDigest": "ZVqDJcq4jlkbKBvSiotiO7ElR126/eiKOiKURsvOcoA=",
-        "recordedFileInputs": {
-          "@@rules_python~//tools/publish/requirements_linux.txt": "8175b4c8df50ae2f22d1706961884beeb54e7da27bd2447018314a175981997d",
-          "@@rules_python~//tools/publish/requirements_windows.txt": "7673adc71dc1a81d3661b90924d7a7c0fc998cd508b3cb4174337cef3f2de556",
-          "@@rules_python~//tools/publish/requirements_darwin.txt": "2994136eab7e57b083c3de76faf46f70fad130bc8e7360a7fed2b288b69e79dc"
-        },
+        "bzlTransitiveDigest": "Xpqjnjzy6zZ90Es9Wa888ZLHhn7IsNGbph/e6qoxzw8=",
+        "usagesDigest": "4JapxcpS0mL3524k0TZJffAtVyuRjDHZvN9kBRxxF1U=",
+        "recordedFileInputs": {},
         "recordedDirentsInputs": {},
-        "envVariables": {
-          "RULES_PYTHON_REPO_DEBUG": null,
-          "RULES_PYTHON_REPO_DEBUG_VERBOSITY": null
-        },
+        "envVariables": {},
         "generatedRepoSpecs": {
-          "rules_python_publish_deps_311_backports_tarfile_py3_none_any_77e284d7": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
+          "uv": {
+            "repoRuleId": "@@rules_python+//python/uv/private:uv_toolchains_repo.bzl%uv_toolchains_repo",
             "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
+              "toolchain_type": "'@@rules_python+//python/uv:uv_toolchain_type'",
+              "toolchain_names": [
+                "none"
               ],
-              "filename": "backports.tarfile-1.2.0-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "backports-tarfile==1.2.0",
-              "sha256": "77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34",
-              "urls": [
-                "https://files.pythonhosted.org/packages/b9/fa/123043af240e49752f1c4bd24da5053b6bd00cad78c2be53c0d1e8b975bc/backports.tarfile-1.2.0-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_backports_tarfile_sdist_d75e02c2": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "backports_tarfile-1.2.0.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "backports-tarfile==1.2.0",
-              "sha256": "d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991",
-              "urls": [
-                "https://files.pythonhosted.org/packages/86/72/cd9b395f25e290e633655a100af28cb253e4393396264a98bd5f5951d50f/backports_tarfile-1.2.0.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_certifi_py3_none_any_922820b5": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "certifi-2024.8.30-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "certifi==2024.8.30",
-              "sha256": "922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8",
-              "urls": [
-                "https://files.pythonhosted.org/packages/12/90/3c9ff0512038035f59d279fddeb79f5f1eccd8859f06d6163c58798b9487/certifi-2024.8.30-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_certifi_sdist_bec941d2": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "certifi-2024.8.30.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "certifi==2024.8.30",
-              "sha256": "bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9",
-              "urls": [
-                "https://files.pythonhosted.org/packages/b0/ee/9b19140fe824b367c04c5e1b369942dd754c4c5462d5674002f75c4dedc1/certifi-2024.8.30.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_aarch64_a1ed2dd2": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64"
-              ],
-              "filename": "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "cffi==1.17.1",
-              "sha256": "a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41",
-              "urls": [
-                "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_ppc64le_46bf4316": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64"
-              ],
-              "filename": "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "cffi==1.17.1",
-              "sha256": "46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1",
-              "urls": [
-                "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_s390x_a24ed04c": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64"
-              ],
-              "filename": "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "cffi==1.17.1",
-              "sha256": "a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6",
-              "urls": [
-                "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_x86_64_610faea7": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64"
-              ],
-              "filename": "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "cffi==1.17.1",
-              "sha256": "610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d",
-              "urls": [
-                "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_cffi_cp311_cp311_musllinux_1_1_aarch64_a9b15d49": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64"
-              ],
-              "filename": "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "cffi==1.17.1",
-              "sha256": "a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6",
-              "urls": [
-                "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_cffi_cp311_cp311_musllinux_1_1_x86_64_fc48c783": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64"
-              ],
-              "filename": "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "cffi==1.17.1",
-              "sha256": "fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b",
-              "urls": [
-                "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_cffi_sdist_1c39c601": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "cffi-1.17.1.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "cffi==1.17.1",
-              "sha256": "1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824",
-              "urls": [
-                "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_macosx_10_9_universal2_0d99dd8f": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "charset-normalizer==3.4.0",
-              "sha256": "0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c",
-              "urls": [
-                "https://files.pythonhosted.org/packages/9c/61/73589dcc7a719582bf56aae309b6103d2762b526bffe189d635a7fcfd998/charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_macosx_10_9_x86_64_c57516e5": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "charset-normalizer==3.4.0",
-              "sha256": "c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944",
-              "urls": [
-                "https://files.pythonhosted.org/packages/77/d5/8c982d58144de49f59571f940e329ad6e8615e1e82ef84584c5eeb5e1d72/charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_macosx_11_0_arm64_6dba5d19": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "charset-normalizer==3.4.0",
-              "sha256": "6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee",
-              "urls": [
-                "https://files.pythonhosted.org/packages/bf/19/411a64f01ee971bed3231111b69eb56f9331a769072de479eae7de52296d/charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_aarch64_bf4475b8": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "charset-normalizer==3.4.0",
-              "sha256": "bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c",
-              "urls": [
-                "https://files.pythonhosted.org/packages/4c/92/97509850f0d00e9f14a46bc751daabd0ad7765cff29cdfb66c68b6dad57f/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_ppc64le_ce031db0": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "charset-normalizer==3.4.0",
-              "sha256": "ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6",
-              "urls": [
-                "https://files.pythonhosted.org/packages/e2/29/d227805bff72ed6d6cb1ce08eec707f7cfbd9868044893617eb331f16295/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_s390x_8ff4e7cd": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "charset-normalizer==3.4.0",
-              "sha256": "8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea",
-              "urls": [
-                "https://files.pythonhosted.org/packages/13/bc/87c2c9f2c144bedfa62f894c3007cd4530ba4b5351acb10dc786428a50f0/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_x86_64_3710a975": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "charset-normalizer==3.4.0",
-              "sha256": "3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc",
-              "urls": [
-                "https://files.pythonhosted.org/packages/eb/5b/6f10bad0f6461fa272bfbbdf5d0023b5fb9bc6217c92bf068fa5a99820f5/charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_aarch64_47334db7": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "charset-normalizer==3.4.0",
-              "sha256": "47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594",
-              "urls": [
-                "https://files.pythonhosted.org/packages/d7/a1/493919799446464ed0299c8eef3c3fad0daf1c3cd48bff9263c731b0d9e2/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_ppc64le_f1a2f519": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "charset-normalizer==3.4.0",
-              "sha256": "f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365",
-              "urls": [
-                "https://files.pythonhosted.org/packages/75/d2/0ab54463d3410709c09266dfb416d032a08f97fd7d60e94b8c6ef54ae14b/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_s390x_63bc5c4a": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "charset-normalizer==3.4.0",
-              "sha256": "63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129",
-              "urls": [
-                "https://files.pythonhosted.org/packages/8d/c9/27e41d481557be53d51e60750b85aa40eaf52b841946b3cdeff363105737/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_x86_64_bcb4f8ea": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "charset-normalizer==3.4.0",
-              "sha256": "bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236",
-              "urls": [
-                "https://files.pythonhosted.org/packages/ee/44/4f62042ca8cdc0cabf87c0fc00ae27cd8b53ab68be3605ba6d071f742ad3/charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_charset_normalizer_cp311_cp311_win_amd64_cee4373f": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "charset-normalizer==3.4.0",
-              "sha256": "cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27",
-              "urls": [
-                "https://files.pythonhosted.org/packages/0b/6e/b13bd47fa9023b3699e94abf565b5a2f0b0be6e9ddac9812182596ee62e4/charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_charset_normalizer_py3_none_any_fe9f97fe": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "charset_normalizer-3.4.0-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "charset-normalizer==3.4.0",
-              "sha256": "fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079",
-              "urls": [
-                "https://files.pythonhosted.org/packages/bf/9b/08c0432272d77b04803958a4598a51e2a4b51c06640af8b8f0f908c18bf2/charset_normalizer-3.4.0-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_charset_normalizer_sdist_223217c3": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "charset_normalizer-3.4.0.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "charset-normalizer==3.4.0",
-              "sha256": "223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e",
-              "urls": [
-                "https://files.pythonhosted.org/packages/f2/4f/e1808dc01273379acc506d18f1504eb2d299bd4131743b9fc54d7be4df1e/charset_normalizer-3.4.0.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_17_aarch64_846da004": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64"
-              ],
-              "filename": "cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "cryptography==43.0.3",
-              "sha256": "846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5",
-              "urls": [
-                "https://files.pythonhosted.org/packages/2f/78/55356eb9075d0be6e81b59f45c7b48df87f76a20e73893872170471f3ee8/cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_17_x86_64_0f996e72": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64"
-              ],
-              "filename": "cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "cryptography==43.0.3",
-              "sha256": "0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4",
-              "urls": [
-                "https://files.pythonhosted.org/packages/2a/2c/488776a3dc843f95f86d2f957ca0fc3407d0242b50bede7fad1e339be03f/cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_28_aarch64_f7b178f1": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64"
-              ],
-              "filename": "cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "cryptography==43.0.3",
-              "sha256": "f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7",
-              "urls": [
-                "https://files.pythonhosted.org/packages/7c/04/2345ca92f7a22f601a9c62961741ef7dd0127c39f7310dffa0041c80f16f/cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_28_x86_64_c2e6fc39": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64"
-              ],
-              "filename": "cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "cryptography==43.0.3",
-              "sha256": "c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405",
-              "urls": [
-                "https://files.pythonhosted.org/packages/ac/25/e715fa0bc24ac2114ed69da33adf451a38abb6f3f24ec207908112e9ba53/cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_cryptography_cp39_abi3_musllinux_1_2_aarch64_e1be4655": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64"
-              ],
-              "filename": "cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "cryptography==43.0.3",
-              "sha256": "e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16",
-              "urls": [
-                "https://files.pythonhosted.org/packages/21/ce/b9c9ff56c7164d8e2edfb6c9305045fbc0df4508ccfdb13ee66eb8c95b0e/cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_cryptography_cp39_abi3_musllinux_1_2_x86_64_df6b6c6d": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64"
-              ],
-              "filename": "cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "cryptography==43.0.3",
-              "sha256": "df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73",
-              "urls": [
-                "https://files.pythonhosted.org/packages/2a/33/b3682992ab2e9476b9c81fff22f02c8b0a1e6e1d49ee1750a67d85fd7ed2/cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_cryptography_sdist_315b9001": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "cryptography-43.0.3.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "cryptography==43.0.3",
-              "sha256": "315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805",
-              "urls": [
-                "https://files.pythonhosted.org/packages/0d/05/07b55d1fa21ac18c3a8c79f764e2514e6f6a9698f1be44994f5adf0d29db/cryptography-43.0.3.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_docutils_py3_none_any_dafca5b9": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "docutils-0.21.2-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "docutils==0.21.2",
-              "sha256": "dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2",
-              "urls": [
-                "https://files.pythonhosted.org/packages/8f/d7/9322c609343d929e75e7e5e6255e614fcc67572cfd083959cdef3b7aad79/docutils-0.21.2-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_docutils_sdist_3a6b1873": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "docutils-0.21.2.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "docutils==0.21.2",
-              "sha256": "3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f",
-              "urls": [
-                "https://files.pythonhosted.org/packages/ae/ed/aefcc8cd0ba62a0560c3c18c33925362d46c6075480bfa4df87b28e169a9/docutils-0.21.2.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_idna_py3_none_any_946d195a": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "idna-3.10-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "idna==3.10",
-              "sha256": "946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3",
-              "urls": [
-                "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_idna_sdist_12f65c9b": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "idna-3.10.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "idna==3.10",
-              "sha256": "12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9",
-              "urls": [
-                "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_importlib_metadata_py3_none_any_45e54197": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "importlib_metadata-8.5.0-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "importlib-metadata==8.5.0",
-              "sha256": "45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b",
-              "urls": [
-                "https://files.pythonhosted.org/packages/a0/d9/a1e041c5e7caa9a05c925f4bdbdfb7f006d1f74996af53467bc394c97be7/importlib_metadata-8.5.0-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_importlib_metadata_sdist_71522656": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "importlib_metadata-8.5.0.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "importlib-metadata==8.5.0",
-              "sha256": "71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7",
-              "urls": [
-                "https://files.pythonhosted.org/packages/cd/12/33e59336dca5be0c398a7482335911a33aa0e20776128f038019f1a95f1b/importlib_metadata-8.5.0.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_jaraco_classes_py3_none_any_f662826b": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "jaraco.classes-3.4.0-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "jaraco-classes==3.4.0",
-              "sha256": "f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790",
-              "urls": [
-                "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_jaraco_classes_sdist_47a024b5": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "jaraco.classes-3.4.0.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "jaraco-classes==3.4.0",
-              "sha256": "47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd",
-              "urls": [
-                "https://files.pythonhosted.org/packages/06/c0/ed4a27bc5571b99e3cff68f8a9fa5b56ff7df1c2251cc715a652ddd26402/jaraco.classes-3.4.0.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_jaraco_context_py3_none_any_f797fc48": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "jaraco.context-6.0.1-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "jaraco-context==6.0.1",
-              "sha256": "f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4",
-              "urls": [
-                "https://files.pythonhosted.org/packages/ff/db/0c52c4cf5e4bd9f5d7135ec7669a3a767af21b3a308e1ed3674881e52b62/jaraco.context-6.0.1-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_jaraco_context_sdist_9bae4ea5": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "jaraco_context-6.0.1.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "jaraco-context==6.0.1",
-              "sha256": "9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3",
-              "urls": [
-                "https://files.pythonhosted.org/packages/df/ad/f3777b81bf0b6e7bc7514a1656d3e637b2e8e15fab2ce3235730b3e7a4e6/jaraco_context-6.0.1.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_jaraco_functools_py3_none_any_ad159f13": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "jaraco.functools-4.1.0-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "jaraco-functools==4.1.0",
-              "sha256": "ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649",
-              "urls": [
-                "https://files.pythonhosted.org/packages/9f/4f/24b319316142c44283d7540e76c7b5a6dbd5db623abd86bb7b3491c21018/jaraco.functools-4.1.0-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_jaraco_functools_sdist_70f7e0e2": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "jaraco_functools-4.1.0.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "jaraco-functools==4.1.0",
-              "sha256": "70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d",
-              "urls": [
-                "https://files.pythonhosted.org/packages/ab/23/9894b3df5d0a6eb44611c36aec777823fc2e07740dabbd0b810e19594013/jaraco_functools-4.1.0.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_jeepney_py3_none_any_c0a454ad": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64"
-              ],
-              "filename": "jeepney-0.8.0-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "jeepney==0.8.0",
-              "sha256": "c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755",
-              "urls": [
-                "https://files.pythonhosted.org/packages/ae/72/2a1e2290f1ab1e06f71f3d0f1646c9e4634e70e1d37491535e19266e8dc9/jeepney-0.8.0-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_jeepney_sdist_5efe48d2": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "jeepney-0.8.0.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "jeepney==0.8.0",
-              "sha256": "5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806",
-              "urls": [
-                "https://files.pythonhosted.org/packages/d6/f4/154cf374c2daf2020e05c3c6a03c91348d59b23c5366e968feb198306fdf/jeepney-0.8.0.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_keyring_py3_none_any_5426f817": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "keyring-25.4.1-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "keyring==25.4.1",
-              "sha256": "5426f817cf7f6f007ba5ec722b1bcad95a75b27d780343772ad76b17cb47b0bf",
-              "urls": [
-                "https://files.pythonhosted.org/packages/83/25/e6d59e5f0a0508d0dca8bb98c7f7fd3772fc943ac3f53d5ab18a218d32c0/keyring-25.4.1-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_keyring_sdist_b07ebc55": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "keyring-25.4.1.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "keyring==25.4.1",
-              "sha256": "b07ebc55f3e8ed86ac81dd31ef14e81ace9dd9c3d4b5d77a6e9a2016d0d71a1b",
-              "urls": [
-                "https://files.pythonhosted.org/packages/a5/1c/2bdbcfd5d59dc6274ffb175bc29aa07ecbfab196830e0cfbde7bd861a2ea/keyring-25.4.1.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_markdown_it_py_py3_none_any_35521684": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "markdown_it_py-3.0.0-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "markdown-it-py==3.0.0",
-              "sha256": "355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1",
-              "urls": [
-                "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_markdown_it_py_sdist_e3f60a94": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "markdown-it-py-3.0.0.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "markdown-it-py==3.0.0",
-              "sha256": "e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb",
-              "urls": [
-                "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_mdurl_py3_none_any_84008a41": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "mdurl-0.1.2-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "mdurl==0.1.2",
-              "sha256": "84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8",
-              "urls": [
-                "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_mdurl_sdist_bb413d29": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "mdurl-0.1.2.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "mdurl==0.1.2",
-              "sha256": "bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba",
-              "urls": [
-                "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_more_itertools_py3_none_any_037b0d32": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "more_itertools-10.5.0-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "more-itertools==10.5.0",
-              "sha256": "037b0d3203ce90cca8ab1defbbdac29d5f993fc20131f3664dc8d6acfa872aef",
-              "urls": [
-                "https://files.pythonhosted.org/packages/48/7e/3a64597054a70f7c86eb0a7d4fc315b8c1ab932f64883a297bdffeb5f967/more_itertools-10.5.0-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_more_itertools_sdist_5482bfef": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "more-itertools-10.5.0.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "more-itertools==10.5.0",
-              "sha256": "5482bfef7849c25dc3c6dd53a6173ae4795da2a41a80faea6700d9f5846c5da6",
-              "urls": [
-                "https://files.pythonhosted.org/packages/51/78/65922308c4248e0eb08ebcbe67c95d48615cc6f27854b6f2e57143e9178f/more-itertools-10.5.0.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_nh3_cp37_abi3_macosx_10_12_x86_64_14c5a72e": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "nh3-0.2.18-cp37-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "nh3==0.2.18",
-              "sha256": "14c5a72e9fe82aea5fe3072116ad4661af5cf8e8ff8fc5ad3450f123e4925e86",
-              "urls": [
-                "https://files.pythonhosted.org/packages/b3/89/1daff5d9ba5a95a157c092c7c5f39b8dd2b1ddb4559966f808d31cfb67e0/nh3-0.2.18-cp37-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_nh3_cp37_abi3_macosx_10_12_x86_64_7b7c2a3c": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "nh3-0.2.18-cp37-abi3-macosx_10_12_x86_64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "nh3==0.2.18",
-              "sha256": "7b7c2a3c9eb1a827d42539aa64091640bd275b81e097cd1d8d82ef91ffa2e811",
-              "urls": [
-                "https://files.pythonhosted.org/packages/2c/b6/42fc3c69cabf86b6b81e4c051a9b6e249c5ba9f8155590222c2622961f58/nh3-0.2.18-cp37-abi3-macosx_10_12_x86_64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_aarch64_42c64511": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "nh3==0.2.18",
-              "sha256": "42c64511469005058cd17cc1537578eac40ae9f7200bedcfd1fc1a05f4f8c200",
-              "urls": [
-                "https://files.pythonhosted.org/packages/45/b9/833f385403abaf0023c6547389ec7a7acf141ddd9d1f21573723a6eab39a/nh3-0.2.18-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_armv7l_0411beb0": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "nh3==0.2.18",
-              "sha256": "0411beb0589eacb6734f28d5497ca2ed379eafab8ad8c84b31bb5c34072b7164",
-              "urls": [
-                "https://files.pythonhosted.org/packages/05/2b/85977d9e11713b5747595ee61f381bc820749daf83f07b90b6c9964cf932/nh3-0.2.18-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_ppc64_5f36b271": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "nh3==0.2.18",
-              "sha256": "5f36b271dae35c465ef5e9090e1fdaba4a60a56f0bb0ba03e0932a66f28b9189",
-              "urls": [
-                "https://files.pythonhosted.org/packages/72/f2/5c894d5265ab80a97c68ca36f25c8f6f0308abac649aaf152b74e7e854a8/nh3-0.2.18-cp37-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_ppc64le_34c03fa7": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "nh3==0.2.18",
-              "sha256": "34c03fa78e328c691f982b7c03d4423bdfd7da69cd707fe572f544cf74ac23ad",
-              "urls": [
-                "https://files.pythonhosted.org/packages/ab/a7/375afcc710dbe2d64cfbd69e31f82f3e423d43737258af01f6a56d844085/nh3-0.2.18-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_s390x_19aaba96": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "nh3==0.2.18",
-              "sha256": "19aaba96e0f795bd0a6c56291495ff59364f4300d4a39b29a0abc9cb3774a84b",
-              "urls": [
-                "https://files.pythonhosted.org/packages/c2/a8/3bb02d0c60a03ad3a112b76c46971e9480efa98a8946677b5a59f60130ca/nh3-0.2.18-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_x86_64_de3ceed6": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "nh3-0.2.18-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "nh3==0.2.18",
-              "sha256": "de3ceed6e661954871d6cd78b410213bdcb136f79aafe22aa7182e028b8c7307",
-              "urls": [
-                "https://files.pythonhosted.org/packages/1b/63/6ab90d0e5225ab9780f6c9fb52254fa36b52bb7c188df9201d05b647e5e1/nh3-0.2.18-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_nh3_cp37_abi3_musllinux_1_2_aarch64_f0eca9ca": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "nh3-0.2.18-cp37-abi3-musllinux_1_2_aarch64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "nh3==0.2.18",
-              "sha256": "f0eca9ca8628dbb4e916ae2491d72957fdd35f7a5d326b7032a345f111ac07fe",
-              "urls": [
-                "https://files.pythonhosted.org/packages/a3/da/0c4e282bc3cff4a0adf37005fa1fb42257673fbc1bbf7d1ff639ec3d255a/nh3-0.2.18-cp37-abi3-musllinux_1_2_aarch64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_nh3_cp37_abi3_musllinux_1_2_armv7l_3a157ab1": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "nh3-0.2.18-cp37-abi3-musllinux_1_2_armv7l.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "nh3==0.2.18",
-              "sha256": "3a157ab149e591bb638a55c8c6bcb8cdb559c8b12c13a8affaba6cedfe51713a",
-              "urls": [
-                "https://files.pythonhosted.org/packages/de/81/c291231463d21da5f8bba82c8167a6d6893cc5419b0639801ee5d3aeb8a9/nh3-0.2.18-cp37-abi3-musllinux_1_2_armv7l.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_nh3_cp37_abi3_musllinux_1_2_x86_64_36c95d4b": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "nh3-0.2.18-cp37-abi3-musllinux_1_2_x86_64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "nh3==0.2.18",
-              "sha256": "36c95d4b70530b320b365659bb5034341316e6a9b30f0b25fa9c9eff4c27a204",
-              "urls": [
-                "https://files.pythonhosted.org/packages/eb/61/73a007c74c37895fdf66e0edcd881f5eaa17a348ff02f4bb4bc906d61085/nh3-0.2.18-cp37-abi3-musllinux_1_2_x86_64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_nh3_cp37_abi3_win_amd64_8ce0f819": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "nh3-0.2.18-cp37-abi3-win_amd64.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "nh3==0.2.18",
-              "sha256": "8ce0f819d2f1933953fca255db2471ad58184a60508f03e6285e5114b6254844",
-              "urls": [
-                "https://files.pythonhosted.org/packages/26/8d/53c5b19c4999bdc6ba95f246f4ef35ca83d7d7423e5e38be43ad66544e5d/nh3-0.2.18-cp37-abi3-win_amd64.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_nh3_sdist_94a16692": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "nh3-0.2.18.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "nh3==0.2.18",
-              "sha256": "94a166927e53972a9698af9542ace4e38b9de50c34352b962f4d9a7d4c927af4",
-              "urls": [
-                "https://files.pythonhosted.org/packages/62/73/10df50b42ddb547a907deeb2f3c9823022580a7a47281e8eae8e003a9639/nh3-0.2.18.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_pkginfo_py3_none_any_889a6da2": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "pkginfo-1.10.0-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "pkginfo==1.10.0",
-              "sha256": "889a6da2ed7ffc58ab5b900d888ddce90bce912f2d2de1dc1c26f4cb9fe65097",
-              "urls": [
-                "https://files.pythonhosted.org/packages/56/09/054aea9b7534a15ad38a363a2bd974c20646ab1582a387a95b8df1bfea1c/pkginfo-1.10.0-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_pkginfo_sdist_5df73835": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "pkginfo-1.10.0.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "pkginfo==1.10.0",
-              "sha256": "5df73835398d10db79f8eecd5cd86b1f6d29317589ea70796994d49399af6297",
-              "urls": [
-                "https://files.pythonhosted.org/packages/2f/72/347ec5be4adc85c182ed2823d8d1c7b51e13b9a6b0c1aae59582eca652df/pkginfo-1.10.0.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_pycparser_py3_none_any_c3702b6d": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64"
-              ],
-              "filename": "pycparser-2.22-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "pycparser==2.22",
-              "sha256": "c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc",
-              "urls": [
-                "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_pycparser_sdist_491c8be9": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "pycparser-2.22.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "pycparser==2.22",
-              "sha256": "491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6",
-              "urls": [
-                "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_pygments_py3_none_any_b8e6aca0": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "pygments-2.18.0-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "pygments==2.18.0",
-              "sha256": "b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a",
-              "urls": [
-                "https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_pygments_sdist_786ff802": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "pygments-2.18.0.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "pygments==2.18.0",
-              "sha256": "786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199",
-              "urls": [
-                "https://files.pythonhosted.org/packages/8e/62/8336eff65bcbc8e4cb5d05b55faf041285951b6e80f33e2bff2024788f31/pygments-2.18.0.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_pywin32_ctypes_py3_none_any_8a151337": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_windows_x86_64"
-              ],
-              "filename": "pywin32_ctypes-0.2.3-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "pywin32-ctypes==0.2.3",
-              "sha256": "8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8",
-              "urls": [
-                "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_pywin32_ctypes_sdist_d162dc04": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "pywin32-ctypes-0.2.3.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "pywin32-ctypes==0.2.3",
-              "sha256": "d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755",
-              "urls": [
-                "https://files.pythonhosted.org/packages/85/9f/01a1a99704853cb63f253eea009390c88e7131c67e66a0a02099a8c917cb/pywin32-ctypes-0.2.3.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_readme_renderer_py3_none_any_2fbca89b": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "readme_renderer-44.0-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "readme-renderer==44.0",
-              "sha256": "2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151",
-              "urls": [
-                "https://files.pythonhosted.org/packages/e1/67/921ec3024056483db83953ae8e48079ad62b92db7880013ca77632921dd0/readme_renderer-44.0-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_readme_renderer_sdist_8712034e": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "readme_renderer-44.0.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "readme-renderer==44.0",
-              "sha256": "8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1",
-              "urls": [
-                "https://files.pythonhosted.org/packages/5a/a9/104ec9234c8448c4379768221ea6df01260cd6c2ce13182d4eac531c8342/readme_renderer-44.0.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_requests_py3_none_any_70761cfe": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "requests-2.32.3-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "requests==2.32.3",
-              "sha256": "70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6",
-              "urls": [
-                "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_requests_sdist_55365417": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "requests-2.32.3.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "requests==2.32.3",
-              "sha256": "55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760",
-              "urls": [
-                "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_requests_toolbelt_py2_none_any_cccfdd66": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "requests_toolbelt-1.0.0-py2.py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "requests-toolbelt==1.0.0",
-              "sha256": "cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06",
-              "urls": [
-                "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_requests_toolbelt_sdist_7681a0a3": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "requests-toolbelt-1.0.0.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "requests-toolbelt==1.0.0",
-              "sha256": "7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6",
-              "urls": [
-                "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_rfc3986_py2_none_any_50b1502b": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "rfc3986-2.0.0-py2.py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "rfc3986==2.0.0",
-              "sha256": "50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd",
-              "urls": [
-                "https://files.pythonhosted.org/packages/ff/9a/9afaade874b2fa6c752c36f1548f718b5b83af81ed9b76628329dab81c1b/rfc3986-2.0.0-py2.py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_rfc3986_sdist_97aacf9d": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "rfc3986-2.0.0.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "rfc3986==2.0.0",
-              "sha256": "97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c",
-              "urls": [
-                "https://files.pythonhosted.org/packages/85/40/1520d68bfa07ab5a6f065a186815fb6610c86fe957bc065754e47f7b0840/rfc3986-2.0.0.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_rich_py3_none_any_9836f509": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "rich-13.9.3-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "rich==13.9.3",
-              "sha256": "9836f5096eb2172c9e77df411c1b009bace4193d6a481d534fea75ebba758283",
-              "urls": [
-                "https://files.pythonhosted.org/packages/9a/e2/10e9819cf4a20bd8ea2f5dabafc2e6bf4a78d6a0965daeb60a4b34d1c11f/rich-13.9.3-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_rich_sdist_bc1e01b8": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "rich-13.9.3.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "rich==13.9.3",
-              "sha256": "bc1e01b899537598cf02579d2b9f4a415104d3fc439313a7a2c165d76557a08e",
-              "urls": [
-                "https://files.pythonhosted.org/packages/d9/e9/cf9ef5245d835065e6673781dbd4b8911d352fb770d56cf0879cf11b7ee1/rich-13.9.3.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_secretstorage_py3_none_any_f356e662": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64"
-              ],
-              "filename": "SecretStorage-3.3.3-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "secretstorage==3.3.3",
-              "sha256": "f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99",
-              "urls": [
-                "https://files.pythonhosted.org/packages/54/24/b4293291fa1dd830f353d2cb163295742fa87f179fcc8a20a306a81978b7/SecretStorage-3.3.3-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_secretstorage_sdist_2403533e": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "SecretStorage-3.3.3.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "secretstorage==3.3.3",
-              "sha256": "2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77",
-              "urls": [
-                "https://files.pythonhosted.org/packages/53/a4/f48c9d79cb507ed1373477dbceaba7401fd8a23af63b837fa61f1dcd3691/SecretStorage-3.3.3.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_twine_py3_none_any_215dbe7b": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "twine-5.1.1-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "twine==5.1.1",
-              "sha256": "215dbe7b4b94c2c50a7315c0275d2258399280fbb7d04182c7e55e24b5f93997",
-              "urls": [
-                "https://files.pythonhosted.org/packages/5d/ec/00f9d5fd040ae29867355e559a94e9a8429225a0284a3f5f091a3878bfc0/twine-5.1.1-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_twine_sdist_9aa08251": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "twine-5.1.1.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "twine==5.1.1",
-              "sha256": "9aa0825139c02b3434d913545c7b847a21c835e11597f5255842d457da2322db",
-              "urls": [
-                "https://files.pythonhosted.org/packages/77/68/bd982e5e949ef8334e6f7dcf76ae40922a8750aa2e347291ae1477a4782b/twine-5.1.1.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_urllib3_py3_none_any_ca899ca0": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "urllib3-2.2.3-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "urllib3==2.2.3",
-              "sha256": "ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac",
-              "urls": [
-                "https://files.pythonhosted.org/packages/ce/d9/5f4c13cecde62396b0d3fe530a50ccea91e7dfc1ccf0e09c228841bb5ba8/urllib3-2.2.3-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_urllib3_sdist_e7d814a8": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "urllib3-2.2.3.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "urllib3==2.2.3",
-              "sha256": "e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9",
-              "urls": [
-                "https://files.pythonhosted.org/packages/ed/63/22ba4ebfe7430b76388e7cd448d5478814d3032121827c12a2cc287e2260/urllib3-2.2.3.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_zipp_py3_none_any_a817ac80": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "filename": "zipp-3.20.2-py3-none-any.whl",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "zipp==3.20.2",
-              "sha256": "a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350",
-              "urls": [
-                "https://files.pythonhosted.org/packages/62/8b/5ba542fa83c90e09eac972fc9baca7a88e7e7ca4b221a89251954019308b/zipp-3.20.2-py3-none-any.whl"
-              ]
-            }
-          },
-          "rules_python_publish_deps_311_zipp_sdist_bc9eb26f": {
-            "bzlFile": "@@rules_python~//python/private/pypi:whl_library.bzl",
-            "ruleClassName": "whl_library",
-            "attributes": {
-              "dep_template": "@rules_python_publish_deps//{name}:{target}",
-              "experimental_target_platforms": [
-                "cp311_linux_aarch64",
-                "cp311_linux_arm",
-                "cp311_linux_ppc",
-                "cp311_linux_s390x",
-                "cp311_linux_x86_64",
-                "cp311_osx_aarch64",
-                "cp311_osx_x86_64",
-                "cp311_windows_x86_64"
-              ],
-              "extra_pip_args": [
-                "--index-url",
-                "https://pypi.org/simple"
-              ],
-              "filename": "zipp-3.20.2.tar.gz",
-              "python_interpreter_target": "@@rules_python~~python~python_3_11_host//:python",
-              "repo": "rules_python_publish_deps_311",
-              "requirement": "zipp==3.20.2",
-              "sha256": "bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29",
-              "urls": [
-                "https://files.pythonhosted.org/packages/54/bf/5c0000c44ebc80123ecbdddba1f5dcd94a5ada602a9c225d84b5aaa55e86/zipp-3.20.2.tar.gz"
-              ]
-            }
-          },
-          "rules_python_publish_deps": {
-            "bzlFile": "@@rules_python~//python/private/pypi:hub_repository.bzl",
-            "ruleClassName": "hub_repository",
-            "attributes": {
-              "repo_name": "rules_python_publish_deps",
-              "extra_hub_aliases": {},
-              "whl_map": {
-                "backports_tarfile": "{\"rules_python_publish_deps_311_backports_tarfile_py3_none_any_77e284d7\":[{\"filename\":\"backports.tarfile-1.2.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_backports_tarfile_sdist_d75e02c2\":[{\"filename\":\"backports_tarfile-1.2.0.tar.gz\",\"version\":\"3.11\"}]}",
-                "certifi": "{\"rules_python_publish_deps_311_certifi_py3_none_any_922820b5\":[{\"filename\":\"certifi-2024.8.30-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_certifi_sdist_bec941d2\":[{\"filename\":\"certifi-2024.8.30.tar.gz\",\"version\":\"3.11\"}]}",
-                "cffi": "{\"rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_aarch64_a1ed2dd2\":[{\"filename\":\"cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_ppc64le_46bf4316\":[{\"filename\":\"cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_s390x_a24ed04c\":[{\"filename\":\"cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cffi_cp311_cp311_manylinux_2_17_x86_64_610faea7\":[{\"filename\":\"cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cffi_cp311_cp311_musllinux_1_1_aarch64_a9b15d49\":[{\"filename\":\"cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cffi_cp311_cp311_musllinux_1_1_x86_64_fc48c783\":[{\"filename\":\"cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cffi_sdist_1c39c601\":[{\"filename\":\"cffi-1.17.1.tar.gz\",\"version\":\"3.11\"}]}",
-                "charset_normalizer": "{\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_macosx_10_9_universal2_0d99dd8f\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_macosx_10_9_x86_64_c57516e5\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_macosx_11_0_arm64_6dba5d19\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_aarch64_bf4475b8\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_ppc64le_ce031db0\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_s390x_8ff4e7cd\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_manylinux_2_17_x86_64_3710a975\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_aarch64_47334db7\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_ppc64le_f1a2f519\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_s390x_63bc5c4a\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_musllinux_1_2_x86_64_bcb4f8ea\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_cp311_cp311_win_amd64_cee4373f\":[{\"filename\":\"charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_py3_none_any_fe9f97fe\":[{\"filename\":\"charset_normalizer-3.4.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_charset_normalizer_sdist_223217c3\":[{\"filename\":\"charset_normalizer-3.4.0.tar.gz\",\"version\":\"3.11\"}]}",
-                "cryptography": "{\"rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_17_aarch64_846da004\":[{\"filename\":\"cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_17_x86_64_0f996e72\":[{\"filename\":\"cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_28_aarch64_f7b178f1\":[{\"filename\":\"cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cryptography_cp39_abi3_manylinux_2_28_x86_64_c2e6fc39\":[{\"filename\":\"cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cryptography_cp39_abi3_musllinux_1_2_aarch64_e1be4655\":[{\"filename\":\"cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cryptography_cp39_abi3_musllinux_1_2_x86_64_df6b6c6d\":[{\"filename\":\"cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_cryptography_sdist_315b9001\":[{\"filename\":\"cryptography-43.0.3.tar.gz\",\"version\":\"3.11\"}]}",
-                "docutils": "{\"rules_python_publish_deps_311_docutils_py3_none_any_dafca5b9\":[{\"filename\":\"docutils-0.21.2-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_docutils_sdist_3a6b1873\":[{\"filename\":\"docutils-0.21.2.tar.gz\",\"version\":\"3.11\"}]}",
-                "idna": "{\"rules_python_publish_deps_311_idna_py3_none_any_946d195a\":[{\"filename\":\"idna-3.10-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_idna_sdist_12f65c9b\":[{\"filename\":\"idna-3.10.tar.gz\",\"version\":\"3.11\"}]}",
-                "importlib_metadata": "{\"rules_python_publish_deps_311_importlib_metadata_py3_none_any_45e54197\":[{\"filename\":\"importlib_metadata-8.5.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_importlib_metadata_sdist_71522656\":[{\"filename\":\"importlib_metadata-8.5.0.tar.gz\",\"version\":\"3.11\"}]}",
-                "jaraco_classes": "{\"rules_python_publish_deps_311_jaraco_classes_py3_none_any_f662826b\":[{\"filename\":\"jaraco.classes-3.4.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_jaraco_classes_sdist_47a024b5\":[{\"filename\":\"jaraco.classes-3.4.0.tar.gz\",\"version\":\"3.11\"}]}",
-                "jaraco_context": "{\"rules_python_publish_deps_311_jaraco_context_py3_none_any_f797fc48\":[{\"filename\":\"jaraco.context-6.0.1-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_jaraco_context_sdist_9bae4ea5\":[{\"filename\":\"jaraco_context-6.0.1.tar.gz\",\"version\":\"3.11\"}]}",
-                "jaraco_functools": "{\"rules_python_publish_deps_311_jaraco_functools_py3_none_any_ad159f13\":[{\"filename\":\"jaraco.functools-4.1.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_jaraco_functools_sdist_70f7e0e2\":[{\"filename\":\"jaraco_functools-4.1.0.tar.gz\",\"version\":\"3.11\"}]}",
-                "jeepney": "{\"rules_python_publish_deps_311_jeepney_py3_none_any_c0a454ad\":[{\"filename\":\"jeepney-0.8.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_jeepney_sdist_5efe48d2\":[{\"filename\":\"jeepney-0.8.0.tar.gz\",\"version\":\"3.11\"}]}",
-                "keyring": "{\"rules_python_publish_deps_311_keyring_py3_none_any_5426f817\":[{\"filename\":\"keyring-25.4.1-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_keyring_sdist_b07ebc55\":[{\"filename\":\"keyring-25.4.1.tar.gz\",\"version\":\"3.11\"}]}",
-                "markdown_it_py": "{\"rules_python_publish_deps_311_markdown_it_py_py3_none_any_35521684\":[{\"filename\":\"markdown_it_py-3.0.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_markdown_it_py_sdist_e3f60a94\":[{\"filename\":\"markdown-it-py-3.0.0.tar.gz\",\"version\":\"3.11\"}]}",
-                "mdurl": "{\"rules_python_publish_deps_311_mdurl_py3_none_any_84008a41\":[{\"filename\":\"mdurl-0.1.2-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_mdurl_sdist_bb413d29\":[{\"filename\":\"mdurl-0.1.2.tar.gz\",\"version\":\"3.11\"}]}",
-                "more_itertools": "{\"rules_python_publish_deps_311_more_itertools_py3_none_any_037b0d32\":[{\"filename\":\"more_itertools-10.5.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_more_itertools_sdist_5482bfef\":[{\"filename\":\"more-itertools-10.5.0.tar.gz\",\"version\":\"3.11\"}]}",
-                "nh3": "{\"rules_python_publish_deps_311_nh3_cp37_abi3_macosx_10_12_x86_64_14c5a72e\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_macosx_10_12_x86_64_7b7c2a3c\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-macosx_10_12_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_aarch64_42c64511\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_armv7l_0411beb0\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_ppc64_5f36b271\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_ppc64le_34c03fa7\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_s390x_19aaba96\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_manylinux_2_17_x86_64_de3ceed6\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_musllinux_1_2_aarch64_f0eca9ca\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-musllinux_1_2_aarch64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_musllinux_1_2_armv7l_3a157ab1\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-musllinux_1_2_armv7l.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_musllinux_1_2_x86_64_36c95d4b\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-musllinux_1_2_x86_64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_cp37_abi3_win_amd64_8ce0f819\":[{\"filename\":\"nh3-0.2.18-cp37-abi3-win_amd64.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_nh3_sdist_94a16692\":[{\"filename\":\"nh3-0.2.18.tar.gz\",\"version\":\"3.11\"}]}",
-                "pkginfo": "{\"rules_python_publish_deps_311_pkginfo_py3_none_any_889a6da2\":[{\"filename\":\"pkginfo-1.10.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_pkginfo_sdist_5df73835\":[{\"filename\":\"pkginfo-1.10.0.tar.gz\",\"version\":\"3.11\"}]}",
-                "pycparser": "{\"rules_python_publish_deps_311_pycparser_py3_none_any_c3702b6d\":[{\"filename\":\"pycparser-2.22-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_pycparser_sdist_491c8be9\":[{\"filename\":\"pycparser-2.22.tar.gz\",\"version\":\"3.11\"}]}",
-                "pygments": "{\"rules_python_publish_deps_311_pygments_py3_none_any_b8e6aca0\":[{\"filename\":\"pygments-2.18.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_pygments_sdist_786ff802\":[{\"filename\":\"pygments-2.18.0.tar.gz\",\"version\":\"3.11\"}]}",
-                "pywin32_ctypes": "{\"rules_python_publish_deps_311_pywin32_ctypes_py3_none_any_8a151337\":[{\"filename\":\"pywin32_ctypes-0.2.3-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_pywin32_ctypes_sdist_d162dc04\":[{\"filename\":\"pywin32-ctypes-0.2.3.tar.gz\",\"version\":\"3.11\"}]}",
-                "readme_renderer": "{\"rules_python_publish_deps_311_readme_renderer_py3_none_any_2fbca89b\":[{\"filename\":\"readme_renderer-44.0-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_readme_renderer_sdist_8712034e\":[{\"filename\":\"readme_renderer-44.0.tar.gz\",\"version\":\"3.11\"}]}",
-                "requests": "{\"rules_python_publish_deps_311_requests_py3_none_any_70761cfe\":[{\"filename\":\"requests-2.32.3-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_requests_sdist_55365417\":[{\"filename\":\"requests-2.32.3.tar.gz\",\"version\":\"3.11\"}]}",
-                "requests_toolbelt": "{\"rules_python_publish_deps_311_requests_toolbelt_py2_none_any_cccfdd66\":[{\"filename\":\"requests_toolbelt-1.0.0-py2.py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_requests_toolbelt_sdist_7681a0a3\":[{\"filename\":\"requests-toolbelt-1.0.0.tar.gz\",\"version\":\"3.11\"}]}",
-                "rfc3986": "{\"rules_python_publish_deps_311_rfc3986_py2_none_any_50b1502b\":[{\"filename\":\"rfc3986-2.0.0-py2.py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_rfc3986_sdist_97aacf9d\":[{\"filename\":\"rfc3986-2.0.0.tar.gz\",\"version\":\"3.11\"}]}",
-                "rich": "{\"rules_python_publish_deps_311_rich_py3_none_any_9836f509\":[{\"filename\":\"rich-13.9.3-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_rich_sdist_bc1e01b8\":[{\"filename\":\"rich-13.9.3.tar.gz\",\"version\":\"3.11\"}]}",
-                "secretstorage": "{\"rules_python_publish_deps_311_secretstorage_py3_none_any_f356e662\":[{\"filename\":\"SecretStorage-3.3.3-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_secretstorage_sdist_2403533e\":[{\"filename\":\"SecretStorage-3.3.3.tar.gz\",\"version\":\"3.11\"}]}",
-                "twine": "{\"rules_python_publish_deps_311_twine_py3_none_any_215dbe7b\":[{\"filename\":\"twine-5.1.1-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_twine_sdist_9aa08251\":[{\"filename\":\"twine-5.1.1.tar.gz\",\"version\":\"3.11\"}]}",
-                "urllib3": "{\"rules_python_publish_deps_311_urllib3_py3_none_any_ca899ca0\":[{\"filename\":\"urllib3-2.2.3-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_urllib3_sdist_e7d814a8\":[{\"filename\":\"urllib3-2.2.3.tar.gz\",\"version\":\"3.11\"}]}",
-                "zipp": "{\"rules_python_publish_deps_311_zipp_py3_none_any_a817ac80\":[{\"filename\":\"zipp-3.20.2-py3-none-any.whl\",\"version\":\"3.11\"}],\"rules_python_publish_deps_311_zipp_sdist_bc9eb26f\":[{\"filename\":\"zipp-3.20.2.tar.gz\",\"version\":\"3.11\"}]}"
+              "toolchain_implementations": {
+                "none": "'@@rules_python+//python:none'"
               },
-              "packages": [
-                "backports_tarfile",
-                "certifi",
-                "charset_normalizer",
-                "docutils",
-                "idna",
-                "importlib_metadata",
-                "jaraco_classes",
-                "jaraco_context",
-                "jaraco_functools",
-                "keyring",
-                "markdown_it_py",
-                "mdurl",
-                "more_itertools",
-                "nh3",
-                "pkginfo",
-                "pygments",
-                "readme_renderer",
-                "requests",
-                "requests_toolbelt",
-                "rfc3986",
-                "rich",
-                "twine",
-                "urllib3",
-                "zipp"
-              ],
-              "groups": {}
+              "toolchain_compatible_with": {
+                "none": [
+                  "@platforms//:incompatible"
+                ]
+              },
+              "toolchain_target_settings": {}
             }
           }
         },
-        "moduleExtensionMetadata": {
-          "useAllRepos": "NO",
-          "reproducible": false
-        },
         "recordedRepoMappingEntries": [
           [
-            "bazel_features~",
-            "bazel_features_globals",
-            "bazel_features~~version_extension~bazel_features_globals"
-          ],
-          [
-            "bazel_features~",
-            "bazel_features_version",
-            "bazel_features~~version_extension~bazel_features_version"
-          ],
-          [
-            "rules_python~",
-            "bazel_features",
-            "bazel_features~"
-          ],
-          [
-            "rules_python~",
-            "bazel_skylib",
-            "bazel_skylib~"
-          ],
-          [
-            "rules_python~",
-            "bazel_tools",
-            "bazel_tools"
-          ],
-          [
-            "rules_python~",
-            "pypi__build",
-            "rules_python~~internal_deps~pypi__build"
-          ],
-          [
-            "rules_python~",
-            "pypi__click",
-            "rules_python~~internal_deps~pypi__click"
-          ],
-          [
-            "rules_python~",
-            "pypi__colorama",
-            "rules_python~~internal_deps~pypi__colorama"
-          ],
-          [
-            "rules_python~",
-            "pypi__importlib_metadata",
-            "rules_python~~internal_deps~pypi__importlib_metadata"
-          ],
-          [
-            "rules_python~",
-            "pypi__installer",
-            "rules_python~~internal_deps~pypi__installer"
-          ],
-          [
-            "rules_python~",
-            "pypi__more_itertools",
-            "rules_python~~internal_deps~pypi__more_itertools"
-          ],
-          [
-            "rules_python~",
-            "pypi__packaging",
-            "rules_python~~internal_deps~pypi__packaging"
-          ],
-          [
-            "rules_python~",
-            "pypi__pep517",
-            "rules_python~~internal_deps~pypi__pep517"
-          ],
-          [
-            "rules_python~",
-            "pypi__pip",
-            "rules_python~~internal_deps~pypi__pip"
-          ],
-          [
-            "rules_python~",
-            "pypi__pip_tools",
-            "rules_python~~internal_deps~pypi__pip_tools"
-          ],
-          [
-            "rules_python~",
-            "pypi__pyproject_hooks",
-            "rules_python~~internal_deps~pypi__pyproject_hooks"
-          ],
-          [
-            "rules_python~",
-            "pypi__setuptools",
-            "rules_python~~internal_deps~pypi__setuptools"
-          ],
-          [
-            "rules_python~",
-            "pypi__tomli",
-            "rules_python~~internal_deps~pypi__tomli"
-          ],
-          [
-            "rules_python~",
-            "pypi__wheel",
-            "rules_python~~internal_deps~pypi__wheel"
-          ],
-          [
-            "rules_python~",
-            "pypi__zipp",
-            "rules_python~~internal_deps~pypi__zipp"
-          ],
-          [
-            "rules_python~",
-            "pythons_hub",
-            "rules_python~~python~pythons_hub"
-          ],
-          [
-            "rules_python~~python~pythons_hub",
-            "python_3_10_host",
-            "rules_python~~python~python_3_10_host"
-          ],
-          [
-            "rules_python~~python~pythons_hub",
-            "python_3_11_host",
-            "rules_python~~python~python_3_11_host"
-          ],
-          [
-            "rules_python~~python~pythons_hub",
-            "python_3_12_host",
-            "rules_python~~python~python_3_12_host"
-          ],
-          [
-            "rules_python~~python~pythons_hub",
-            "python_3_9_host",
-            "rules_python~~python~python_3_9_host"
+            "rules_python+",
+            "platforms",
+            "platforms"
           ]
         ]
       }
     },
-    "@@rules_swift~//swift:extensions.bzl%non_module_deps": {
+    "@@rules_swift+//swift:extensions.bzl%non_module_deps": {
       "general": {
-        "bzlTransitiveDigest": "vhXfCi07IAmWf5hLHcxh5xCtTwvEGrmMkOavEMD5pzs=",
-        "usagesDigest": "/dVEtCLqIAaLXjfRXsJupTS9pTgmYVN/tFdJlGgE5NA=",
+        "bzlTransitiveDigest": "6axDCXf6fQoPav8hojnUBxGA0FAMqLvtpC1cRsisCdw=",
+        "usagesDigest": "mhACFnrdMv9Wi0Mt67bxocJqviRkDSV+Ee5Mqdj5akA=",
         "recordedFileInputs": {},
         "recordedDirentsInputs": {},
         "envVariables": {},
         "generatedRepoSpecs": {
           "com_github_apple_swift_protobuf": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
+            "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
             "attributes": {
               "urls": [
                 "https://github.com/apple/swift-protobuf/archive/1.20.2.tar.gz"
               ],
               "sha256": "3fb50bd4d293337f202d917b6ada22f9548a0a0aed9d9a4d791e6fbd8a246ebb",
               "strip_prefix": "swift-protobuf-1.20.2/",
-              "build_file": "@@rules_swift~//third_party:com_github_apple_swift_protobuf/BUILD.overlay"
+              "build_file": "@@rules_swift+//third_party:com_github_apple_swift_protobuf/BUILD.overlay"
             }
           },
           "com_github_grpc_grpc_swift": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
+            "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
             "attributes": {
               "urls": [
                 "https://github.com/grpc/grpc-swift/archive/1.16.0.tar.gz"
               ],
               "sha256": "58b60431d0064969f9679411264b82e40a217ae6bd34e17096d92cc4e47556a5",
               "strip_prefix": "grpc-swift-1.16.0/",
-              "build_file": "@@rules_swift~//third_party:com_github_grpc_grpc_swift/BUILD.overlay"
+              "build_file": "@@rules_swift+//third_party:com_github_grpc_grpc_swift/BUILD.overlay"
             }
           },
           "com_github_apple_swift_docc_symbolkit": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
+            "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
             "attributes": {
               "urls": [
                 "https://github.com/apple/swift-docc-symbolkit/archive/refs/tags/swift-5.10-RELEASE.tar.gz"
               ],
               "sha256": "de1d4b6940468ddb53b89df7aa1a81323b9712775b0e33e8254fa0f6f7469a97",
               "strip_prefix": "swift-docc-symbolkit-swift-5.10-RELEASE",
-              "build_file": "@@rules_swift~//third_party:com_github_apple_swift_docc_symbolkit/BUILD.overlay"
+              "build_file": "@@rules_swift+//third_party:com_github_apple_swift_docc_symbolkit/BUILD.overlay"
             }
           },
           "com_github_apple_swift_nio": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
+            "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
             "attributes": {
               "urls": [
                 "https://github.com/apple/swift-nio/archive/2.42.0.tar.gz"
               ],
               "sha256": "e3304bc3fb53aea74a3e54bd005ede11f6dc357117d9b1db642d03aea87194a0",
               "strip_prefix": "swift-nio-2.42.0/",
-              "build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio/BUILD.overlay"
+              "build_file": "@@rules_swift+//third_party:com_github_apple_swift_nio/BUILD.overlay"
             }
           },
           "com_github_apple_swift_nio_http2": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
+            "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
             "attributes": {
               "urls": [
                 "https://github.com/apple/swift-nio-http2/archive/1.26.0.tar.gz"
               ],
               "sha256": "f0edfc9d6a7be1d587e5b403f2d04264bdfae59aac1d74f7d974a9022c6d2b25",
               "strip_prefix": "swift-nio-http2-1.26.0/",
-              "build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio_http2/BUILD.overlay"
+              "build_file": "@@rules_swift+//third_party:com_github_apple_swift_nio_http2/BUILD.overlay"
             }
           },
           "com_github_apple_swift_nio_transport_services": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
+            "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
             "attributes": {
               "urls": [
                 "https://github.com/apple/swift-nio-transport-services/archive/1.15.0.tar.gz"
               ],
               "sha256": "f3498dafa633751a52b9b7f741f7ac30c42bcbeb3b9edca6d447e0da8e693262",
               "strip_prefix": "swift-nio-transport-services-1.15.0/",
-              "build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio_transport_services/BUILD.overlay"
+              "build_file": "@@rules_swift+//third_party:com_github_apple_swift_nio_transport_services/BUILD.overlay"
             }
           },
           "com_github_apple_swift_nio_extras": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
+            "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
             "attributes": {
               "urls": [
                 "https://github.com/apple/swift-nio-extras/archive/1.4.0.tar.gz"
               ],
               "sha256": "4684b52951d9d9937bb3e8ccd6b5daedd777021ef2519ea2f18c4c922843b52b",
               "strip_prefix": "swift-nio-extras-1.4.0/",
-              "build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio_extras/BUILD.overlay"
+              "build_file": "@@rules_swift+//third_party:com_github_apple_swift_nio_extras/BUILD.overlay"
             }
           },
           "com_github_apple_swift_log": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
+            "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
             "attributes": {
               "urls": [
                 "https://github.com/apple/swift-log/archive/1.4.4.tar.gz"
               ],
               "sha256": "48fe66426c784c0c20031f15dc17faf9f4c9037c192bfac2f643f65cb2321ba0",
               "strip_prefix": "swift-log-1.4.4/",
-              "build_file": "@@rules_swift~//third_party:com_github_apple_swift_log/BUILD.overlay"
+              "build_file": "@@rules_swift+//third_party:com_github_apple_swift_log/BUILD.overlay"
             }
           },
           "com_github_apple_swift_nio_ssl": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
+            "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
             "attributes": {
               "urls": [
                 "https://github.com/apple/swift-nio-ssl/archive/2.23.0.tar.gz"
               ],
               "sha256": "4787c63f61dd04d99e498adc3d1a628193387e41efddf8de19b8db04544d016d",
               "strip_prefix": "swift-nio-ssl-2.23.0/",
-              "build_file": "@@rules_swift~//third_party:com_github_apple_swift_nio_ssl/BUILD.overlay"
+              "build_file": "@@rules_swift+//third_party:com_github_apple_swift_nio_ssl/BUILD.overlay"
             }
           },
           "com_github_apple_swift_collections": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
+            "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
             "attributes": {
               "urls": [
                 "https://github.com/apple/swift-collections/archive/1.0.4.tar.gz"
               ],
               "sha256": "d9e4c8a91c60fb9c92a04caccbb10ded42f4cb47b26a212bc6b39cc390a4b096",
               "strip_prefix": "swift-collections-1.0.4/",
-              "build_file": "@@rules_swift~//third_party:com_github_apple_swift_collections/BUILD.overlay"
+              "build_file": "@@rules_swift+//third_party:com_github_apple_swift_collections/BUILD.overlay"
             }
           },
           "com_github_apple_swift_atomics": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
+            "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
             "attributes": {
               "urls": [
                 "https://github.com/apple/swift-atomics/archive/1.1.0.tar.gz"
               ],
               "sha256": "1bee7f469f7e8dc49f11cfa4da07182fbc79eab000ec2c17bfdce468c5d276fb",
               "strip_prefix": "swift-atomics-1.1.0/",
-              "build_file": "@@rules_swift~//third_party:com_github_apple_swift_atomics/BUILD.overlay"
+              "build_file": "@@rules_swift+//third_party:com_github_apple_swift_atomics/BUILD.overlay"
             }
           },
           "build_bazel_rules_swift_index_import": {
-            "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl",
-            "ruleClassName": "http_archive",
+            "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive",
             "attributes": {
-              "build_file": "@@rules_swift~//third_party:build_bazel_rules_swift_index_import/BUILD.overlay",
+              "build_file": "@@rules_swift+//third_party:build_bazel_rules_swift_index_import/BUILD.overlay",
               "canonical_id": "index-import-5.8",
               "urls": [
                 "https://github.com/MobileNativeFoundation/index-import/releases/download/5.8.0.1/index-import.tar.gz"
@@ -3267,24 +711,24 @@
             }
           },
           "build_bazel_rules_swift_local_config": {
-            "bzlFile": "@@rules_swift~//swift/internal:swift_autoconfiguration.bzl",
-            "ruleClassName": "swift_autoconfiguration",
+            "repoRuleId": "@@rules_swift+//swift/internal:swift_autoconfiguration.bzl%swift_autoconfiguration",
             "attributes": {}
           }
         },
         "recordedRepoMappingEntries": [
           [
-            "rules_swift~",
+            "rules_swift+",
             "bazel_tools",
             "bazel_tools"
           ],
           [
-            "rules_swift~",
+            "rules_swift+",
             "build_bazel_rules_swift",
-            "rules_swift~"
+            "rules_swift+"
           ]
         ]
       }
     }
-  }
+  },
+  "facts": {}
 }
diff --git a/WORKSPACE b/WORKSPACE
deleted file mode 100644
index 6ba4a02..0000000
--- a/WORKSPACE
+++ /dev/null
@@ -1,2 +0,0 @@
-# This file marks the root of the Bazel workspace.
-# See MODULE.bazel for external dependencies setup.
diff --git a/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF
index 1b2793a..d9d1b0f 100644
--- a/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF
@@ -8,12 +8,12 @@
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: JavaSE-17
 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git
-Import-Package: org.bouncycastle.asn1.cryptlib;version="[1.83.0,2.0.0)",
- org.bouncycastle.jce.provider;version="[1.83.0,2.0.0)",
- org.bouncycastle.openpgp;version="[1.83.0,2.0.0)",
- org.bouncycastle.openpgp.operator;version="[1.83.0,2.0.0)",
- org.bouncycastle.openpgp.operator.jcajce;version="[1.83.0,2.0.0)",
- org.bouncycastle.util.encoders;version="[1.83.0,2.0.0)",
+Import-Package: org.bouncycastle.asn1.cryptlib;version="[1.84.0,2.0.0)",
+ org.bouncycastle.jce.provider;version="[1.84.0,2.0.0)",
+ org.bouncycastle.openpgp;version="[1.84.0,2.0.0)",
+ org.bouncycastle.openpgp.operator;version="[1.84.0,2.0.0)",
+ org.bouncycastle.openpgp.operator.jcajce;version="[1.84.0,2.0.0)",
+ org.bouncycastle.util.encoders;version="[1.84.0,2.0.0)",
  org.eclipse.jgit.gpg.bc.internal;version="[7.7.0,7.8.0)",
  org.eclipse.jgit.gpg.bc.internal.keys;version="[7.7.0,7.8.0)",
  org.eclipse.jgit.util.sha1;version="[7.7.0,7.8.0)",
diff --git a/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF b/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF
index c039403..d6d826c 100644
--- a/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF
@@ -9,23 +9,23 @@
 Bundle-Version: 7.7.0.qualifier
 Bundle-RequiredExecutionEnvironment: JavaSE-17
 Bundle-SCM: url=https://github.com/eclipse-jgit/jgit, connection=scm:git:https://eclipse.gerrithub.io/eclipse-jgit/jgit.git, developerConnection=scm:git:https://eclipse.gerrithub.io/a/eclipse-jgit/jgit.git
-Import-Package: org.bouncycastle.asn1;version="[1.83.0,2.0.0)",
- org.bouncycastle.asn1.x9;version="[1.83.0,2.0.0)",
- org.bouncycastle.bcpg;version="[1.83.0,2.0.0)",
- org.bouncycastle.bcpg.sig;version="[1.83.0,2.0.0)",
- org.bouncycastle.crypto.ec;version="[1.83.0,2.0.0)",
- org.bouncycastle.gpg;version="[1.83.0,2.0.0)",
- org.bouncycastle.gpg.keybox;version="[1.83.0,2.0.0)",
- org.bouncycastle.gpg.keybox.jcajce;version="[1.83.0,2.0.0)",
- org.bouncycastle.jcajce.interfaces;version="[1.83.0,2.0.0)",
- org.bouncycastle.jcajce.util;version="[1.83.0,2.0.0)",
- org.bouncycastle.math.ec;version="[1.83.0,2.0.0)",
- org.bouncycastle.math.field;version="[1.83.0,2.0.0)",
- org.bouncycastle.openpgp;version="[1.83.0,2.0.0)",
- org.bouncycastle.openpgp.jcajce;version="[1.83.0,2.0.0)",
- org.bouncycastle.openpgp.operator;version="[1.83.0,2.0.0)",
- org.bouncycastle.openpgp.operator.jcajce;version="[1.83.0,2.0.0)",
- org.bouncycastle.util.encoders;version="[1.83.0,2.0.0)",
+Import-Package: org.bouncycastle.asn1;version="[1.84.0,2.0.0)",
+ org.bouncycastle.asn1.x9;version="[1.84.0,2.0.0)",
+ org.bouncycastle.bcpg;version="[1.84.0,2.0.0)",
+ org.bouncycastle.bcpg.sig;version="[1.84.0,2.0.0)",
+ org.bouncycastle.crypto.ec;version="[1.84.0,2.0.0)",
+ org.bouncycastle.gpg;version="[1.84.0,2.0.0)",
+ org.bouncycastle.gpg.keybox;version="[1.84.0,2.0.0)",
+ org.bouncycastle.gpg.keybox.jcajce;version="[1.84.0,2.0.0)",
+ org.bouncycastle.jcajce.interfaces;version="[1.84.0,2.0.0)",
+ org.bouncycastle.jcajce.util;version="[1.84.0,2.0.0)",
+ org.bouncycastle.math.ec;version="[1.84.0,2.0.0)",
+ org.bouncycastle.math.field;version="[1.84.0,2.0.0)",
+ org.bouncycastle.openpgp;version="[1.84.0,2.0.0)",
+ org.bouncycastle.openpgp.jcajce;version="[1.84.0,2.0.0)",
+ org.bouncycastle.openpgp.operator;version="[1.84.0,2.0.0)",
+ org.bouncycastle.openpgp.operator.jcajce;version="[1.84.0,2.0.0)",
+ org.bouncycastle.util.encoders;version="[1.84.0,2.0.0)",
  org.slf4j;version="[1.7.0,3.0.0)"
 Export-Package: org.eclipse.jgit.gpg.bc.internal;version="7.7.0";x-friends:="org.eclipse.jgit.gpg.bc.test",
  org.eclipse.jgit.gpg.bc.internal.keys;version="7.7.0";x-friends:="org.eclipse.jgit.gpg.bc.test"
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.34.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.34.target
index 6e1c72a..aaa7676 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.34.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.34.target
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.34" sequenceNumber="1772188163">
+<target name="jgit-4.34" sequenceNumber="1777548471">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/>
@@ -39,7 +39,7 @@
         <dependency>
           <groupId>org.tukaani</groupId>
           <artifactId>xz</artifactId>
-          <version>1.11</version>
+          <version>1.12</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -87,7 +87,7 @@
         <dependency>
           <groupId>org.mockito</groupId>
           <artifactId>mockito-core</artifactId>
-          <version>5.21.0</version>
+          <version>5.23.0</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -113,61 +113,61 @@
         <dependency>
           <groupId>org.eclipse.jetty.ee8</groupId>
           <artifactId>jetty-ee8-servlet</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty.ee8</groupId>
           <artifactId>jetty-ee8-nested</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty.ee8</groupId>
           <artifactId>jetty-ee8-security</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-http</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-io</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-security</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-server</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-session</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-util</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-util-ajax</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
@@ -213,13 +213,13 @@
         <dependency>
           <groupId>net.bytebuddy</groupId>
           <artifactId>byte-buddy</artifactId>
-          <version>1.18.5</version>
+          <version>1.18.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>net.bytebuddy</groupId>
           <artifactId>byte-buddy-agent</artifactId>
-          <version>1.18.5</version>
+          <version>1.18.8</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -229,25 +229,25 @@
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcpg-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcprov-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcpkix-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcutil-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -301,7 +301,7 @@
         <dependency>
           <groupId>commons-logging</groupId>
           <artifactId>commons-logging</artifactId>
-          <version>1.3.5</version>
+          <version>1.3.6</version>
           <type>jar</type>
         </dependency>
       </dependencies>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.35.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.35.target
index 9134dd0..f63efaa 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.35.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.35.target
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.35" sequenceNumber="1772188163">
+<target name="jgit-4.35" sequenceNumber="1777548471">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/>
@@ -39,7 +39,7 @@
         <dependency>
           <groupId>org.tukaani</groupId>
           <artifactId>xz</artifactId>
-          <version>1.11</version>
+          <version>1.12</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -87,7 +87,7 @@
         <dependency>
           <groupId>org.mockito</groupId>
           <artifactId>mockito-core</artifactId>
-          <version>5.21.0</version>
+          <version>5.23.0</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -113,61 +113,61 @@
         <dependency>
           <groupId>org.eclipse.jetty.ee8</groupId>
           <artifactId>jetty-ee8-servlet</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty.ee8</groupId>
           <artifactId>jetty-ee8-nested</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty.ee8</groupId>
           <artifactId>jetty-ee8-security</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-http</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-io</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-security</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-server</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-session</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-util</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-util-ajax</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
@@ -213,13 +213,13 @@
         <dependency>
           <groupId>net.bytebuddy</groupId>
           <artifactId>byte-buddy</artifactId>
-          <version>1.18.5</version>
+          <version>1.18.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>net.bytebuddy</groupId>
           <artifactId>byte-buddy-agent</artifactId>
-          <version>1.18.5</version>
+          <version>1.18.8</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -229,25 +229,25 @@
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcpg-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcprov-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcpkix-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcutil-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -301,7 +301,7 @@
         <dependency>
           <groupId>commons-logging</groupId>
           <artifactId>commons-logging</artifactId>
-          <version>1.3.5</version>
+          <version>1.3.6</version>
           <type>jar</type>
         </dependency>
       </dependencies>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.36.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.36.target
index beb25fd..8d96981 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.36.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.36.target
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.36" sequenceNumber="1772188163">
+<target name="jgit-4.36" sequenceNumber="1777548471">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/>
@@ -39,7 +39,7 @@
         <dependency>
           <groupId>org.tukaani</groupId>
           <artifactId>xz</artifactId>
-          <version>1.11</version>
+          <version>1.12</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -87,7 +87,7 @@
         <dependency>
           <groupId>org.mockito</groupId>
           <artifactId>mockito-core</artifactId>
-          <version>5.21.0</version>
+          <version>5.23.0</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -113,61 +113,61 @@
         <dependency>
           <groupId>org.eclipse.jetty.ee8</groupId>
           <artifactId>jetty-ee8-servlet</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty.ee8</groupId>
           <artifactId>jetty-ee8-nested</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty.ee8</groupId>
           <artifactId>jetty-ee8-security</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-http</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-io</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-security</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-server</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-session</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-util</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-util-ajax</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
@@ -213,13 +213,13 @@
         <dependency>
           <groupId>net.bytebuddy</groupId>
           <artifactId>byte-buddy</artifactId>
-          <version>1.18.5</version>
+          <version>1.18.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>net.bytebuddy</groupId>
           <artifactId>byte-buddy-agent</artifactId>
-          <version>1.18.5</version>
+          <version>1.18.8</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -229,25 +229,25 @@
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcpg-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcprov-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcpkix-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcutil-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -301,7 +301,7 @@
         <dependency>
           <groupId>commons-logging</groupId>
           <artifactId>commons-logging</artifactId>
-          <version>1.3.5</version>
+          <version>1.3.6</version>
           <type>jar</type>
         </dependency>
       </dependencies>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.37.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.37.target
index 1c9135c..aca3a80 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.37.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.37.target
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.37" sequenceNumber="1772188163">
+<target name="jgit-4.37" sequenceNumber="1777548471">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/>
@@ -39,7 +39,7 @@
         <dependency>
           <groupId>org.tukaani</groupId>
           <artifactId>xz</artifactId>
-          <version>1.11</version>
+          <version>1.12</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -87,7 +87,7 @@
         <dependency>
           <groupId>org.mockito</groupId>
           <artifactId>mockito-core</artifactId>
-          <version>5.21.0</version>
+          <version>5.23.0</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -113,61 +113,61 @@
         <dependency>
           <groupId>org.eclipse.jetty.ee8</groupId>
           <artifactId>jetty-ee8-servlet</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty.ee8</groupId>
           <artifactId>jetty-ee8-nested</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty.ee8</groupId>
           <artifactId>jetty-ee8-security</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-http</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-io</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-security</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-server</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-session</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-util</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-util-ajax</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
@@ -213,13 +213,13 @@
         <dependency>
           <groupId>net.bytebuddy</groupId>
           <artifactId>byte-buddy</artifactId>
-          <version>1.18.5</version>
+          <version>1.18.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>net.bytebuddy</groupId>
           <artifactId>byte-buddy-agent</artifactId>
-          <version>1.18.5</version>
+          <version>1.18.8</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -229,25 +229,25 @@
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcpg-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcprov-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcpkix-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcutil-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -301,7 +301,7 @@
         <dependency>
           <groupId>commons-logging</groupId>
           <artifactId>commons-logging</artifactId>
-          <version>1.3.5</version>
+          <version>1.3.6</version>
           <type>jar</type>
         </dependency>
       </dependencies>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.38.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.38.target
index 0d838d8..9526197 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.38.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.38.target
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.38" sequenceNumber="1772188163">
+<target name="jgit-4.38" sequenceNumber="1777548472">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/>
@@ -39,7 +39,7 @@
         <dependency>
           <groupId>org.tukaani</groupId>
           <artifactId>xz</artifactId>
-          <version>1.11</version>
+          <version>1.12</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -87,7 +87,7 @@
         <dependency>
           <groupId>org.mockito</groupId>
           <artifactId>mockito-core</artifactId>
-          <version>5.21.0</version>
+          <version>5.23.0</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -113,61 +113,61 @@
         <dependency>
           <groupId>org.eclipse.jetty.ee8</groupId>
           <artifactId>jetty-ee8-servlet</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty.ee8</groupId>
           <artifactId>jetty-ee8-nested</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty.ee8</groupId>
           <artifactId>jetty-ee8-security</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-http</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-io</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-security</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-server</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-session</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-util</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-util-ajax</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
@@ -213,13 +213,13 @@
         <dependency>
           <groupId>net.bytebuddy</groupId>
           <artifactId>byte-buddy</artifactId>
-          <version>1.18.5</version>
+          <version>1.18.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>net.bytebuddy</groupId>
           <artifactId>byte-buddy-agent</artifactId>
-          <version>1.18.5</version>
+          <version>1.18.8</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -229,25 +229,25 @@
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcpg-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcprov-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcpkix-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcutil-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -301,7 +301,7 @@
         <dependency>
           <groupId>commons-logging</groupId>
           <artifactId>commons-logging</artifactId>
-          <version>1.3.5</version>
+          <version>1.3.6</version>
           <type>jar</type>
         </dependency>
       </dependencies>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.39.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.39.target
index 6ce26dd..9542085 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.39.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.39.target
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
-<target name="jgit-4.39" sequenceNumber="1772188163">
+<target name="jgit-4.39" sequenceNumber="1777548472">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/>
@@ -32,14 +32,14 @@
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
-      <repository location="https://download.eclipse.org/staging/2026-03/"/>
+      <repository location="https://download.eclipse.org/releases/2026-03/"/>
     </location>
     <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz">
       <dependencies>
         <dependency>
           <groupId>org.tukaani</groupId>
           <artifactId>xz</artifactId>
-          <version>1.11</version>
+          <version>1.12</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -87,7 +87,7 @@
         <dependency>
           <groupId>org.mockito</groupId>
           <artifactId>mockito-core</artifactId>
-          <version>5.21.0</version>
+          <version>5.23.0</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -113,61 +113,61 @@
         <dependency>
           <groupId>org.eclipse.jetty.ee8</groupId>
           <artifactId>jetty-ee8-servlet</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty.ee8</groupId>
           <artifactId>jetty-ee8-nested</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty.ee8</groupId>
           <artifactId>jetty-ee8-security</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-http</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-io</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-security</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-server</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-session</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-util</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.eclipse.jetty</groupId>
           <artifactId>jetty-util-ajax</artifactId>
-          <version>12.1.6</version>
+          <version>12.1.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
@@ -213,13 +213,13 @@
         <dependency>
           <groupId>net.bytebuddy</groupId>
           <artifactId>byte-buddy</artifactId>
-          <version>1.18.5</version>
+          <version>1.18.8</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>net.bytebuddy</groupId>
           <artifactId>byte-buddy-agent</artifactId>
-          <version>1.18.5</version>
+          <version>1.18.8</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -229,25 +229,25 @@
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcpg-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcprov-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcpkix-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
         <dependency>
           <groupId>org.bouncycastle</groupId>
           <artifactId>bcutil-jdk18on</artifactId>
-          <version>1.83</version>
+          <version>1.84</version>
           <type>jar</type>
         </dependency>
       </dependencies>
@@ -301,7 +301,7 @@
         <dependency>
           <groupId>commons-logging</groupId>
           <artifactId>commons-logging</artifactId>
-          <version>1.3.5</version>
+          <version>1.3.6</version>
           <type>jar</type>
         </dependency>
       </dependencies>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.39.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.39.tpd
index 0b32b1b..fb0fc7e 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.39.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.39.tpd
@@ -3,6 +3,6 @@
 include "orbit/orbit-4.39.tpd"
 include "maven/dependencies.tpd"
 
-location "https://download.eclipse.org/staging/2026-03/" {
+location "https://download.eclipse.org/releases/2026-03/" {
 	org.eclipse.osgi lazy
 }
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.40.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.40.target
new file mode 100644
index 0000000..068e12a
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.40.target
@@ -0,0 +1,310 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?pde?>
+<!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl -->
+<target name="jgit-4.40" sequenceNumber="1777548472">
+  <locations>
+    <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
+      <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/>
+      <unit id="com.jcraft.jsch.source" version="0.1.55.v20230916-1400"/>
+      <unit id="com.jcraft.jzlib" version="1.1.3.v20230916-1400"/>
+      <unit id="com.jcraft.jzlib.source" version="1.1.3.v20230916-1400"/>
+      <unit id="org.apache.ant" version="1.10.17.v20260410-1000"/>
+      <unit id="org.apache.ant.source" version="1.10.17.v20260410-1000"/>
+      <unit id="org.apache.aries.spifly.dynamic.bundle" version="1.3.7"/>
+      <unit id="org.apache.httpcomponents.httpclient" version="4.5.14"/>
+      <unit id="org.apache.httpcomponents.httpclient.source" version="4.5.14"/>
+      <unit id="org.apache.httpcomponents.httpcore" version="4.4.16"/>
+      <unit id="org.apache.httpcomponents.httpcore.source" version="4.4.16"/>
+      <unit id="org.hamcrest" version="3.0.0"/>
+      <unit id="org.hamcrest.source" version="3.0.0"/>
+      <unit id="org.junit" version="4.13.2.v20240929-1000"/>
+      <unit id="org.junit.source" version="4.13.2.v20240929-1000"/>
+      <unit id="org.objectweb.asm" version="9.9.1"/>
+      <unit id="org.objectweb.asm.commons" version="9.9.1"/>
+      <unit id="org.objectweb.asm.util" version="9.9.1"/>
+      <unit id="org.objectweb.asm.tree" version="9.9.1"/>
+      <unit id="org.objectweb.asm.tree.analysis" version="9.9.1"/>
+      <unit id="org.objenesis" version="3.5.0"/>
+      <unit id="org.objenesis.source" version="3.5.0"/>
+      <unit id="org.osgi.service.cm" version="1.6.1.202109301733"/>
+      <unit id="org.osgi.service.cm.source" version="1.6.1.202109301733"/>
+      <repository location="https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2026-06"/>
+    </location>
+    <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
+      <unit id="org.eclipse.osgi" version="0.0.0"/>
+      <repository location="https://download.eclipse.org/staging/2026-06/"/>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="xz">
+      <dependencies>
+        <dependency>
+          <groupId>org.tukaani</groupId>
+          <artifactId>xz</artifactId>
+          <version>1.12</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="slf4j">
+      <dependencies>
+        <dependency>
+          <groupId>org.slf4j</groupId>
+          <artifactId>slf4j-api</artifactId>
+          <version>2.0.17</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.slf4j</groupId>
+          <artifactId>slf4j-simple</artifactId>
+          <version>2.0.17</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.slf4j</groupId>
+          <artifactId>jcl-over-slf4j</artifactId>
+          <version>2.0.17</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="sshd">
+      <dependencies>
+        <dependency>
+          <groupId>org.apache.sshd</groupId>
+          <artifactId>sshd-osgi</artifactId>
+          <version>2.17.1</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.apache.sshd</groupId>
+          <artifactId>sshd-sftp</artifactId>
+          <version>2.17.1</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="mockito">
+      <dependencies>
+        <dependency>
+          <groupId>org.mockito</groupId>
+          <artifactId>mockito-core</artifactId>
+          <version>5.23.0</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jna">
+      <dependencies>
+        <dependency>
+          <groupId>net.java.dev.jna</groupId>
+          <artifactId>jna</artifactId>
+          <version>5.18.1</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>net.java.dev.jna</groupId>
+          <artifactId>jna-platform</artifactId>
+          <version>5.18.1</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="jetty">
+      <dependencies>
+        <dependency>
+          <groupId>org.eclipse.jetty.ee8</groupId>
+          <artifactId>jetty-ee8-servlet</artifactId>
+          <version>12.1.8</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.eclipse.jetty.ee8</groupId>
+          <artifactId>jetty-ee8-nested</artifactId>
+          <version>12.1.8</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.eclipse.jetty.ee8</groupId>
+          <artifactId>jetty-ee8-security</artifactId>
+          <version>12.1.8</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.eclipse.jetty</groupId>
+          <artifactId>jetty-http</artifactId>
+          <version>12.1.8</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.eclipse.jetty</groupId>
+          <artifactId>jetty-io</artifactId>
+          <version>12.1.8</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.eclipse.jetty</groupId>
+          <artifactId>jetty-security</artifactId>
+          <version>12.1.8</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.eclipse.jetty</groupId>
+          <artifactId>jetty-server</artifactId>
+          <version>12.1.8</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.eclipse.jetty</groupId>
+          <artifactId>jetty-session</artifactId>
+          <version>12.1.8</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.eclipse.jetty</groupId>
+          <artifactId>jetty-util</artifactId>
+          <version>12.1.8</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.eclipse.jetty</groupId>
+          <artifactId>jetty-util-ajax</artifactId>
+          <version>12.1.8</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>javax.servlet</groupId>
+          <artifactId>javax.servlet-api</artifactId>
+          <version>4.0.1</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="javaewah">
+      <dependencies>
+        <dependency>
+          <groupId>com.googlecode.javaewah</groupId>
+          <artifactId>JavaEWAH</artifactId>
+          <version>1.2.3</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="hamcrest">
+      <dependencies>
+        <dependency>
+          <groupId>org.hamcrest</groupId>
+          <artifactId>hamcrest</artifactId>
+          <version>3.0</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="gson">
+      <dependencies>
+        <dependency>
+          <groupId>com.google.code.gson</groupId>
+          <artifactId>gson</artifactId>
+          <version>2.13.2</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bytebuddy">
+      <dependencies>
+        <dependency>
+          <groupId>net.bytebuddy</groupId>
+          <artifactId>byte-buddy</artifactId>
+          <version>1.18.8</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>net.bytebuddy</groupId>
+          <artifactId>byte-buddy-agent</artifactId>
+          <version>1.18.8</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="bouncycastle">
+      <dependencies>
+        <dependency>
+          <groupId>org.bouncycastle</groupId>
+          <artifactId>bcpg-jdk18on</artifactId>
+          <version>1.84</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.bouncycastle</groupId>
+          <artifactId>bcprov-jdk18on</artifactId>
+          <version>1.84</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.bouncycastle</groupId>
+          <artifactId>bcpkix-jdk18on</artifactId>
+          <version>1.84</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.bouncycastle</groupId>
+          <artifactId>bcutil-jdk18on</artifactId>
+          <version>1.84</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="assertj">
+      <dependencies>
+        <dependency>
+          <groupId>org.assertj</groupId>
+          <artifactId>assertj-core</artifactId>
+          <version>3.27.7</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="args4j">
+      <dependencies>
+        <dependency>
+          <groupId>args4j</groupId>
+          <artifactId>args4j</artifactId>
+          <version>2.37</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+    <location includeDependencyDepth="none" includeDependencyScopes="compile" includeSource="true" missingManifest="error" type="Maven" label="apache">
+      <dependencies>
+        <dependency>
+          <groupId>commons-codec</groupId>
+          <artifactId>commons-codec</artifactId>
+          <version>1.21.0</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.apache.commons</groupId>
+          <artifactId>commons-compress</artifactId>
+          <version>1.28.0</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>org.apache.commons</groupId>
+          <artifactId>commons-lang3</artifactId>
+          <version>3.20.0</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>commons-io</groupId>
+          <artifactId>commons-io</artifactId>
+          <version>2.21.0</version>
+          <type>jar</type>
+        </dependency>
+        <dependency>
+          <groupId>commons-logging</groupId>
+          <artifactId>commons-logging</artifactId>
+          <version>1.3.6</version>
+          <type>jar</type>
+        </dependency>
+      </dependencies>
+    </location>
+  </locations>
+</target>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.40.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.40.tpd
new file mode 100644
index 0000000..62e9f38
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.40.tpd
@@ -0,0 +1,8 @@
+target "jgit-4.40" with source configurePhase
+
+include "orbit/orbit-4.40.tpd"
+include "maven/dependencies.tpd"
+
+location "https://download.eclipse.org/staging/2026-06/" {
+	org.eclipse.osgi lazy
+}
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/maven/dependencies.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/maven/dependencies.tpd
index 175141c..18a7e4e 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/maven/dependencies.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/maven/dependencies.tpd
@@ -30,7 +30,7 @@
 	dependency {
 		groupId = "commons-logging"
 		artifactId = "commons-logging"
-		version = "1.3.5"
+		version = "1.3.6"
 	}
 }
 
@@ -69,22 +69,22 @@
 	dependency {
 		groupId = "org.bouncycastle"
 		artifactId = "bcpg-jdk18on"
-		version = "1.83"
+		version = "1.84"
 	}
 	dependency {
 		groupId = "org.bouncycastle"
 		artifactId = "bcprov-jdk18on"
-		version = "1.83"
+		version = "1.84"
 	}
 	dependency {
 		groupId = "org.bouncycastle"
 		artifactId = "bcpkix-jdk18on"
-		version = "1.83"
+		version = "1.84"
 	}
 	dependency {
 		groupId = "org.bouncycastle"
 		artifactId = "bcutil-jdk18on"
-		version = "1.83"
+		version = "1.84"
 	}
 }
 
@@ -97,12 +97,12 @@
 	dependency {
 		groupId = "net.bytebuddy"
 		artifactId = "byte-buddy"
-		version = "1.18.5"
+		version = "1.18.8"
 	}
 	dependency {
 		groupId = "net.bytebuddy"
 		artifactId = "byte-buddy-agent"
-		version = "1.18.5"
+		version = "1.18.8"
 	}
 }
 
@@ -154,52 +154,52 @@
 	dependency {
 		groupId = "org.eclipse.jetty.ee8"
 		artifactId = "jetty-ee8-servlet"
-		version = "12.1.6"
+		version = "12.1.8"
 	}
 	dependency {
 		groupId = "org.eclipse.jetty.ee8"
 		artifactId = "jetty-ee8-nested"
-		version = "12.1.6"
+		version = "12.1.8"
 	}
 	dependency {
 		groupId = "org.eclipse.jetty.ee8"
 		artifactId = "jetty-ee8-security"
-		version = "12.1.6"
+		version = "12.1.8"
 	}
 	dependency {
 		groupId = "org.eclipse.jetty"
 		artifactId = "jetty-http"
-		version = "12.1.6"
+		version = "12.1.8"
 	}
 	dependency {
 		groupId = "org.eclipse.jetty"
 		artifactId = "jetty-io"
-		version = "12.1.6"
+		version = "12.1.8"
 	}
 	dependency {
 		groupId = "org.eclipse.jetty"
 		artifactId = "jetty-security"
-		version = "12.1.6"
+		version = "12.1.8"
 	}
 	dependency {
 		groupId = "org.eclipse.jetty"
 		artifactId = "jetty-server"
-		version = "12.1.6"
+		version = "12.1.8"
 	}
 	dependency {
 		groupId = "org.eclipse.jetty"
 		artifactId = "jetty-session"
-		version = "12.1.6"
+		version = "12.1.8"
 	}
 	dependency {
 		groupId = "org.eclipse.jetty"
 		artifactId = "jetty-util"
-		version = "12.1.6"
+		version = "12.1.8"
 	}
 	dependency {
 		groupId = "org.eclipse.jetty"
 		artifactId = "jetty-util-ajax"
-		version = "12.1.6"
+		version = "12.1.8"
 	}
 	dependency {
 		groupId = "javax.servlet"
@@ -235,7 +235,7 @@
 	dependency {
 		groupId = "org.mockito"
 		artifactId = "mockito-core"
-		version = "5.21.0"
+		version = "5.23.0"
 	}
 }
 
@@ -289,6 +289,6 @@
 	dependency {
 		groupId = "org.tukaani"
 		artifactId = "xz"
-		version = "1.11"
+		version = "1.12"
 	}
-}
+}
\ No newline at end of file
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.40.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.40.tpd
new file mode 100644
index 0000000..4ce74f7
--- /dev/null
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/orbit-4.40.tpd
@@ -0,0 +1,29 @@
+target "orbit-4.40" with source configurePhase
+// see https://download.eclipse.org/tools/orbit/downloads/
+
+location "https://download.eclipse.org/tools/orbit/simrel/orbit-aggregation/2026-06" {
+	com.jcraft.jsch [0.1.55.v20230916-1400,0.1.55.v20230916-1400]
+	com.jcraft.jsch.source [0.1.55.v20230916-1400,0.1.55.v20230916-1400]
+	com.jcraft.jzlib [1.1.3.v20230916-1400,1.1.3.v20230916-1400]
+	com.jcraft.jzlib.source [1.1.3.v20230916-1400,1.1.3.v20230916-1400]
+	org.apache.ant [1.10.17.v20260410-1000,1.10.17.v20260410-1000]
+	org.apache.ant.source [1.10.17.v20260410-1000,1.10.17.v20260410-1000]
+	org.apache.aries.spifly.dynamic.bundle [1.3.7,1.3.7]
+	org.apache.httpcomponents.httpclient [4.5.14,4.5.14]
+	org.apache.httpcomponents.httpclient.source [4.5.14,4.5.14]
+	org.apache.httpcomponents.httpcore [4.4.16,4.4.16]
+	org.apache.httpcomponents.httpcore.source [4.4.16,4.4.16]
+	org.hamcrest [3.0.0,3.0.0]
+	org.hamcrest.source [3.0.0,3.0.0]
+	org.junit [4.13.2.v20240929-1000,4.13.2.v20240929-1000]
+	org.junit.source [4.13.2.v20240929-1000,4.13.2.v20240929-1000]
+	org.objectweb.asm [9.9.1,9.9.1]
+	org.objectweb.asm.commons [9.9.1,9.9.1]
+	org.objectweb.asm.util [9.9.1,9.9.1]
+	org.objectweb.asm.tree [9.9.1,9.9.1]
+	org.objectweb.asm.tree.analysis [9.9.1,9.9.1]
+	org.objenesis [3.5.0,3.5.0]
+	org.objenesis.source [3.5.0,3.5.0]
+	org.osgi.service.cm [1.6.1.202109301733,1.6.1.202109301733]
+	org.osgi.service.cm.source [1.6.1.202109301733,1.6.1.202109301733]
+}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MultiPackIndex.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MultiPackIndex.java
index 81fc0e8..37e835a 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MultiPackIndex.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MultiPackIndex.java
@@ -15,11 +15,13 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.util.regex.Pattern;
 
 import org.eclipse.jgit.internal.storage.file.MidxWriter;
 import org.eclipse.jgit.internal.storage.file.ObjectDirectory;
 import org.eclipse.jgit.internal.storage.midx.MultiPackIndexPrettyPrinter;
 import org.eclipse.jgit.lib.TextProgressMonitor;
+import org.eclipse.jgit.storage.pack.PackConfig;
 import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.Option;
 
@@ -32,6 +34,9 @@ class MultiPackIndex extends TextBuiltin {
 	@Option(name = "--midx")
 	private String midxPath;
 
+	@Option(name = "--bitmaps")
+	private boolean writeBitmaps;
+
 	/** {@inheritDoc} */
 	@Override
 	protected void run() throws IOException {
@@ -68,6 +73,11 @@ private void writeMultiPackIndex() throws IOException {
 			throw die("This repository object db doesn't have packs");
 		}
 
+		ObjectDirectory odb = (ObjectDirectory) db.getObjectDatabase();
+		if (hasLooseObjects(odb)) {
+			throw die("Cannot write multi-pack-index with loose objects");
+		}
+
 		File midx;
 		if (midxPath == null || midxPath.isEmpty()) {
 			midx = new File(((ObjectDirectory) db.getObjectDatabase())
@@ -77,9 +87,53 @@ private void writeMultiPackIndex() throws IOException {
 		}
 
 		errw.println("Writing " + midx.getAbsolutePath());
+		PackConfig packConfig = null;
+		if (writeBitmaps) {
+			packConfig = new PackConfig();
+			packConfig.setBitmapRecentCommitSpan(1);
+			packConfig.setBitmapRecentCommitSpan(100);
+		}
 
-		ObjectDirectory odb = (ObjectDirectory) db.getObjectDatabase();
-		MidxWriter.writeMidx(new TextProgressMonitor(errw), odb.getPacks(),
-				midx);
+		MidxWriter.writeMidx(new TextProgressMonitor(errw), db, odb.getPacks(),
+				midx, packConfig);
+	}
+
+	private static final Pattern FANOUT_DIR_PATTERN = Pattern
+			.compile("^[0-9a-f]{2}$");
+
+	/**
+	 * Checks if the repository's object directory contains any loose objects.
+	 *
+	 * @param objDir
+	 *            the ObjectDirectory to check.
+	 * @return {@code true} if any loose objects are found, {@code false}
+	 *         otherwise.
+	 */
+	private static boolean hasLooseObjects(ObjectDirectory objDir) {
+		File objectsDir = objDir.getDirectory();
+		if (objectsDir == null || !objectsDir.isDirectory()) {
+			return false;
+		}
+
+		String[] fanoutDirNames = objectsDir.list();
+		if (fanoutDirNames == null) {
+			return false;
+		}
+
+		for (String dirName : fanoutDirNames) {
+			if (FANOUT_DIR_PATTERN.matcher(dirName).matches()) {
+				File fanoutDir = new File(objectsDir, dirName);
+				if (fanoutDir.isDirectory()) {
+					String[] objects = fanoutDir.list();
+					// If the fan-out directory is not empty, we have loose
+					// objects.
+					if (objects != null && objects.length > 0) {
+						return true;
+					}
+				}
+			}
+		}
+
+		return false;
 	}
 }
diff --git a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabaseTest.java b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabaseTest.java
index 6b61821..ff6eb2b 100644
--- a/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabaseTest.java
+++ b/org.eclipse.jgit.ssh.apache.test/tst/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabaseTest.java
@@ -28,6 +28,7 @@
 import org.apache.sshd.common.SshConstants;
 import org.apache.sshd.common.cipher.ECCurves;
 import org.apache.sshd.common.config.keys.KeyUtils;
+import org.apache.sshd.common.config.keys.OpenSshCertificate;
 import org.apache.sshd.common.config.keys.PublicKeyEntry;
 import org.apache.sshd.common.util.security.SecurityUtils;
 import org.eclipse.jgit.annotations.NonNull;
@@ -58,7 +59,8 @@ public class OpenSshServerKeyDatabaseTest {
 	private static PublicKey ec256;
 	private static PublicKey ec384;
 	private static PublicKey caKey;
-	private static PublicKey certificate;
+
+	private static OpenSshCertificate certificate;
 
 	@BeforeClass
 	public static void initKeys() throws Exception {
@@ -179,7 +181,7 @@ public void testCaKeyNotConsidered() throws Exception {
 	}
 
 	@Test
-	public void testkeyPlainAndCa() throws Exception {
+	public void testKeyPlainAndCa() throws Exception {
 		Files.write(knownHosts, List.of(
 				"localhost,127.0.0.1 " + PublicKeyEntry.toString(rsa1024),
 				"some.other.com " + PublicKeyEntry.toString(ec384),
@@ -192,7 +194,46 @@ public void testkeyPlainAndCa() throws Exception {
 	}
 
 	@Test
+	public void testCaIsPlain() throws Exception {
+		Files.write(knownHosts, List.of(
+				"localhost,127.0.0.1 " + PublicKeyEntry.toString(rsa1024),
+				"some.other.com " + PublicKeyEntry.toString(ec384),
+				"localhost,127.0.0.1 " + PublicKeyEntry.toString(caKey)));
+		// caKey not marked as cert-authorithy
+		assertFalse(database.accept("localhost", LOCAL, certificate,
+				new KnownHostsConfig(), null));
+	}
+
+	@Test
+	public void testRevokedCa() throws Exception {
+		Files.write(knownHosts,
+				List.of("localhost,127.0.0.1 "
+						+ PublicKeyEntry.toString(rsa1024),
+						"some.other.com " + PublicKeyEntry.toString(ec384),
+						"@revoked localhost,127.0.0.1 "
+								+ PublicKeyEntry.toString(caKey)));
+		assertFalse(database.accept("localhost", LOCAL, certificate,
+				new KnownHostsConfig(), null));
+	}
+
+	@Test
+	public void testRevokedCertifiedKey() throws Exception {
+		Files.write(knownHosts,
+				List.of("localhost,127.0.0.1 "
+						+ PublicKeyEntry.toString(rsa1024),
+						"some.other.com " + PublicKeyEntry.toString(ec384),
+						"@cert-authority localhost,127.0.0.1 "
+								+ PublicKeyEntry.toString(caKey),
+						"@revoked localhost,127.0.0.1 " + PublicKeyEntry
+								.toString(certificate.getCertPubKey())));
+		assertFalse(database.accept("localhost", LOCAL, certificate,
+				new KnownHostsConfig(), null));
+	}
+
+	@Test
 	public void testLookupCertificate() throws Exception {
+		Files.write(knownHosts, List.of("@cert-authority localhost,127.0.0.1 "
+				+ PublicKeyEntry.toString(caKey)));
 		List<PublicKey> keys = database.lookup("localhost", LOCAL,
 				new KnownHostsConfig());
 		// Certificates or CA keys are not reported via lookup.
diff --git a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
index 2647126..5cff8a8 100644
--- a/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.ssh.apache/META-INF/MANIFEST.MF
@@ -38,7 +38,7 @@
    org.apache.sshd.client.session,
    org.apache.sshd.client.keyverifier",
  org.eclipse.jgit.transport.sshd.agent;version="7.7.0"
-Import-Package: org.bouncycastle.jce.provider;version="[1.83.0,2.0.0)",
+Import-Package: org.bouncycastle.jce.provider;version="[1.84.0,2.0.0)",
  org.apache.sshd.agent;version="[2.17.1,2.18.0)",
  org.apache.sshd.client;version="[2.17.1,2.18.0)",
  org.apache.sshd.client.auth;version="[2.17.1,2.18.0)",
diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabase.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabase.java
index acb77c5..7300a44 100644
--- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabase.java
+++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/transport/sshd/OpenSshServerKeyDatabase.java
@@ -210,10 +210,26 @@ public boolean accept(@NonNull String connectAddress,
 			@NonNull Configuration config, CredentialsProvider provider) {
 		List<HostKeyFile> filesToUse = getFilesToUse(config);
 		AskUser ask = new AskUser(config, provider);
-		HostEntryPair[] modified = { null };
-		Path path = null;
 		Collection<SshdSocketAddress> candidates = getCandidates(connectAddress,
 				remoteAddress);
+		if (acceptKey(remoteAddress, candidates, serverKey, filesToUse, config,
+				ask)) {
+			if (serverKey instanceof OpenSshCertificate certificate) {
+				if (isRevoked(remoteAddress, candidates, filesToUse,
+						certificate.getCertPubKey(), ask)) {
+					return false;
+				}
+			}
+			return true;
+		}
+		return false;
+	}
+
+	private boolean acceptKey(InetSocketAddress remoteAddress,
+			Collection<SshdSocketAddress> candidates, PublicKey serverKey,
+			List<HostKeyFile> filesToUse, Configuration config, AskUser ask) {
+		HostEntryPair[] modified = { null };
+		Path path = null;
 		for (HostKeyFile file : filesToUse) {
 			HostEntryPair lastModified = modified[0];
 			try {
@@ -285,7 +301,26 @@ private static boolean isCertificateAuthority(KnownHostEntry entry) {
 		return MARKER_CA.equals(entry.getMarker());
 	}
 
-	private boolean find(Collection<SshdSocketAddress> candidates,
+	private static boolean isRevoked(InetSocketAddress remoteAddress,
+			Collection<SshdSocketAddress> candidates,
+			List<HostKeyFile> filesToUse, PublicKey serverKey, AskUser ask) {
+		HostEntryPair[] dummy = { null };
+		for (HostKeyFile file : filesToUse) {
+			try {
+				if (find(candidates, serverKey, file.get(), dummy)) {
+					// It's definitely not revoked.
+					return false;
+				}
+			} catch (RevokedKeyException e) {
+				ask.revokedKey(remoteAddress, serverKey, file.getPath());
+				return true;
+			}
+		}
+		// Not found, so it is not revoked
+		return false;
+	}
+
+	private static boolean find(Collection<SshdSocketAddress> candidates,
 			PublicKey serverKey, List<HostEntryPair> entries,
 			HostEntryPair[] modified) throws RevokedKeyException {
 		PublicKey keyToCheck = serverKey;
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/MidxPackListTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/MidxPackListTest.java
index c275c32..217f587 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/MidxPackListTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/MidxPackListTest.java
@@ -9,341 +9,333 @@
  */
 package org.eclipse.jgit.internal.storage.dfs;
 
-import static java.util.Arrays.asList;
-import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
+import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC;
+import static org.eclipse.jgit.internal.storage.pack.PackExt.MULTI_PACK_INDEX;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
 
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
-import java.util.zip.Deflater;
+import java.util.Map;
+import java.util.Set;
 
-import org.eclipse.jgit.junit.JGitTestUtil;
-import org.eclipse.jgit.junit.TestRng;
-import org.eclipse.jgit.lib.NullProgressMonitor;
-import org.eclipse.jgit.lib.ObjectId;
-import org.junit.Before;
 import org.junit.Test;
 
 public class MidxPackListTest {
 
-	InMemoryRepository db;
+	PackPool packPool = new PackPool();
 
-	@Before
-	public void setUp() {
-		db = new InMemoryRepository(new DfsRepositoryDescription("test"));
-		db.getObjectDatabase().setUseMultipackIndex(true);
+	@Test
+	public void getAllPlainPacks_onlyPlain() {
+		DfsPackFile a = packPool.pack("a");
+		DfsPackFile b = packPool.pack("b");
+		DfsPackFile c = packPool.pack("c");
+
+		MidxPackList packList = MidxPackList.create(a, b, c);
+		assertEquals(List.of(a, b, c), packList.getAllPlainPacks());
 	}
 
 	@Test
-	public void getAllPlainPacks_onlyPlain() throws IOException {
-		setupThreePacks();
-		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
-		MidxPackList packList = MidxPackList.create(packs);
-		assertEquals(3, packList.getAllPlainPacks().size());
+	public void getAllPlainPacks_onlyMidx() {
+		DfsPackFile a = packPool.pack("a");
+		DfsPackFile b = packPool.pack("b");
+		DfsPackFile c = packPool.pack("c");
+		DfsPackFileMidx midx = packPool.midx("midx", null, "a", "b", "c");
+
+		MidxPackList packList = MidxPackList.create(midx);
+		assertEquals(List.of(c, b, a), packList.getAllPlainPacks());
 	}
 
 	@Test
-	public void getAllPlainPacks_onlyMidx() throws IOException {
-		setupThreePacksAndMidx();
+	public void getAllPlainPacks_midxPlusOne() {
+		DfsPackFile a = packPool.pack("a");
+		DfsPackFile b = packPool.pack("b");
+		DfsPackFile c = packPool.pack("c");
+		DfsPackFileMidx midx = packPool.midx("midx", null, "a", "b", "c");
+		DfsPackFile d = packPool.pack("d");
 
-		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
-		assertEquals(1, packs.length);
-		MidxPackList packList = MidxPackList.create(packs);
-		assertEquals(3, packList.getAllPlainPacks().size());
+		MidxPackList packList = MidxPackList.create(d, midx);
+		assertEquals(List.of(d, c, b, a), packList.getAllPlainPacks());
 	}
 
 	@Test
-	public void getAllPlainPacks_midxPlusOne() throws IOException {
-		setupThreePacksAndMidx();
-		writePackWithRandomBlob(60);
+	public void getAllPlainPacks_nestedMidx() {
+		DfsPackFile a = packPool.pack("a");
+		DfsPackFile b = packPool.pack("b");
+		DfsPackFileMidx midxBase = packPool.midx("midxBase", null, "a", "b");
+		DfsPackFile c = packPool.pack("c");
+		DfsPackFile d = packPool.pack("d");
+		DfsPackFileMidx midxMiddle = packPool.midx("midxMiddle", midxBase, "c",
+				"d");
+		DfsPackFile e = packPool.pack("e");
+		DfsPackFile f = packPool.pack("f");
+		DfsPackFileMidx midxTip = packPool.midx("midxTip", midxMiddle, "e",
+				"f");
 
-		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
-		assertEquals(2, packs.length);
-		MidxPackList packList = MidxPackList.create(packs);
-		assertEquals(4, packList.getAllPlainPacks().size());
+		MidxPackList packList = MidxPackList.create(midxTip);
+		assertEquals(List.of(f, e, d, c, b, a), packList.getAllPlainPacks());
 	}
 
 	@Test
-	public void getAllPlainPacks_nestedMidx() throws IOException {
-		setupSixPacksThreeMidx();
+	public void getAllMidxPacks_onlyPlain() {
+		DfsPackFile a = packPool.pack("a");
+		DfsPackFile b = packPool.pack("b");
+		DfsPackFile c = packPool.pack("c");
 
-		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
-		assertEquals(1, packs.length);
-		MidxPackList packList = MidxPackList.create(packs);
-		assertEquals(6, packList.getAllPlainPacks().size());
-	}
-
-	@Test
-	public void getAllMidxPacks_onlyPlain() throws IOException {
-		setupThreePacks();
-
-		MidxPackList packList = MidxPackList
-				.create(db.getObjectDatabase().getPacks());
+		MidxPackList packList = MidxPackList.create(a, b, c);
 		assertEquals(0, packList.getAllMidxPacks().size());
 	}
 
 	@Test
-	public void getAllMidxPacks_onlyMidx() throws IOException {
-		setupThreePacksAndMidx();
+	public void getAllMidxPacks_onlyMidx() {
+		packPool.pack("a");
+		packPool.pack("b");
+		packPool.pack("c");
+		DfsPackFileMidx midx = packPool.midx("midx", null, "a", "b", "c");
 
-		MidxPackList packList = MidxPackList
-				.create(db.getObjectDatabase().getPacks());
-		assertEquals(1, packList.getAllMidxPacks().size());
+		MidxPackList packList = MidxPackList.create(midx);
+		assertEquals(List.of(midx), packList.getAllMidxPacks());
 	}
 
 	@Test
-	public void getAllMidxPacks_midxPlusOne() throws IOException {
-		setupThreePacksAndMidx();
-		writePackWithRandomBlob(60);
+	public void getAllMidxPacks_midxPlusOne() {
+		packPool.pack("a");
+		packPool.pack("b");
+		packPool.pack("c");
+		DfsPackFileMidx midx = packPool.midx("midx", null, "a", "b", "c");
+		DfsPackFile d = packPool.pack("d");
 
-		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
-		assertEquals(2, packs.length);
-		MidxPackList packList = MidxPackList.create(packs);
-		assertEquals(1, packList.getAllMidxPacks().size());
+		MidxPackList packList = MidxPackList.create(d, midx);
+		assertEquals(List.of(midx), packList.getAllMidxPacks());
 	}
 
 	@Test
-	public void getAllMidxPacks_nestedMidx() throws IOException {
-		setupSixPacksThreeMidx();
+	public void getAllMidxPacks_nestedMidx() {
+		packPool.pack("a");
+		packPool.pack("b");
+		DfsPackFileMidx midxBase = packPool.midx("midxBase", null, "a", "b");
+		packPool.pack("c");
+		packPool.pack("d");
+		DfsPackFileMidx midxMiddle = packPool.midx("midxMiddle", midxBase, "c",
+				"d");
+		packPool.pack("e");
+		packPool.pack("f");
+		DfsPackFileMidx midxTip = packPool.midx("midxTip", midxMiddle, "e",
+				"f");
 
-		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
-		assertEquals(1, packs.length);
-		MidxPackList packList = MidxPackList.create(packs);
-		assertEquals(3, packList.getAllMidxPacks().size());
+		MidxPackList packList = MidxPackList.create(midxTip);
+		assertEquals(List.of(midxTip, midxMiddle, midxBase),
+				packList.getAllMidxPacks());
 	}
 
 	@Test
-	public void findAllImpactedMidx_onlyPacks() throws IOException {
-		setupThreePacks();
+	public void findAllImpactedMidx_onlyPacks() {
+		DfsPackFile a = packPool.pack("a");
+		DfsPackFile b = packPool.pack("b");
+		DfsPackFile c = packPool.pack("c");
 
-		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
-		MidxPackList packList = MidxPackList
-				.create(db.getObjectDatabase().getPacks());
-		assertEquals(0, packList.findAllCoveringMidxs(asList(packs)).size());
+		MidxPackList packList = MidxPackList.create(a, b, c);
+		assertEquals(Set.of(), packList.findAllCoveringMidxs(a));
+		assertEquals(Set.of(), packList.findAllCoveringMidxs(b));
+		assertEquals(Set.of(), packList.findAllCoveringMidxs(c));
+		assertEquals(Set.of(), packList.findAllCoveringMidxs(a, b));
 	}
 
 	@Test
-	public void findAllImpactedMidx_onlyMidx() throws IOException {
-		setupThreePacksAndMidx();
+	public void findAllImpactedMidx_onlyMidx() {
+		DfsPackFile a = packPool.pack("a");
+		DfsPackFile b = packPool.pack("b");
+		DfsPackFile c = packPool.pack("c");
+		DfsPackFileMidx midx = packPool.midx("midx", null, "a", "b", "c");
 
-		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
-		MidxPackList packList = MidxPackList.create(packs);
-		List<DfsPackFile> covered = ((DfsPackFileMidx) packs[0])
-				.getAllCoveredPacks();
-		assertEquals(1, packList.findAllCoveringMidxs(covered.get(0)).size());
-		assertEquals(1, packList.findAllCoveringMidxs(covered.get(1)).size());
-		assertEquals(1, packList.findAllCoveringMidxs(covered.get(2)).size());
-
-		assertEquals("multiple packs covered", 1,
-				packList.findAllCoveringMidxs(covered.subList(0, 2)).size());
+		MidxPackList packList = MidxPackList.create(midx);
+		assertEquals(Set.of(midx), packList.findAllCoveringMidxs(a));
+		assertEquals(Set.of(midx), packList.findAllCoveringMidxs(b));
+		assertEquals(Set.of(midx), packList.findAllCoveringMidxs(c));
+		assertEquals(Set.of(midx), packList.findAllCoveringMidxs(a, b));
 	}
 
 	@Test
-	public void findAllImpactedMidx_midxPlusOne() throws IOException {
-		setupThreePacksAndMidx();
-		writePackWithRandomBlob(60);
+	public void findAllImpactedMidx_midxPlusOne() {
+		packPool.pack("a");
+		DfsPackFile b = packPool.pack("b");
+		DfsPackFile c = packPool.pack("c");
+		DfsPackFileMidx midx = packPool.midx("midx", null, "a", "b", "c");
+		DfsPackFile d = packPool.pack("d");
 
-		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
-		assertEquals(2, packs.length);
-
-		DfsPackFile uncoveredPack = packs[0];
-		List<DfsPackFile> coveredPacks = ((DfsPackFileMidx) packs[1])
-				.getAllCoveredPacks();
-		assertEquals(3, coveredPacks.size());
-
-		MidxPackList packList = MidxPackList.create(packs);
-		assertEquals("one non covered", 0,
-				packList.findAllCoveringMidxs(uncoveredPack).size());
-		assertEquals("one and covered", 1,
-				packList.findAllCoveringMidxs(coveredPacks.get(1)).size());
+		MidxPackList packList = MidxPackList.create(d, midx);
+		assertEquals("one non covered", Set.of(),
+				packList.findAllCoveringMidxs(d));
+		assertEquals("one covered", Set.of(midx),
+				packList.findAllCoveringMidxs(b));
 		assertEquals(
-				"two, only one covered", 1, packList
-						.findAllCoveringMidxs(
-								List.of(uncoveredPack, coveredPacks.get(2)))
-						.size());
+				"two, only one covered", Set.of(midx),
+				packList.findAllCoveringMidxs(c, d));
 	}
 
 	@Test
-	public void findAllImpactedMidxs_nestedMidx() throws IOException {
-		setupSixPacksThreeMidx();
+	public void findAllImpactedMidxs_nestedMidx() {
+		DfsPackFile a = packPool.pack("a");
+		DfsPackFile b = packPool.pack("b");
+		DfsPackFileMidx midxBase = packPool.midx("midxBase", null, "a", "b");
+		DfsPackFile c = packPool.pack("c");
+		DfsPackFile d = packPool.pack("d");
+		DfsPackFileMidx midxMiddle = packPool.midx("midxMiddle", midxBase, "c",
+				"d");
+		DfsPackFile e = packPool.pack("e");
+		DfsPackFile f = packPool.pack("f");
+		DfsPackFileMidx midxTip = packPool.midx("midxTip", midxMiddle, "e",
+				"f");
 
-		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
-		assertEquals(1, packs.length);
-		MidxPackList packList = MidxPackList.create(packs);
-		List<DfsPackFile> coveredPacks = ((DfsPackFileMidx) packs[0])
-				.getAllCoveredPacks();
-		assertEquals(6, coveredPacks.size());
+		MidxPackList packList = MidxPackList.create(midxTip);
+		// Only tip
+		assertEquals(Set.of(midxTip), packList.findAllCoveringMidxs(e));
+		assertEquals(Set.of(midxTip), packList.findAllCoveringMidxs(f));
+		assertEquals(Set.of(midxTip), packList.findAllCoveringMidxs(e, f));
 
-		assertEquals("one covered tip midx", 1,
-				packList.findAllCoveringMidxs(coveredPacks.get(0)).size());
-		assertEquals("one covered middle midx", 2,
-				packList.findAllCoveringMidxs(coveredPacks.get(2)).size());
-		assertEquals("one covered base midx", 3,
-				packList.findAllCoveringMidxs(coveredPacks.get(4)).size());
-		assertEquals(
-				"multiple covered in chain", 3, packList
-						.findAllCoveringMidxs(List.of(coveredPacks.get(1),
-								coveredPacks.get(2), coveredPacks.get(5)))
-						.size());
+		// Tip and middle
+		assertEquals(Set.of(midxTip, midxMiddle),
+				packList.findAllCoveringMidxs(c));
+		assertEquals(Set.of(midxTip, midxMiddle),
+				packList.findAllCoveringMidxs(d));
+		assertEquals(Set.of(midxTip, midxMiddle),
+				packList.findAllCoveringMidxs(c, d));
+		assertEquals(Set.of(midxTip, midxMiddle),
+				packList.findAllCoveringMidxs(e, d));
+
+		// All three
+		assertEquals(Set.of(midxTip, midxMiddle, midxBase),
+				packList.findAllCoveringMidxs(a));
+		assertEquals(Set.of(midxTip, midxMiddle, midxBase),
+				packList.findAllCoveringMidxs(b));
+		assertEquals(Set.of(midxTip, midxMiddle, midxBase),
+				packList.findAllCoveringMidxs(a, b));
+		assertEquals(Set.of(midxTip, midxMiddle, midxBase),
+				packList.findAllCoveringMidxs(c, a));
+		assertEquals(Set.of(midxTip, midxMiddle, midxBase),
+				packList.findAllCoveringMidxs(f, c, b));
 	}
 
 	@Test
-	public void getTopMidxPack_noMidx_null() throws IOException {
-		setupThreePacks();
-		MidxPackList packList = MidxPackList
-				.create(db.getObjectDatabase().getPacks());
+	public void getTopMidxPack_noMidx_null() {
+		DfsPackFile a = packPool.pack("a");
+		DfsPackFile b = packPool.pack("b");
+		DfsPackFile c = packPool.pack("c");
+		MidxPackList packList = MidxPackList.create(a, b, c);
 		assertNull(packList.getTopMidxPack());
 	}
 
 	@Test
-	public void getTopMidxPack_oneMidx_returned() throws IOException {
-		DfsPackFileMidx midx = setupThreePacksAndMidx();
-		MidxPackList packList = MidxPackList
-				.create(db.getObjectDatabase().getPacks());
-		assertEquals(midx.getPackDescription(),
-				packList.getTopMidxPack().getPackDescription());
+	public void getTopMidxPack_oneMidx_returned() {
+		packPool.pack("a");
+		packPool.pack("b");
+		packPool.pack("c");
+		DfsPackFileMidx midx = packPool.midx("midx", null, "a", "b", "c");
+
+		MidxPackList packList = MidxPackList.create(midx);
+		assertEquals(midx, packList.getTopMidxPack());
 	}
 
 	@Test
-	public void getTopMidxPack_multipleMidx_mostRecent() throws IOException {
-		writePackWithRandomBlob(100);
-		writePackWithRandomBlob(300);
-		writePackWithRandomBlob(50);
-		writePackWithRandomBlob(400);
-		writePackWithRandomBlob(130);
-		writePackWithRandomBlob(500);
-		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
-		assertEquals(6, packs.length);
+	public void getTopMidxPack_multipleMidx_mostRecent() {
+		packPool.pack("a");
+		packPool.pack("b");
+		DfsPackFileMidx midxBase = packPool.midx("midxBase", null, "a", "b");
+		packPool.pack("c");
+		packPool.pack("d");
+		DfsPackFileMidx midxMiddle = packPool.midx("midxMiddle", midxBase, "c",
+				"d");
+		packPool.pack("e");
+		packPool.pack("f");
+		DfsPackFileMidx midxTip = packPool.midx("midxTip", midxMiddle, "e",
+				"f");
 
-		// midx covers first two packs
-		writeMultipackIndex(Arrays.copyOfRange(packs, 4, 6), null);
-
-		// chain of midxs covering all
-		DfsPackFileMidx midxBase = writeMultipackIndex(
-				Arrays.copyOfRange(packs, 4, 6), null);
-		DfsPackFileMidx midxMid = writeMultipackIndex(
-				Arrays.copyOfRange(packs, 2, 4), midxBase);
-		DfsPackFileMidx chainTwo = writeMultipackIndex(
-				Arrays.copyOfRange(packs, 0, 2), midxMid);
-
-		MidxPackList packList = MidxPackList
-				.create(db.getObjectDatabase().getPacks());
-		assertEquals(chainTwo.getPackDescription(),
-				packList.getTopMidxPack().getPackDescription());
+		MidxPackList packList = MidxPackList.create(midxTip);
+		assertEquals(midxTip, packList.getTopMidxPack());
 	}
 
 	@Test
-	public void getPlainPacksNotCoveredBy_null_all() throws IOException {
-		setupThreePacks();
-		MidxPackList packList = MidxPackList
-				.create(db.getObjectDatabase().getPacks());
-		assertEquals(3, packList.getPlainPacksNotCoveredBy(null).size());
+	public void getPlainPacksNotCoveredBy_null_all() {
+		DfsPackFile a = packPool.pack("a");
+		DfsPackFile b = packPool.pack("b");
+		DfsPackFile c = packPool.pack("c");
+		MidxPackList packList = MidxPackList.create(a, b, c);
+		assertEquals(List.of(a, b, c),
+				packList.getPlainPacksNotCoveredBy(null));
 	}
 
 	@Test
 	public void getPlainPacksNotCoveredBy_midxCoversAll_nothing()
-			throws IOException {
-		DfsPackFileMidx midx = setupThreePacksAndMidx();
-		MidxPackList packList = MidxPackList
-				.create(db.getObjectDatabase().getPacks());
-		assertEquals(0, packList.getPlainPacksNotCoveredBy(midx).size());
+	{
+		packPool.pack("a");
+		packPool.pack("b");
+		packPool.pack("c");
+		DfsPackFileMidx midx = packPool.midx("midx", null, "a", "b", "c");
+
+		MidxPackList packList = MidxPackList.create(midx);
+		assertEquals(List.of(), packList.getPlainPacksNotCoveredBy(midx));
 	}
 
 	@Test
 	public void getPlainPacksNotCoveredBy_midxMissesOne_one()
-			throws IOException {
-		DfsPackFileMidx midx = setupThreePacksAndMidx();
-		writePackWithBlob("getPlainPacksNotCovered_missingone"
-				.getBytes(StandardCharsets.UTF_8));
-		MidxPackList packList = MidxPackList
-				.create(db.getObjectDatabase().getPacks());
-		assertEquals(1, packList.getPlainPacksNotCoveredBy(midx).size());
+	{
+		packPool.pack("a");
+		packPool.pack("b");
+		packPool.pack("c");
+		DfsPackFileMidx midx = packPool.midx("midx", null, "a", "b", "c");
+		DfsPackFile d = packPool.pack("d");
+		MidxPackList packList = MidxPackList.create(d, midx);
+		assertEquals(List.of(d), packList.getPlainPacksNotCoveredBy(midx));
 	}
 
 	@Test
-	public void getPlainPacksNotCoveredBy_midxChain() throws IOException {
-		writePackWithRandomBlob(100);
-		writePackWithRandomBlob(300);
-		writePackWithRandomBlob(50);
-		writePackWithRandomBlob(400);
-		writePackWithRandomBlob(130);
-		writePackWithRandomBlob(500);
-		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
-		assertEquals(6, packs.length);
-		DfsPackFileMidx midxBase = writeMultipackIndex(
-				Arrays.copyOfRange(packs, 4, 6), null);
-		DfsPackFileMidx midxMid = writeMultipackIndex(
-				Arrays.copyOfRange(packs, 2, 4), midxBase);
-		DfsPackFileMidx midxTip = writeMultipackIndex(
-				Arrays.copyOfRange(packs, 0, 2), midxMid);
+	public void getPlainPacksNotCoveredBy_midxChain() {
+		packPool.pack("a");
+		packPool.pack("b");
+		DfsPackFileMidx midxBase = packPool.midx("midxBase", null, "a", "b");
+		DfsPackFile c = packPool.pack("c");
+		DfsPackFile d = packPool.pack("d");
+		DfsPackFileMidx midxMiddle = packPool.midx("midxMiddle", midxBase, "c",
+				"d");
+		DfsPackFile e = packPool.pack("e");
+		DfsPackFile f = packPool.pack("f");
+		DfsPackFileMidx midxTip = packPool.midx("midxTip", midxMiddle, "e",
+				"f");
 
-		MidxPackList packList = MidxPackList
-				.create(db.getObjectDatabase().getPacks());
-		assertEquals(4, packList.getPlainPacksNotCoveredBy(midxBase).size());
-		assertEquals(2, packList.getPlainPacksNotCoveredBy(midxMid).size());
-		assertEquals(0, packList.getPlainPacksNotCoveredBy(midxTip).size());
+		MidxPackList packList = MidxPackList.create(midxTip);
+		assertEquals(List.of(f, e, d, c),
+				packList.getPlainPacksNotCoveredBy(midxBase));
+		assertEquals(List.of(f, e),
+				packList.getPlainPacksNotCoveredBy(midxMiddle));
+		assertEquals(List.of(), packList.getPlainPacksNotCoveredBy(midxTip));
 	}
 
-	private void setupThreePacks() throws IOException {
-		writePackWithRandomBlob(100);
-		writePackWithRandomBlob(300);
-		writePackWithRandomBlob(50);
-	}
 
-	private DfsPackFileMidx setupThreePacksAndMidx() throws IOException {
-		writePackWithRandomBlob(100);
-		writePackWithRandomBlob(300);
-		writePackWithRandomBlob(50);
-		return writeMultipackIndex();
-	}
+	private static final class PackPool {
+		private static final DfsRepositoryDescription repoDesc = new DfsRepositoryDescription(
+				"midxpacklisttest");
 
-	private void setupSixPacksThreeMidx() throws IOException {
-		writePackWithRandomBlob(100);
-		writePackWithRandomBlob(300);
-		writePackWithRandomBlob(50);
-		writePackWithRandomBlob(400);
-		writePackWithRandomBlob(130);
-		writePackWithRandomBlob(500);
-		DfsPackFile[] packs = db.getObjectDatabase().getPacks();
-		assertEquals(6, packs.length);
-		DfsPackFileMidx midxBase = writeMultipackIndex(
-				Arrays.copyOfRange(packs, 4, 6), null);
-		DfsPackFileMidx midxMid = writeMultipackIndex(
-				Arrays.copyOfRange(packs, 2, 4), midxBase);
-		writeMultipackIndex(Arrays.copyOfRange(packs, 0, 2), midxMid);
-		assertEquals("only top midx", 1,
-				db.getObjectDatabase().getPacks().length);
-	}
+		private final Map<String, DfsPackFile> knownPacks = new HashMap<>();
 
-	private DfsPackFileMidx writeMultipackIndex() throws IOException {
-		return writeMultipackIndex(db.getObjectDatabase().getPacks(), null);
-	}
+		DfsPackFile pack(String name) {
+			DfsPackDescription dsc = new DfsPackDescription(repoDesc, name, GC);
+			DfsPackFile p = new DfsPackFile(DfsBlockCache.getInstance(), dsc);
+			knownPacks.put(name, p);
+			return p;
+		}
 
-	private DfsPackFileMidx writeMultipackIndex(DfsPackFile[] packs,
-			DfsPackFileMidx base) throws IOException {
-		List<DfsPackFile> packfiles = asList(packs);
-		DfsPackDescription desc = DfsMidxWriter.writeMidx(
-				NullProgressMonitor.INSTANCE, db.getObjectDatabase(), packfiles,
-				base != null ? base.getPackDescription() : null, null);
-		db.getObjectDatabase().commitPack(List.of(desc), null);
-		return DfsPackFileMidx.create(DfsBlockCache.getInstance(), desc,
-				packfiles, base);
-	}
-
-	private ObjectId writePackWithBlob(byte[] data) throws IOException {
-		DfsInserter ins = (DfsInserter) db.newObjectInserter();
-		ins.setCompressionLevel(Deflater.NO_COMPRESSION);
-		ObjectId blobId = ins.insert(OBJ_BLOB, data);
-		ins.flush();
-		return blobId;
-	}
-
-	// Do not use the size twice into the same test (it gives the same blob!)
-	private ObjectId writePackWithRandomBlob(int size) throws IOException {
-		byte[] data = new TestRng(JGitTestUtil.getName()).nextBytes(size);
-		return writePackWithBlob(data);
+		DfsPackFileMidx midx(String name, DfsPackFileMidx base,
+				String... coveredPacks) {
+			DfsPackDescription dsc = new DfsPackDescription(repoDesc, name, GC);
+			dsc.addFileExt(MULTI_PACK_INDEX);
+			dsc.setCoveredPacks(Arrays.stream(coveredPacks).map(knownPacks::get)
+					.map(DfsPackFile::getPackDescription).toList());
+			if (base != null) {
+				dsc.setMultiPackIndexBase(base.getPackDescription());
+			}
+			return DfsPackFileMidx.create(DfsBlockCache.getInstance(), dsc,
+					knownPacks.values().stream().toList(), base);
+		}
 	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/MidxWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/MidxWriterTest.java
new file mode 100644
index 0000000..bb45d0a
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/MidxWriterTest.java
@@ -0,0 +1,91 @@
+package org.eclipse.jgit.internal.storage.file;
+
+import static org.eclipse.jgit.internal.storage.pack.PackExt.BITMAP_INDEX;
+import static org.eclipse.jgit.lib.Constants.MIDX_FILE;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+
+import org.eclipse.jgit.internal.storage.midx.MultiPackIndex;
+import org.eclipse.jgit.internal.storage.midx.MultiPackIndexLoader;
+import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.TextProgressMonitor;
+import org.eclipse.jgit.revwalk.RevBlob;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.storage.file.WindowCacheConfig;
+import org.eclipse.jgit.storage.pack.PackConfig;
+import org.junit.Before;
+import org.junit.Test;
+
+public class MidxWriterTest extends LocalDiskRepositoryTestCase {
+	private int streamThreshold = 16 * 1024;
+
+	private final static ObjectId UNKNOWN_OBJ = ObjectId
+			.fromString("678668bdd3a609c6e1d7fea516e9fc1ed4f50ad2");
+
+	private FileRepository repo;
+
+	private TestRepository<Repository> tr;
+
+//	private WindowCursor wc;
+
+	@Override
+	@Before
+	public void setUp() throws Exception {
+		super.setUp();
+
+		WindowCacheConfig cfg = new WindowCacheConfig();
+		cfg.setStreamFileThreshold(streamThreshold);
+		cfg.install();
+
+		repo = createBareRepository();
+		tr = new TestRepository<>(repo);
+//		wc = (WindowCursor) repo.newObjectReader();
+	}
+
+	@Test
+	public void midx_write() throws Exception {
+		TestRepository<Repository>.BranchBuilder branch = tr
+				.branch("refs/heads/main");
+		RevBlob contentsOfA = tr.blob("contents of a");
+		RevCommit commitA = branch.commit().add("a.txt", contentsOfA).create();
+		tr.packAndPrune();
+
+		RevBlob contentsOfB = tr.blob("contents of b");
+		RevCommit commitB = branch.commit().add("b.txt", contentsOfB).create();
+		tr.packAndPrune();
+
+		RevCommit commitC = branch.commit().add("c.txt", "contents of c commit")
+				.create();
+		tr.packAndPrune();
+
+		File midxFile = new File(repo.getObjectDatabase().getPackDirectory(),
+				MIDX_FILE);
+		assertFalse(midxFile.exists());
+		MidxWriter.writeMidx(
+				new TextProgressMonitor(new OutputStreamWriter(System.out,
+						StandardCharsets.UTF_8)),
+				repo, repo.getObjectDatabase().getPacks(), midxFile,
+				new PackConfig());
+		assertTrue(midxFile.exists());
+
+		MultiPackIndex midx = MultiPackIndexLoader.open(midxFile);
+		assertTrue(midx.hasObject(commitA));
+		assertTrue(midx.hasObject(commitB));
+		assertTrue(midx.hasObject(commitC));
+		assertFalse(midx.hasObject(UNKNOWN_OBJ));
+
+		File midxBitmaps = new File(repo.getObjectDatabase().getPackDirectory(),
+				String.format("%s-%s.%s", MIDX_FILE,
+						ObjectId.fromRaw(midx.getChecksum()).name(),
+						BITMAP_INDEX.getExtension()));
+		assertTrue(midxBitmaps.exists());
+
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackDirectoryTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackDirectoryTest.java
new file mode 100644
index 0000000..b04d31a
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackDirectoryTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2026, Google LLC. and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.internal.storage.file;
+
+import static org.eclipse.jgit.lib.Constants.MIDX_FILE;
+import static org.junit.Assert.assertEquals;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+
+import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.lib.TextProgressMonitor;
+import org.eclipse.jgit.revwalk.RevBlob;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.storage.file.WindowCacheConfig;
+import org.eclipse.jgit.storage.pack.PackConfig;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PackDirectoryTest extends LocalDiskRepositoryTestCase {
+	private int streamThreshold = 16 * 1024;
+
+	private FileRepository repo;
+
+	private TestRepository<FileRepository> tr;
+
+	@Override
+	@Before
+	public void setUp() throws Exception {
+		super.setUp();
+
+		WindowCacheConfig cfg = new WindowCacheConfig();
+		cfg.setStreamFileThreshold(streamThreshold);
+		cfg.install();
+
+		mockSystemReader.getSystemConfig().setBoolean(
+				ConfigConstants.CONFIG_CORE_SECTION, null,
+				ConfigConstants.CONFIG_KEY_MULTIPACKINDEX, true);
+
+		repo = createBareRepository();
+		tr = new TestRepository<>(repo);
+	}
+
+	@Test
+	public void getPacks_midxReplacesCoveredPacks() throws Exception {
+		createThreePacks();
+		Collection<Pack> packs = repo.getObjectDatabase().getPacks();
+		assertEquals(3, packs.size());
+		writeMidxOverAllPacks();
+
+		// Reading now should return the midx
+		packs = repo.getObjectDatabase().getPacks();
+		assertEquals(1, packs.size());
+
+		tr.branch("refs/heads/main").commit().add("more.txt", "booooo")
+				.create();
+		tr.packAndPrune();
+
+		packs = repo.getObjectDatabase().getPacks();
+		assertEquals(2, packs.size());
+	}
+
+	private TestRepoObjects createThreePacks() throws Exception {
+		TestRepository<FileRepository>.BranchBuilder branch = tr
+				.branch("refs/heads/main");
+		RevBlob contentsOfA = tr.blob("contents of a");
+		RevCommit commitA = branch.commit().add("a.txt", contentsOfA).create();
+		tr.packAndPrune();
+
+		RevBlob contentsOfB = tr.blob("contents of b");
+		RevCommit commitB = branch.commit().add("b.txt", contentsOfB).create();
+		tr.packAndPrune();
+
+		RevCommit commitC = branch.commit().add("c.txt", "contents of c commit")
+				.create();
+		tr.packAndPrune();
+
+		Map<RevObject, Integer> midxOffsets = Map.of(commitA, 163, commitB, 12,
+				commitC, 694, contentsOfA, 399, contentsOfB, 421);
+
+		return new TestRepoObjects(commitA, commitB, commitC, contentsOfA,
+				contentsOfB, midxOffsets);
+	}
+
+	private record TestRepoObjects(RevCommit commitA, RevCommit commitB,
+			RevCommit commitC, RevBlob contentsOfA, RevBlob contentsOfB,
+			Map<RevObject, Integer> midxOffsets) {
+	}
+
+	private void writeMidxOverAllPacks() throws IOException {
+		Collection<Pack> packs = tr.getRepository().getObjectDatabase()
+				.getPacks();
+		assertEquals(3, packs.size());
+
+		File midxDest = new File(repo.getObjectDatabase().getPackDirectory(),
+				MIDX_FILE);
+		MidxWriter.writeMidx(new TextProgressMonitor(), repo, packs, midxDest,
+				new PackConfig(repo));
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackMidxTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackMidxTest.java
new file mode 100644
index 0000000..7a497d6
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackMidxTest.java
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2026, Google LLC
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.internal.storage.file;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.TextProgressMonitor;
+import org.eclipse.jgit.revwalk.RevBlob;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.storage.file.WindowCacheConfig;
+import org.eclipse.jgit.storage.pack.PackConfig;
+import org.junit.Before;
+import org.junit.Test;
+
+public class PackMidxTest extends LocalDiskRepositoryTestCase {
+	private int streamThreshold = 16 * 1024;
+
+	private final static ObjectId UNKNOWN_OBJ = ObjectId
+			.fromString("678668bdd3a609c6e1d7fea516e9fc1ed4f50ad2");
+
+	private FileRepository repo;
+
+	private TestRepository<Repository> tr;
+
+	private WindowCursor wc;
+
+	@Override
+	@Before
+	public void setUp() throws Exception {
+		super.setUp();
+
+		WindowCacheConfig cfg = new WindowCacheConfig();
+		cfg.setStreamFileThreshold(streamThreshold);
+		cfg.install();
+
+		repo = createBareRepository();
+		tr = new TestRepository<>(repo);
+		wc = (WindowCursor) repo.newObjectReader();
+	}
+
+	@Test
+	public void midx_hasObject() throws Exception {
+		TestRepoObjects objs = createThreePacks();
+		PackMidx midx = writeAndOpenMidxAllPacks();
+
+		assertTrue(midx.hasObject(objs.commitA));
+		assertTrue(midx.hasObject(objs.commitB));
+		assertTrue(midx.hasObject(objs.commitC));
+		assertTrue(midx.hasObject(objs.contentsOfB));
+		assertTrue(midx.hasObject(objs.contentsOfA));
+		assertFalse(midx.hasObject(UNKNOWN_OBJ));
+	}
+
+	@Test
+	public void midx_getObjectCount() throws Exception {
+		createThreePacks();
+		PackMidx midx = writeAndOpenMidxAllPacks();
+		assertEquals(9, midx.getObjectCount());
+	}
+
+	@Test
+	public void midx_getObjectSize_byId() throws Exception {
+		TestRepoObjects objs = createThreePacks();
+		PackMidx midx = writeAndOpenMidxAllPacks();
+
+		assertEquals(getObjectSizeFromObjectDb(objs.commitA),
+				midx.getObjectSize(wc, objs.commitA));
+		assertEquals(getObjectSizeFromObjectDb(objs.commitB),
+				midx.getObjectSize(wc, objs.commitB));
+		assertEquals(getObjectSizeFromObjectDb(objs.commitC),
+				midx.getObjectSize(wc, objs.commitC));
+		assertEquals(getObjectSizeFromObjectDb(objs.contentsOfA),
+				midx.getObjectSize(wc, objs.contentsOfA));
+		assertEquals(getObjectSizeFromObjectDb(objs.contentsOfB),
+				midx.getObjectSize(wc, objs.contentsOfB));
+		assertEquals(-1, midx.getObjectSize(wc, UNKNOWN_OBJ));
+	}
+
+	@Test
+	public void midx_getObjectSize_byOffset() throws Exception {
+		TestRepoObjects objs = createThreePacks();
+		PackMidx midx = writeAndOpenMidxAllPacks();
+
+		Map<RevObject, Integer> midxOffsets = objs.midxOffsets;
+		Integer offsetCommitA = midxOffsets.get(objs.commitA);
+		assertEquals(getObjectSizeFromObjectDb(objs.commitA),
+				midx.getObjectSize(wc, offsetCommitA));
+
+		Integer offsetCommitB = midxOffsets.get(objs.commitB);
+		assertEquals(getObjectSizeFromObjectDb(objs.commitB),
+				midx.getObjectSize(wc, offsetCommitB));
+
+		Integer offsetCommitC = midxOffsets.get(objs.commitC);
+		assertEquals(getObjectSizeFromObjectDb(objs.commitC),
+				midx.getObjectSize(wc, offsetCommitC));
+
+		Integer offsetContentsOfA = midxOffsets.get(objs.contentsOfA);
+		assertEquals(getObjectSizeFromObjectDb(objs.contentsOfA),
+				midx.getObjectSize(wc, offsetContentsOfA));
+
+		Integer offsetContentsOfB = midxOffsets.get(objs.contentsOfB);
+		assertEquals(midx.getObjectSize(wc, objs.contentsOfB),
+				midx.getObjectSize(wc, offsetContentsOfB));
+	}
+
+	private long getObjectSizeFromObjectDb(AnyObjectId oid) throws IOException {
+		return repo.getObjectDatabase().getObjectSize(wc, oid);
+	}
+
+	@Test
+	public void midx_get_byOid() throws Exception {
+		TestRepoObjects objs = createThreePacks();
+		PackMidx midx = writeAndOpenMidxAllPacks();
+
+		assertEquals("contents of a", midxGet(midx, objs.contentsOfA));
+		assertEquals("contents of b", midxGet(midx, objs.contentsOfB));
+		String commitContent = midxGet(midx, objs.commitB);
+		assertTrue(commitContent
+				.startsWith("tree 4ad3577dd1af1fe281a6e55d48cee2d397d570d5"));
+		assertTrue(commitContent
+				.contains("author J. Author <jauthor@example.com>"));
+
+		assertNull(midx.get(wc, UNKNOWN_OBJ));
+	}
+
+	private String midxGet(PackMidx midx, AnyObjectId oid) throws IOException {
+		ObjectLoader ol = midx.get(wc, oid);
+		return new String(ol.getCachedBytes(), UTF_8);
+	}
+
+	@Test
+	public void midx_load_byOffset() throws Exception {
+		TestRepoObjects objs = createThreePacks();
+		PackMidx midx = writeAndOpenMidxAllPacks();
+
+		Map<RevObject, Integer> midxOffsets = objs.midxOffsets;
+		assertEquals("contents of a",
+				midxLoad(midx, midxOffsets.get(objs.contentsOfA)));
+		assertEquals("contents of b",
+				midxLoad(midx, midxOffsets.get(objs.contentsOfB)));
+		String commitContent = midxLoad(midx, midxOffsets.get(objs.commitB));
+		assertTrue(commitContent
+				.startsWith("tree 4ad3577dd1af1fe281a6e55d48cee2d397d570d5"));
+		assertTrue(commitContent
+				.contains("author J. Author <jauthor@example.com>"));
+	}
+
+	private String midxLoad(PackMidx midx, int pos) throws IOException {
+		ObjectLoader ol = midx.load(wc, pos);
+		return new String(ol.getCachedBytes(), UTF_8);
+	}
+
+	@Test
+	public void midx_findObject_byOffset() throws Exception {
+		TestRepoObjects objs = createThreePacks();
+		PackMidx midx = writeAndOpenMidxAllPacks();
+
+		Map<RevObject, Integer> midxOffsets = objs.midxOffsets;
+		assertEquals(objs.commitA,
+				midx.findObjectForOffset(midxOffsets.get(objs.commitA)));
+		assertEquals(objs.commitB,
+				midx.findObjectForOffset(midxOffsets.get(objs.commitB)));
+		assertEquals(objs.commitC,
+				midx.findObjectForOffset(midxOffsets.get(objs.commitC)));
+		assertEquals(objs.contentsOfA,
+				midx.findObjectForOffset(midxOffsets.get(objs.contentsOfA)));
+		assertEquals(objs.contentsOfB,
+				midx.findObjectForOffset(midxOffsets.get(objs.contentsOfB)));
+	}
+
+	@Test
+	public void midx_getObjectType() throws Exception {
+		TestRepoObjects objs = createThreePacks();
+		PackMidx midx = writeAndOpenMidxAllPacks();
+
+		Map<RevObject, Integer> midxOffsets = objs.midxOffsets;
+		assertEquals(Constants.OBJ_COMMIT,
+				midx.getObjectType(wc, midxOffsets.get(objs.commitA)));
+		assertEquals(Constants.OBJ_COMMIT,
+				midx.getObjectType(wc, midxOffsets.get(objs.commitB)));
+		assertEquals(Constants.OBJ_COMMIT,
+				midx.getObjectType(wc, midxOffsets.get(objs.commitC)));
+		assertEquals(Constants.OBJ_BLOB,
+				midx.getObjectType(wc, midxOffsets.get(objs.contentsOfA)));
+		assertEquals(Constants.OBJ_BLOB,
+				midx.getObjectType(wc, midxOffsets.get(objs.contentsOfB)));
+	}
+
+	@Test
+	public void midx_iterator() throws Exception {
+		TestRepoObjects objs = createThreePacks();
+		PackMidx midx = writeAndOpenMidxAllPacks();
+
+		Map<RevObject, Integer> midxOffsets = objs.midxOffsets;
+		Iterator<PackIndex.MutableEntry> it = midx.iterator();
+		assertIteratorEntry(it, objs.contentsOfB,
+				midxOffsets.get(objs.contentsOfB));
+		it.next();
+		it.next();
+		assertIteratorEntry(it, objs.commitB, midxOffsets.get(objs.commitB));
+		assertIteratorEntry(it, objs.commitA, midxOffsets.get(objs.commitA));
+		it.next();
+		it.next();
+		assertIteratorEntry(it, objs.contentsOfA,
+				midxOffsets.get(objs.contentsOfA));
+		assertIteratorEntry(it, objs.commitC, midxOffsets.get(objs.commitC));
+		assertFalse(it.hasNext());
+	}
+
+	private void assertIteratorEntry(Iterator<PackIndex.MutableEntry> it,
+			ObjectId oid, int offset) {
+		assertTrue(it.hasNext());
+		PackIndex.MutableEntry next = it.next();
+		assertEquals(oid, next.toObjectId());
+		assertEquals(offset, next.getOffset());
+	}
+
+	@Test
+	public void midx_packIndex_hasObject() throws Exception {
+		TestRepoObjects objs = createThreePacks();
+		PackMidx midx = writeAndOpenMidxAllPacks();
+
+		PackIndex index = midx.getIndex();
+		assertTrue(index.hasObject(objs.commitA));
+		assertTrue(index.hasObject(objs.commitB));
+		assertTrue(index.hasObject(objs.commitC));
+		assertTrue(index.hasObject(objs.contentsOfA));
+		assertTrue(index.hasObject(objs.contentsOfB));
+		assertFalse(index.hasObject(UNKNOWN_OBJ));
+	}
+
+	@Test
+	public void midx_packIndex_findPosition_getByPosition() throws Exception {
+		TestRepoObjects objs = createThreePacks();
+		PackMidx midx = writeAndOpenMidxAllPacks();
+
+		PackIndex index = midx.getIndex();
+		assertEquals(objs.commitA,
+				index.getObjectId(index.findPosition(objs.commitA)));
+		assertEquals(objs.commitB,
+				index.getObjectId(index.findPosition(objs.commitB)));
+		assertEquals(objs.commitC,
+				index.getObjectId(index.findPosition(objs.commitC)));
+		assertEquals(objs.contentsOfA,
+				index.getObjectId(index.findPosition(objs.contentsOfA)));
+		assertEquals(objs.contentsOfB,
+				index.getObjectId(index.findPosition(objs.contentsOfB)));
+		assertEquals(-1, index.findPosition(UNKNOWN_OBJ));
+	}
+
+	@Test
+	public void midx_packIndex_findOffset() throws Exception {
+		TestRepoObjects objs = createThreePacks();
+		PackMidx midx = writeAndOpenMidxAllPacks();
+
+		Map<RevObject, Integer> offsets = objs.midxOffsets;
+		PackIndex index = midx.getIndex();
+		assertEquals((long) offsets.get(objs.commitA),
+				index.findOffset(objs.commitA));
+		assertEquals((long) offsets.get(objs.commitB),
+				index.findOffset(objs.commitB));
+		assertEquals((long) offsets.get(objs.commitC),
+				index.findOffset(objs.commitC));
+		assertEquals((long) offsets.get(objs.contentsOfA),
+				index.findOffset(objs.contentsOfA));
+		assertEquals((long) offsets.get(objs.contentsOfB),
+				index.findOffset(objs.contentsOfB));
+		assertEquals(-1, index.findOffset(UNKNOWN_OBJ));
+	}
+
+	@Test
+	public void midx_reversePackIndex_findObject() throws Exception {
+		TestRepoObjects objs = createThreePacks();
+		PackMidx midx = writeAndOpenMidxAllPacks();
+
+		List<ObjectOffset> offsetOrdered = inRidxOrder(objs.midxOffsets);
+		PackReverseIndex ridx = midx.getReverseIdx();
+
+		assertFalse(offsetOrdered.isEmpty());
+		for (int i = 0; i < offsetOrdered.size(); i++) {
+			ObjectOffset entry = offsetOrdered.get(i);
+			assertEquals(entry.obj().getId(), ridx.findObject(entry.offset()));
+		}
+	}
+
+	@Test
+	public void midx_reversePackIndex_findPosition_findObjectByPosition()
+			throws Exception {
+		TestRepoObjects objs = createThreePacks();
+		PackMidx midx = writeAndOpenMidxAllPacks();
+
+		List<ObjectOffset> offsetOrdered = inRidxOrder(objs.midxOffsets);
+		PackReverseIndex ridx = midx.getReverseIdx();
+
+		assertFalse(offsetOrdered.isEmpty());
+		for (int i = 0; i < offsetOrdered.size(); i++) {
+			ObjectOffset entry = offsetOrdered.get(i);
+			assertEquals(entry.obj(), ridx
+					.findObjectByPosition(ridx.findPosition(entry.offset())));
+		}
+	}
+
+	private PackMidx writeAndOpenMidxAllPacks() throws IOException {
+		Collection<Pack> packs = ((ObjectDirectory) tr.getRepository()
+				.getObjectDatabase()).getPacks();
+		assertEquals(3, packs.size());
+
+		File midxDest = new File(repo.getObjectDatabase().getPackDirectory(),
+				Constants.MIDX_FILE);
+		MidxWriter.writeMidx(new TextProgressMonitor(), repo, packs, midxDest,
+				new PackConfig(repo));
+
+		return new PackMidx(new Config(), midxDest, packs.stream().toList());
+
+	}
+
+	private TestRepoObjects createThreePacks() throws Exception {
+		TestRepository<Repository>.BranchBuilder branch = tr
+				.branch("refs/heads/main");
+		RevBlob contentsOfA = tr.blob("contents of a");
+		RevCommit commitA = branch.commit().add("a.txt", contentsOfA).create();
+		tr.packAndPrune();
+
+		RevBlob contentsOfB = tr.blob("contents of b");
+		RevCommit commitB = branch.commit().add("b.txt", contentsOfB).create();
+		tr.packAndPrune();
+
+		RevCommit commitC = branch.commit().add("c.txt", "contents of c commit")
+				.create();
+		tr.packAndPrune();
+
+		Map<RevObject, Integer> midxOffsets = Map.of(commitA, 163, commitB, 12,
+				commitC, 694, contentsOfA, 399, contentsOfB, 421);
+
+		return new TestRepoObjects(commitA, commitB, commitC, contentsOfA,
+				contentsOfB, midxOffsets);
+	}
+
+	private record TestRepoObjects(RevCommit commitA, RevCommit commitB,
+			RevCommit commitC, RevBlob contentsOfA, RevBlob contentsOfB,
+			Map<RevObject, Integer> midxOffsets) {
+	}
+
+	private List<ObjectOffset> inRidxOrder(Map<RevObject, Integer> objs) {
+		return objs.entrySet().stream()
+				.map(e -> new ObjectOffset(e.getKey(), e.getValue()))
+				.sorted(Comparator.comparing(ObjectOffset::offset)).toList();
+	}
+
+	private record ObjectOffset(RevObject obj, Integer offset) {
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MidxMetadataReaderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MidxMetadataReaderTest.java
new file mode 100644
index 0000000..b41d6c3
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MidxMetadataReaderTest.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2026, Google LLC
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.internal.storage.midx;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+import org.eclipse.jgit.junit.JGitTestUtil;
+import org.junit.Test;
+
+public class MidxMetadataReaderTest {
+	@Test
+	public void load_validFile_basic_upstream() throws Exception {
+		MidxMetadataReader.MidxMetadata meta = MidxMetadataReader
+				.read(JGitTestUtil.getTestResourceFile("multi-pack-index.v1"));
+		assertEquals(26, meta.packNames().size());
+
+		byte[] expected = new byte[] { 15, -10, -96, 97, 76, 13, -72, 95, 106,
+				15, -55, -12, 18, -13, 50, 33, 120, -113, 71, -119 };
+		assertArrayEquals(expected, meta.checksum());
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriterTest.java
index 1ca8aaf..1743fb0 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriterTest.java
@@ -174,6 +174,18 @@ public void jgit_emptyMidx() throws IOException {
 		assertEquals(5, chunkIds.indexOf(MIDX_CHUNKID_PACKNAMES));
 	}
 
+	@Test
+	public void jgit_noPacks() throws IOException {
+		PackIndexMerger packs = PackIndexMerger.builder().build();
+		MultiPackIndexWriter writer = new MultiPackIndexWriter();
+		ByteArrayOutputStream out = new ByteArrayOutputStream();
+		MultiPackIndexWriter.Result result = writer
+				.write(NullProgressMonitor.INSTANCE, out, packs);
+		assertEquals(0, result.packNames().size());
+		MidxHeader header = readHeader(out);
+		assertEquals(0, header.packCount());
+	}
+
 	private List<Integer> readChunkIds(ByteArrayOutputStream out) {
 		List<Integer> chunkIds = new ArrayList<>();
 		byte[] raw = out.toByteArray();
@@ -193,4 +205,14 @@ private static PackIndex indexOf(IndexObject... objs) {
 	private static IndexObject object(String name, long offset) {
 		return new IndexObject(name, offset);
 	}
+
+	private record MidxHeader(int packCount) {
+	}
+
+	private MidxHeader readHeader(ByteArrayOutputStream out) {
+		byte[] midx = out.toByteArray();
+
+		int packCount = NB.decodeInt32(midx, 8);
+		return new MidxHeader(packCount);
+	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/transport/connectivity/TreeWalkConnectivityCheckerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/transport/connectivity/TreeWalkConnectivityCheckerTest.java
new file mode 100644
index 0000000..371f876
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/transport/connectivity/TreeWalkConnectivityCheckerTest.java
@@ -0,0 +1,1129 @@
+/*
+ * Copyright (C) 2026, Google LLC and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+package org.eclipse.jgit.internal.transport.connectivity;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
+import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
+import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.CommitBuilder;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdSubclassMap;
+import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.lib.TreeFormatter;
+import org.eclipse.jgit.revwalk.RevBlob;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevTag;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.ConnectivityChecker.ConnectivityCheckInfo;
+import org.eclipse.jgit.transport.PackParser;
+import org.eclipse.jgit.transport.ReceiveCommand;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import jdk.jfr.Recording;
+import jdk.jfr.consumer.RecordingFile;
+
+/** Tests for {@link TreeWalkConnectivityChecker}. */
+public class TreeWalkConnectivityCheckerTest {
+	@Rule
+	public MockitoRule rule = MockitoJUnit.rule();
+
+	private TestRepository<InMemoryRepository> tr;
+
+	private TreeWalkConnectivityChecker checker;
+
+	private ConnectivityCheckInfo info;
+
+	private Set<ObjectId> haves;
+
+	private CountingProgressMonitor pm = new CountingProgressMonitor();
+
+	private static class CountingProgressMonitor implements ProgressMonitor {
+		private long objectsCheckedCount = 0;
+
+		@Override
+		public void start(int totalTasks) {
+			// noop
+		}
+
+		@Override
+		public void beginTask(String title, int totalWork) {
+			// noop
+		}
+
+		@Override
+		public void update(int completed) {
+			objectsCheckedCount += completed;
+		}
+
+		@Override
+		public void endTask() {
+			// noop
+		}
+
+		@Override
+		public boolean isCancelled() {
+			return false;
+		}
+
+		@Override
+		public void showDuration(boolean show) {
+			// noop
+		}
+
+		public long getObjectsCheckedCount() {
+			return objectsCheckedCount;
+		}
+
+		public void reset() {
+			objectsCheckedCount = 0;
+		}
+	}
+
+	@Mock
+	private PackParser parser;
+
+	@Before
+	@SuppressWarnings("boxing")
+	public void setUp() throws Exception {
+		tr = new TestRepository<>(
+				new InMemoryRepository(new DfsRepositoryDescription("test")));
+		checker = new TreeWalkConnectivityChecker();
+		info = new ConnectivityCheckInfo();
+		info.setRepository(tr.getRepository());
+		info.setWalk(tr.getRevWalk());
+		info.setParser(parser);
+		when(parser.needNewObjectIds()).thenReturn(true);
+		haves = new HashSet<>();
+		pm.reset();
+	}
+
+	@Test
+	public void testFailureMissingParent() throws Exception {
+		ObjectId missingParentId = ObjectId
+				.fromString("0123456789abcdef0123456789abcdef01234567");
+
+		RevCommit newCommit = createCommitWithParent(missingParentId);
+
+		setupSingleReceiveCommand(ObjectId.zeroId(), newCommit.getId());
+		mockNewPackObjects(newCommit);
+
+		// MOE thrown within RevWalk.next() when emitting newCommit, count isn't
+		// updated
+		runCheckAndExpectMissingObject(missingParentId, 0);
+	}
+
+	@Test
+	public void testFailureMissingParentChain() throws Exception {
+		ObjectId missingParentId = ObjectId
+				.fromString("0123456789abcdef0123456789abcdef01234567");
+
+		RevCommit commit1 = createCommitWithParent(missingParentId);
+		RevCommit commit2 = createCommitWithParent(commit1);
+
+		setupSingleReceiveCommand(ObjectId.zeroId(), commit2.getId());
+		mockNewPackObjects(commit1, commit2);
+
+		runCheckAndExpectMissingObject(missingParentId, 1);
+	}
+
+	@Test
+	public void testFailureMissingParentMultipleBranches() throws Exception {
+		RevCommit base = tr.commit().create();
+		haves.add(base.getId());
+
+		ObjectId missingParentId = ObjectId
+				.fromString("0123456789abcdef0123456789abcdef01234567");
+
+		RevCommit newCommit1 = tr.commit().parent(base).create();
+		RevCommit newCommit2 = createCommitWithParent(missingParentId);
+
+		ReceiveCommand cmd1 = new ReceiveCommand(base, newCommit1,
+				"refs/heads/branch1");
+		ReceiveCommand cmd2 = new ReceiveCommand(ObjectId.zeroId(), newCommit2,
+				"refs/heads/branch2");
+
+		info.setCommands(Arrays.asList(cmd1, cmd2));
+
+		mockNewPackObjects(newCommit1, newCommit2);
+
+		runCheckAndExpectMissingObject(missingParentId, 1);
+	}
+
+	@Test
+	public void testFailureMissingBlob() throws Exception {
+		RevCommit base = tr.commit().create();
+		haves.add(base.getId());
+
+		// Create a missing blob ID that is not in DB or pack
+		ObjectId missingBlobId = ObjectId
+				.fromString("0123456789abcdef0123456789abcdef01234567");
+		RevBlob missingBlob = tr.getRevWalk().lookupBlob(missingBlobId);
+
+		RevCommit newCommit = tr.commit().parent(base).add("foo", missingBlob)
+				.create();
+
+		setupSingleReceiveCommand(base.getId(), newCommit.getId());
+		mockNewPackObjects(newCommit, newCommit.getTree());
+
+		runCheckAndExpectMissingObject(missingBlobId, 4);
+	}
+
+	@Test
+	public void testFailureMissingSubtree() throws Exception {
+		RevCommit base = tr.commit().create();
+		haves.add(base.getId());
+
+		ObjectId missingTreeId = ObjectId
+				.fromString("0123456789abcdef0123456789abcdef01234568");
+
+		RevBlob blob = tr.blob("content");
+
+		TreeFormatter formatter = new TreeFormatter();
+		formatter.append("file", FileMode.REGULAR_FILE, blob);
+		formatter.append("dir", FileMode.TREE, missingTreeId);
+
+		try (ObjectInserter inserter = tr.getRepository().newObjectInserter()) {
+			ObjectId rootTreeId = inserter.insert(formatter);
+
+			CommitBuilder cb = new CommitBuilder();
+			cb.setTreeId(rootTreeId);
+			cb.setAuthor(new PersonIdent("Author", "author@example.com"));
+			cb.setCommitter(
+					new PersonIdent("Committer", "committer@example.com"));
+			cb.setMessage("Commit with missing subtree");
+			cb.setParentIds(base.getId());
+
+			ObjectId commitId = inserter.insert(cb);
+			inserter.flush();
+
+			RevCommit newCommit = tr.getRevWalk().parseCommit(commitId);
+
+			setupSingleReceiveCommand(base.getId(), newCommit.getId());
+			mockNewPackObjects(newCommit, newCommit.getTree(), blob);
+
+			runCheckAndExpectMissingObject(missingTreeId, 4);
+		}
+	}
+
+	@Test
+	public void testFailureUnreachableParentCommit() throws Exception {
+		RevCommit base = tr.commit().create();
+		haves.add(base.getId());
+
+		RevCommit secretCommit = tr.commit().create();
+		RevCommit newCommit = tr.commit().parent(secretCommit).create();
+
+		setupSingleReceiveCommand(ObjectId.zeroId(), newCommit.getId());
+		mockNewPackObjects(newCommit, newCommit.getTree());
+
+		runCheckAndExpectMissingObject(secretCommit.getId(), 3);
+	}
+
+	@Test
+	public void testMultipleBranchesUnreachableParent() throws Exception {
+		// base2 & new2 have newer timestamps
+		RevCommit base1 = tr.commit().create();
+		RevCommit new1 = tr.commit().parent(base1).create();
+		RevCommit base2 = tr.commit().create();
+		RevCommit new2 = tr.commit().parent(base2).create();
+
+		tr.branch("refs/heads/base1").update(base1);
+		haves.add(base1);
+
+		ReceiveCommand cmd1 = new ReceiveCommand(base1, new1, "refs/heads/b1");
+		ReceiveCommand cmd2 = new ReceiveCommand(base2, new2, "refs/heads/b2");
+
+		info.setCommands(Arrays.asList(cmd1, cmd2));
+		mockNewPackObjects(new1, new1.getTree(), new2, new2.getTree());
+
+		runCheckAndExpectMissingObject(base2, 5);
+
+		// Verify order doesn't matter - reset state and swap order
+		setUp();
+
+		// base2 & new2 have newer timestamps
+		base1 = tr.commit().create();
+		new1 = tr.commit().parent(base1).create();
+		base2 = tr.commit().create();
+		new2 = tr.commit().parent(base2).create();
+
+		tr.branch("refs/heads/base2").update(base2);
+		haves.add(base2);
+
+		cmd1 = new ReceiveCommand(base1, new1, "refs/heads/b1");
+		cmd2 = new ReceiveCommand(base2, new2, "refs/heads/b2");
+
+		info.setCommands(Arrays.asList(cmd2, cmd1));
+		mockNewPackObjects(new1, new1.getTree(), new2, new2.getTree());
+
+		runCheckAndExpectMissingObject(base1, 5);
+	}
+
+	@Test
+	public void testThinPackFailureUnreachableDeltaBase() throws Exception {
+		RevCommit base = tr.commit().create();
+		haves.add(base.getId());
+
+		RevBlob deltafiledBlob = tr.blob("simulated delta blob");
+		RevBlob missingBase = tr.getRevWalk().lookupBlob(ObjectId
+				.fromString("0123456789abcdef0123456789abcdef01234567"));
+		RevCommit newCommit = tr.commit().parent(base)
+				.add("foo", deltafiledBlob).create();
+
+		setupSingleReceiveCommand(ObjectId.zeroId(), newCommit);
+		mockNewPackObjects(newCommit, newCommit.getTree(), deltafiledBlob);
+
+		ObjectIdSubclassMap<ObjectId> baseObjectIds = new ObjectIdSubclassMap<>();
+		baseObjectIds.add(missingBase);
+		when(parser.getBaseObjectIds()).thenReturn(baseObjectIds);
+		info.setCheckObjects(true);
+
+		runCheckAndExpectMissingObject(missingBase.getId(), 2);
+	}
+
+	@Test
+	public void testSuccessMatchingParent() throws Exception {
+		RevCommit base = tr.commit().create();
+		haves.add(base.getId());
+
+		// Create a new commit in the pack that explicitly matches the base tree
+		ObjectId newCommitId = tr.unparsedCommit(1, base.getTree(),
+				base.getId());
+		RevCommit newCommit = tr.getRevWalk().parseCommit(newCommitId);
+
+		setupSingleReceiveCommand(base.getId(), newCommitId);
+		mockNewPackObjects(newCommit);
+		runCheckAndAssertCount(4);
+	}
+
+	@Test
+	public void testSuccessWithDifferentBlob() throws Exception {
+		RevCommit base = tr.commit().create();
+		haves.add(base.getId());
+
+		RevBlob blob = tr.blob("hello");
+		RevCommit newCommit = tr.commit().parent(base).add("foo", blob)
+				.create();
+
+		setupSingleReceiveCommand(base.getId(), newCommit.getId());
+		mockNewPackObjects(newCommit, newCommit.getTree(), blob);
+
+		runCheckAndAssertCount(4);
+	}
+
+	@Test
+	public void testSuccessNoReachabilityCheckWhenParentsInHaves()
+			throws Exception {
+		RevCommit base = tr.commit().create();
+		haves.add(base.getId());
+
+		RevCommit currentHaves = base;
+		for (int i = 0; i < 250; i++) {
+			currentHaves = tr.commit().parent(currentHaves).create();
+			haves.add(currentHaves.getId());
+		}
+
+		RevBlob blob = tr.blob("hello");
+		RevCommit newCommit = tr.commit().parent(base).add("foo", blob)
+				.create();
+
+		setupSingleReceiveCommand(base.getId(), newCommit.getId());
+		mockNewPackObjects(newCommit);
+
+		runCheckAndAssertCount(4);
+	}
+
+	/**
+	 * Test with a large flat tree to measure objects checked.
+	 *
+	 * <pre>{@code
+	 * [Existing DB]               [Received Pack]
+	 *      base <------------------- newCommit
+	 *        |                          |
+	 *      root_tree                 root_tree (differs)
+	 *        |                          |
+	 *        +- file0                   +- file0 (differs)
+	 *        +- file1                   +- file1 (differs)
+	 *        +- file2                   +- file2 (differs)
+	 *        +- file3                   +- file3 (differs)
+	 *        +- file4                   +- file4 (differs)
+	 *        +- file5                   +- file5 (shared)
+	 *        +- ...                     +- ...
+	 *        `- file99                  `- file99 (shared)
+	 * }</pre>
+	 */
+	@Test
+	public void testLargeFlatTree() throws Exception {
+		TestRepository.CommitBuilder cb = tr.commit();
+		for (int i = 0; i < 100; i++) {
+			cb.add("file" + i, tr.blob("content" + i));
+		}
+		RevCommit base = cb.create();
+		haves.add(base.getId());
+
+		TestRepository.CommitBuilder cbNew = tr.commit().parent(base);
+		List<ObjectId> allNewObjects = new ArrayList<>();
+		for (int i = 0; i < 5; i++) {
+			RevBlob b = tr.blob("new content " + i);
+			cbNew.add("file" + i, b);
+			allNewObjects.add(b);
+		}
+		RevCommit newCommit = cbNew.create();
+		allNewObjects.add(newCommit);
+		allNewObjects.add(newCommit.getTree());
+
+		setupSingleReceiveCommand(base.getId(), newCommit.getId());
+		mockNewPackObjects(allNewObjects);
+
+		runCheckAndAssertCount(4);
+	}
+
+	@Test
+	public void testGitlink() throws Exception {
+		RevCommit base = tr.commit().create();
+		haves.add(base.getId());
+
+		ObjectId submoduleCommitId = ObjectId
+				.fromString("0123456789abcdef0123456789abcdef01234567");
+
+		TreeFormatter formatter = new TreeFormatter();
+		formatter.append("submodule", FileMode.GITLINK, submoduleCommitId);
+
+		try (ObjectInserter inserter = tr.getRepository().newObjectInserter()) {
+			ObjectId rootTreeId = inserter.insert(formatter);
+
+			CommitBuilder cb = new CommitBuilder();
+			cb.setTreeId(rootTreeId);
+			cb.setAuthor(new PersonIdent("Author", "author@example.com"));
+			cb.setCommitter(
+					new PersonIdent("Committer", "committer@example.com"));
+			cb.setMessage("Commit with gitlink");
+			cb.setParentIds(base.getId());
+
+			ObjectId commitId = inserter.insert(cb);
+			inserter.flush();
+
+			RevCommit newCommit = tr.getRevWalk().parseCommit(commitId);
+
+			setupSingleReceiveCommand(base.getId(), newCommit.getId());
+			mockNewPackObjects(newCommit, newCommit.getTree());
+
+			// Should not fail gitlink identifier not being in the local
+			// database
+			runCheckAndAssertCount(4);
+		}
+	}
+
+	@Test
+	public void testZeroParents() throws Exception {
+		RevBlob blob = tr.blob("content");
+		RevCommit rootCommit = tr.commit().add("file1", blob).create();
+
+		setupSingleReceiveCommand(ObjectId.zeroId(), rootCommit.getId());
+		mockNewPackObjects(rootCommit, rootCommit.getTree(), blob);
+
+		runCheckAndAssertCount(2);
+	}
+
+	@Test
+	public void testMultipleParents() throws Exception {
+		RevCommit parent1 = tr.commit().add("file1", tr.blob("content1"))
+				.create();
+		RevCommit parent2 = tr.commit().add("file2", tr.blob("content2"))
+				.create();
+		haves.add(parent1.getId());
+		haves.add(parent2.getId());
+
+		RevCommit mergeCommit = tr.commit().parent(parent1).parent(parent2)
+				.add("file3", tr.blob("content3")).create();
+
+		setupSingleReceiveCommand(ObjectId.zeroId(), mergeCommit.getId());
+		mockNewPackObjects(mergeCommit, mergeCommit.getTree());
+
+		runCheckAndAssertCount(6);
+	}
+
+	@Test
+	public void testChainedCommitsInPack() throws Exception {
+		RevCommit base = tr.commit().create();
+		haves.add(base.getId());
+
+		RevCommit c1 = tr.commit().parent(base).create();
+		RevCommit c2 = tr.commit().parent(c1).create();
+
+		setupSingleReceiveCommand(base.getId(), c2.getId());
+		mockNewPackObjects(c1, c2, c1.getTree(), c2.getTree());
+
+		runCheckAndAssertCount(7);
+	}
+
+	@Test
+	public void testSuccessReachableParentCommit() throws Exception {
+		RevCommit base = tr.commit().create();
+		RevCommit reachableCommit = tr.commit().parent(base).create();
+		haves.add(reachableCommit.getId());
+
+		RevCommit newCommit = tr.commit().parent(base).create();
+
+		setupSingleReceiveCommand(ObjectId.zeroId(), newCommit.getId());
+		mockNewPackObjects(newCommit, newCommit.getTree());
+
+		runCheckAndAssertCount(5);
+	}
+
+	@Test
+	public void testSuccessFallbackToFullRefDatabase() throws Exception {
+		RevCommit base = tr.commit().create();
+		haves.add(base.getId());
+
+		RevCommit newRootCommit = tr.commit().create();
+		tr.branch("refs/heads/unconnected").update(newRootCommit);
+
+		RevCommit newCommit = tr.commit().parent(newRootCommit).create();
+
+		info.setCommands(Collections.singletonList(new ReceiveCommand(
+				ObjectId.zeroId(), newCommit.getId(), "refs/heads/master")));
+		mockNewPackObjects(newCommit, newCommit.getTree());
+
+		runCheckAndAssertCount(5);
+	}
+
+	@Test
+	public void testCheckReachabilityWithBlobInHaves() throws Exception {
+		RevCommit base = tr.commit().create();
+		haves.add(base.getId());
+
+		RevBlob blob = tr.blob("blob content");
+		haves.add(blob.getId());
+
+		RevCommit newCommit = tr.commit().parent(base).create();
+
+		setupSingleReceiveCommand(ObjectId.zeroId(), newCommit.getId());
+		mockNewPackObjects(newCommit, newCommit.getTree());
+
+		runCheckAndAssertCount(4);
+	}
+
+	@Test
+	public void testCheckReachabilityWithAnnotatedTagInHaves()
+			throws Exception {
+		RevCommit base = tr.commit().create();
+
+		RevTag tag = tr.tag("my-tag", base);
+		haves.add(tag.getId());
+
+		RevCommit newCommit = tr.commit().parent(base).create();
+
+		setupSingleReceiveCommand(ObjectId.zeroId(), newCommit.getId());
+		mockNewPackObjects(newCommit, newCommit.getTree());
+
+		runCheckAndAssertCount(5);
+	}
+
+	@Test
+	public void testCheckReachabilityWithBlobInRefs() throws Exception {
+		RevCommit base = tr.commit().create();
+		haves.add(base.getId());
+
+		RevBlob blob = tr.blob("blob content");
+		tr.update("refs/tags/my-blob", blob);
+
+		RevCommit newCommit = tr.commit().parent(base).create();
+
+		setupSingleReceiveCommand(ObjectId.zeroId(), newCommit.getId());
+		mockNewPackObjects(newCommit, newCommit.getTree());
+
+		runCheckAndAssertCount(4);
+	}
+
+	@Test
+	public void testCheckReachabilityWithAnnotatedTagInRefs() throws Exception {
+		RevCommit base = tr.commit().create();
+
+		RevTag tag = tr.tag("my-tag", base);
+		tr.update("refs/tags/my-tag", tag);
+
+		RevCommit newCommit = tr.commit().parent(base).create();
+
+		setupSingleReceiveCommand(ObjectId.zeroId(), newCommit.getId());
+		mockNewPackObjects(newCommit, newCommit.getTree());
+
+		runCheckAndAssertCount(4);
+	}
+
+	@Test
+	public void testSuccessWithDeletion() throws Exception {
+		RevBlob blob = tr.blob("hello");
+		RevCommit base = tr.commit().add("foo", blob).create();
+		haves.add(base.getId());
+
+		// Create a new commit that deletes "foo"
+		RevCommit newCommit = tr.commit().parent(base).rm("foo").create();
+
+		info.setCommands(Collections.singletonList(new ReceiveCommand(
+				base.getId(), newCommit.getId(), "refs/heads/master")));
+
+		mockNewPackObjects(newCommit, newCommit.getTree());
+
+		runCheckAndAssertCount(4);
+	}
+
+	@Test
+	public void testDeleteCommandIgnored() throws Exception {
+		RevCommit base = tr.commit().create();
+		tr.branch("refs/heads/master").update(base);
+
+		ReceiveCommand cmd = new ReceiveCommand(base.getId(), ObjectId.zeroId(),
+				"refs/heads/master", ReceiveCommand.Type.DELETE);
+
+		info.setCommands(Collections.singletonList(cmd));
+
+		runCheckAndAssertCount(0);
+	}
+
+	@Test
+	public void testMultipleCommands() throws Exception {
+		RevCommit base = tr.commit().create();
+		haves.add(base.getId());
+
+		RevBlob blob1 = tr.blob("content1");
+		RevCommit newCommit1 = tr.commit().parent(base).add("foo1", blob1)
+				.create();
+
+		RevBlob blob2 = tr.blob("content2");
+		RevCommit newCommit2 = tr.commit().parent(base).add("foo2", blob2)
+				.create();
+
+		ReceiveCommand cmd1 = new ReceiveCommand(base.getId(),
+				newCommit1.getId(), "refs/heads/branch1");
+		ReceiveCommand cmd2 = new ReceiveCommand(base.getId(),
+				newCommit2.getId(), "refs/heads/branch2");
+
+		info.setCommands(Arrays.asList(cmd1, cmd2));
+
+		mockNewPackObjects(newCommit1, newCommit1.getTree(), blob1, newCommit2,
+				newCommit2.getTree(), blob2);
+
+		runCheckAndAssertCount(7);
+	}
+
+	@Test
+	public void testThinPackSuccess() throws Exception {
+		RevCommit base = tr.commit().create();
+		haves.add(base.getId());
+
+		RevBlob baseBlob = tr.blob("base blob content");
+		haves.add(baseBlob.getId());
+
+		RevCommit newCommit = tr.commit().parent(base).create();
+
+		setupSingleReceiveCommand(base.getId(), newCommit.getId());
+		mockNewPackObjects(newCommit, newCommit.getTree());
+
+		ObjectIdSubclassMap<ObjectId> baseObjectIds = new ObjectIdSubclassMap<>();
+		baseObjectIds.add(baseBlob.getId());
+		when(parser.getBaseObjectIds()).thenReturn(baseObjectIds);
+		info.setCheckObjects(true);
+
+		runCheckAndAssertCount(4);
+	}
+
+	@Test
+	public void testThinPackWithBlobInHaves() throws Exception {
+		RevCommit base = tr.commit().create();
+		haves.add(base.getId());
+
+		RevBlob baseBlob = tr.blob("base blob content");
+
+		RevBlob unrelatedBlob = tr.blob("unrelated blob content");
+		haves.add(unrelatedBlob.getId());
+
+		RevCommit newCommit = tr.commit().parent(base).create();
+
+		setupSingleReceiveCommand(base.getId(), newCommit.getId());
+		mockNewPackObjects(newCommit, newCommit.getTree());
+
+		ObjectIdSubclassMap<ObjectId> baseObjectIds = new ObjectIdSubclassMap<>();
+		baseObjectIds.add(baseBlob.getId());
+		when(parser.getBaseObjectIds()).thenReturn(baseObjectIds);
+		info.setCheckObjects(true);
+
+		runCheckAndAssertCount(4);
+	}
+
+	@Test
+	public void testThinPackWithSignedTagInHaves() throws Exception {
+		RevCommit base = tr.commit().create();
+		haves.add(base.getId());
+
+		RevBlob baseBlob = tr.blob("base blob content");
+
+		RevTag tag = tr.tag("my-tag", base);
+		haves.add(tag.getId());
+
+		RevCommit newCommit = tr.commit().parent(base).create();
+
+		setupSingleReceiveCommand(base.getId(), newCommit.getId());
+		mockNewPackObjects(newCommit, newCommit.getTree());
+
+		ObjectIdSubclassMap<ObjectId> baseObjectIds = new ObjectIdSubclassMap<>();
+		baseObjectIds.add(baseBlob.getId());
+		when(parser.getBaseObjectIds()).thenReturn(baseObjectIds);
+		info.setCheckObjects(true);
+
+		runCheckAndAssertCount(4);
+	}
+
+	@Test
+	public void testThinPackWithBlobInRefs() throws Exception {
+		RevCommit base = tr.commit().create();
+		haves.add(base.getId());
+
+		RevBlob baseBlob = tr.blob("base blob content");
+
+		RevBlob unrelatedBlob = tr.blob("unrelated blob content");
+		tr.update("refs/tags/my-blob", unrelatedBlob);
+
+		RevCommit newCommit = tr.commit().parent(base).create();
+
+		setupSingleReceiveCommand(base.getId(), newCommit.getId());
+		mockNewPackObjects(newCommit, newCommit.getTree());
+
+		ObjectIdSubclassMap<ObjectId> baseObjectIds = new ObjectIdSubclassMap<>();
+		baseObjectIds.add(baseBlob.getId());
+		when(parser.getBaseObjectIds()).thenReturn(baseObjectIds);
+		info.setCheckObjects(true);
+
+		runCheckAndAssertCount(4);
+	}
+
+	@Test
+	public void testThinPackWithAnnotatedTagInRefs() throws Exception {
+		RevCommit base = tr.commit().create();
+		haves.add(base.getId());
+
+		RevBlob baseBlob = tr.blob("base blob content");
+
+		RevTag tag = tr.tag("my-tag", base);
+		tr.update("refs/tags/my-tag", tag);
+
+		RevCommit newCommit = tr.commit().parent(base).create();
+
+		setupSingleReceiveCommand(base.getId(), newCommit.getId());
+		mockNewPackObjects(newCommit, newCommit.getTree());
+
+		ObjectIdSubclassMap<ObjectId> baseObjectIds = new ObjectIdSubclassMap<>();
+		baseObjectIds.add(baseBlob.getId());
+		when(parser.getBaseObjectIds()).thenReturn(baseObjectIds);
+		info.setCheckObjects(true);
+
+		runCheckAndAssertCount(4);
+	}
+
+	@Test
+	public void testMultipleCommandsDifferentParents() throws Exception {
+		RevCommit base1 = tr.commit().create();
+		RevCommit base2 = tr.commit().create();
+		tr.branch("refs/heads/base1").update(base1);
+		tr.branch("refs/heads/base2").update(base2);
+		haves.add(base1.getId());
+		haves.add(base2.getId());
+
+		RevBlob blob1 = tr.blob("content1");
+		RevCommit newCommit1 = tr.commit().parent(base1).add("foo1", blob1)
+				.create();
+
+		RevBlob blob2 = tr.blob("content2");
+		RevCommit newCommit2 = tr.commit().parent(base2).add("foo2", blob2)
+				.create();
+
+		ReceiveCommand cmd1 = new ReceiveCommand(base1.getId(),
+				newCommit1.getId(), "refs/heads/branch1");
+		ReceiveCommand cmd2 = new ReceiveCommand(base2.getId(),
+				newCommit2.getId(), "refs/heads/branch2");
+
+		info.setCommands(Arrays.asList(cmd1, cmd2));
+
+		mockNewPackObjects(newCommit1, newCommit1.getTree(), blob1, newCommit2,
+				newCommit2.getTree(), blob2);
+
+		runCheckAndAssertCount(8);
+	}
+
+	/**
+	 * Test case with a deep and wide tree structure. Modifying a file 5 levels
+	 * deep should only check the trees along that path.
+	 *
+	 * <pre>{@code
+	 * [Existing DB]               [Received Pack]
+	 *      base <------------------- newCommit
+	 *        |                          |
+	 *      root_tree                 root_tree (differs)
+	 *        |                          |
+	 *        +- A                       +- A (differs)
+	 *        |  +- C                    |  +- C (differs)
+	 *        |  |  +- I                 |  |  +- I (differs)
+	 *        |  |  |  +- J              |  |  |  +- J (differs)
+	 *        |  |  |  |  +- K           |  |  |  |  +- K (differs)
+	 *        |  |  |  |  |  +- L        |  |  |  |  |  +- L (differs)
+	 *        |  |  |  |  |  |  +- M     |  |  |  |  |  |  +- M (differs)
+	 *        |  |  |  |  |  |  |  `- 1  |  |  |  |  |  |  |  `- 1 (differs)
+	 *        |  +- D                    |  +- D (shared)
+	 *        |     `- 2                 |     `- 2 (shared)
+	 *        +- B                       +- B (shared)
+	 *           +- E                    |  +- E (shared)
+	 *           |  `- 3                 |     `- 3 (shared)
+	 *           +- F                    |  +- F (shared)
+	 *           |  `- 4                 |     `- 4 (shared)
+	 *           +- G                    |  +- G (shared)
+	 *           |  `- 5                 |     `- 5 (shared)
+	 *           +- H                    |  +- H (shared)
+	 *              `- 6                 |     `- 6 (shared)
+	 * }</pre>
+	 */
+	@Test
+	public void testDeepTreeSuccess() throws Exception {
+		// Create base with deep and wide structure
+		TestRepository.CommitBuilder cb = tr.commit();
+		cb.add("A/C/I/J/K/L/M/1", tr.blob("content1"));
+		cb.add("A/D/2", tr.blob("content2"));
+		cb.add("B/E/3", tr.blob("content3"));
+		cb.add("B/F/4", tr.blob("content4"));
+		cb.add("B/G/5", tr.blob("content5"));
+		cb.add("B/H/6", tr.blob("content6"));
+		RevCommit base = cb.create();
+		haves.add(base.getId());
+
+		RevCommit currentHaves = base;
+		for (int i = 0; i < 250; i++) {
+			currentHaves = tr.commit().parent(currentHaves).create();
+			haves.add(currentHaves.getId());
+		}
+
+		// Create new commit modifying file at end of deep path
+		RevBlob newBlob = tr.blob("new content");
+		RevCommit newCommit = tr.commit().parent(base)
+				.add("A/C/I/J/K/L/M/000", newBlob).create();
+
+		info.setCommands(Collections.singletonList(new ReceiveCommand(
+				base.getId(), newCommit.getId(), "refs/heads/master")));
+
+		List<ObjectId> allNewObjects = new ArrayList<>();
+		allNewObjects.add(newCommit);
+		allNewObjects.add(newCommit.getTree());
+		allNewObjects.add(newBlob);
+		try (TreeWalk tw = new TreeWalk(tr.getRepository())) {
+			tw.setRecursive(false);
+			tw.addTree(newCommit.getTree());
+			String[] pathSegments = { "A", "C", "I", "J", "K", "L", "M" };
+			for (String segment : pathSegments) {
+				while (tw.next()) {
+					if (tw.getNameString().equals(segment)) {
+						allNewObjects.add(tw.getObjectId(0));
+						tw.enterSubtree();
+						break;
+					}
+				}
+			}
+		}
+		mockNewPackObjects(allNewObjects);
+
+		runCheckAndAssertCount(18);
+	}
+
+	/**
+	 * Compare the efficiency of the TreeWalk checker vs. iterative vs. full
+	 * checkers. Initial JFR results on this test:
+	 * <ul>
+	 * <li>TreeWalk Checker: 22 checked objects, 25 JFR allocations</li>
+	 * <li>Iterative Checker: 14 checked objects, 41 JFR allocations</li>
+	 * <li>Full Checker: 264 checked objects, 147 JFR allocations</li>
+	 * </ul>
+	 *
+	 * <pre>{@code
+	 * [Existing DB]               [Received Pack]
+	 *      base <------------------- newCommit
+	 *        |                          |
+	 *      root_tree                 root_tree (differs)
+	 *        |                          |
+	 *        +- A                       +- A (differs)
+	 *        |  +- C                    |  +- C (differs)
+	 *        |  |  +- I                 |  |  +- I (differs)
+	 *        |  |  |  +- J              |  |  |  +- J (differs)
+	 *        |  |  |  |  +- K           |  |  |  |  +- K (differs)
+	 *        |  |  |  |  |  +- L        |  |  |  |  |  +- L (differs)
+	 *        |  |  |  |  |  |  +- M     |  |  |  |  |  |  +- M (differs)
+	 *        |  |  |  |  |  |  |  `- 1  |  |  |  |  |  |  |  `- 1 (differs)
+	 *        |  +- D                    |  +- D (shared)
+	 *        |     `- 2                 |     `- 2 (shared)
+	 *        +- B                       +- B (differs)
+	 *           +- E                    |  +- E (shared)
+	 *           |  `- 3                 |     `- 3 (shared)
+	 *           +- F                    |  +- F (shared)
+	 *           |  `- 4                 |     `- 4 (shared)
+	 *           +- G                    |  +- G (shared)
+	 *           |  `- 5                 |     `- 5 (shared)
+	 *           +- H                    |  +- H (differs)
+	 *              `- 6                 |     `- 6 (differs)
+	 * }</pre>
+	 */
+	@Test
+	public void testDeepTreePerformance() throws Exception {
+		// Create base with deep and wide structure
+		TestRepository.CommitBuilder cb = tr.commit();
+		cb.add("A/C/I/J/K/L/M/1", tr.blob("content1"));
+		cb.add("A/D/2", tr.blob("content2"));
+		cb.add("B/E/3", tr.blob("content3"));
+		cb.add("B/F/4", tr.blob("content4"));
+		cb.add("B/G/5", tr.blob("content5"));
+		cb.add("B/H/6", tr.blob("content6"));
+
+		RevCommit base = cb.create();
+		haves.add(base.getId());
+		RevCommit currentHaves = base;
+		for (int i = 0; i < 250; i++) {
+			currentHaves = tr.commit().parent(currentHaves).create();
+			haves.add(currentHaves.getId());
+		}
+
+		// Create new commit modifying file at end of deep path
+		RevBlob newBlob = tr.blob("new content");
+		RevCommit newCommit = tr.commit().parent(base)
+				.add("A/C/I/J/K/L/M/1", newBlob).add("B/H/6", newBlob).create();
+
+		info.setCommands(Collections.singletonList(new ReceiveCommand(
+				base.getId(), newCommit.getId(), "refs/heads/new_change")));
+
+		ObjectIdSubclassMap<ObjectId> newObjectIds = new ObjectIdSubclassMap<>();
+		newObjectIds.add(newCommit);
+		newObjectIds.add(newCommit.getTree());
+		newObjectIds.add(newBlob);
+		try (TreeWalk tw = new TreeWalk(tr.getRepository())) {
+			tw.setRecursive(false);
+			tw.addTree(newCommit.getTree());
+			String[] pathSegments = { "A", "C", "I", "J", "K", "L", "M" };
+			for (String segment : pathSegments) {
+				while (tw.next()) {
+					if (tw.getNameString().equals(segment)) {
+						newObjectIds.add(tw.getObjectId(0));
+						tw.enterSubtree();
+						break;
+					}
+				}
+			}
+		}
+		try (TreeWalk tw = new TreeWalk(tr.getRepository())) {
+			tw.setRecursive(false);
+			tw.addTree(newCommit.getTree());
+			while (tw.next()) {
+				if (tw.getNameString().equals("B")) {
+					newObjectIds.add(tw.getObjectId(0));
+					tw.enterSubtree();
+					while (tw.next()) {
+						if (tw.getNameString().equals("H")) {
+							newObjectIds.add(tw.getObjectId(0));
+							break;
+						}
+					}
+					break;
+				}
+			}
+		}
+		when(parser.getNewObjectIds()).thenReturn(newObjectIds);
+
+		TreeWalkConnectivityChecker scChecker = new TreeWalkConnectivityChecker();
+
+		long scJfrCount = 0;
+		try (Recording r = new Recording()) {
+			r.enable("jdk.ObjectAllocationInNewTLAB");
+			r.enable("jdk.ObjectAllocationOutsideTLAB");
+			r.start();
+
+			for (int i = 0; i < 1000; i++) {
+				try (RevWalk rw = new RevWalk(info.getRepository())) {
+					info.setWalk(rw);
+					pm.reset();
+					scChecker.checkConnectivity(info, haves, pm);
+				}
+			}
+
+			r.stop();
+			Path p = Files.createTempFile("sc_jfr", ".jfr");
+			r.dump(p);
+			try (RecordingFile file = new RecordingFile(p)) {
+				while (file.hasMoreEvents()) {
+					file.readEvent();
+					scJfrCount++;
+				}
+			}
+			Files.delete(p);
+		}
+		long scCount = pm.getObjectsCheckedCount();
+
+		// Run IterativeConnectivityChecker
+		IterativeConnectivityChecker icChecker = new IterativeConnectivityChecker(
+				new FullConnectivityChecker());
+
+		long icJfrCount = 0;
+		try (jdk.jfr.Recording r = new jdk.jfr.Recording()) {
+			r.enable("jdk.ObjectAllocationInNewTLAB");
+			r.enable("jdk.ObjectAllocationOutsideTLAB");
+			r.start();
+
+			for (int i = 0; i < 1000; i++) {
+				try (RevWalk rw = new RevWalk(info.getRepository())) {
+					info.setWalk(rw);
+					pm.reset();
+					icChecker.checkConnectivity(info, haves, pm);
+				}
+			}
+
+			r.stop();
+			Path p = Files.createTempFile("ic_jfr_deep", ".jfr");
+			r.dump(p);
+			try (jdk.jfr.consumer.RecordingFile file = new jdk.jfr.consumer.RecordingFile(
+					p)) {
+				while (file.hasMoreEvents()) {
+					jdk.jfr.consumer.RecordedEvent event = file.readEvent();
+					if (event.getEventType().getName()
+							.startsWith("jdk.ObjectAllocation")) {
+						icJfrCount++;
+					}
+				}
+			}
+			Files.delete(p);
+		}
+		long icCount = pm.getObjectsCheckedCount();
+
+		// Run FullConnectivityChecker
+		FullConnectivityChecker fcChecker = new FullConnectivityChecker();
+
+		long fcJfrCount = 0;
+		try (Recording r = new Recording()) {
+			r.enable("jdk.ObjectAllocationInNewTLAB");
+			r.enable("jdk.ObjectAllocationOutsideTLAB");
+			r.start();
+
+			for (int i = 0; i < 1000; i++) {
+				try (RevWalk rw = new RevWalk(info.getRepository())) {
+					info.setWalk(rw);
+					pm.reset();
+					fcChecker.checkConnectivity(info, haves, pm);
+				}
+			}
+
+			r.stop();
+			Path p = Files.createTempFile("fc_jfr", ".jfr");
+			r.dump(p);
+			try (RecordingFile file = new RecordingFile(p)) {
+				while (file.hasMoreEvents()) {
+					file.readEvent();
+					fcJfrCount++;
+				}
+			}
+			Files.delete(p);
+		}
+		long fcCount = pm.getObjectsCheckedCount();
+
+		System.out.println("TreeWalk Checked Objects: " + scCount);
+		System.out.println("TreeWalk JFR allocations: " + scJfrCount);
+		System.out.println("Iterative Checked Objects: " + icCount);
+		System.out.println("Iterative JFR allocations: " + icJfrCount);
+		System.out.println("Full Checked Objects: " + fcCount);
+		System.out.println("Full JFR allocations: " + fcJfrCount);
+
+		assertEquals(22, scCount);
+		assertEquals(14, icCount);
+		assertEquals(264, fcCount);
+
+		assertTrue(
+				"TreeWalkConnectivityChecker should produce fewer JFR allocation events. Expected "
+						+ scJfrCount + " < " + fcJfrCount,
+				scJfrCount < fcJfrCount);
+	}
+
+	private void setupSingleReceiveCommand(ObjectId oldId, ObjectId newId) {
+		info.setCommands(Collections.singletonList(
+				new ReceiveCommand(oldId, newId, "refs/heads/master")));
+	}
+
+	private void mockNewPackObjects(ObjectId... ids) {
+		mockNewPackObjects(Arrays.asList(ids));
+	}
+
+	private void mockNewPackObjects(Collection<? extends ObjectId> ids) {
+		ObjectIdSubclassMap<ObjectId> map = new ObjectIdSubclassMap<>();
+		for (ObjectId id : ids) {
+			map.add(id);
+		}
+		when(parser.getNewObjectIds()).thenReturn(map);
+	}
+
+	private void runCheckAndAssertCount(int expectedCount) throws IOException {
+		checker.checkConnectivity(info, haves, pm);
+		assertEquals(expectedCount, pm.getObjectsCheckedCount());
+	}
+
+	private void runCheckAndExpectMissingObject(ObjectId expectedMissingId,
+			int expectedCount) throws IOException {
+		try {
+			checker.checkConnectivity(info, haves, pm);
+			fail("Expected MissingObjectException");
+		} catch (MissingObjectException e) {
+			assertEquals(expectedMissingId, e.getObjectId());
+			assertEquals(expectedCount, pm.getObjectsCheckedCount());
+		}
+	}
+
+	private RevCommit createCommitWithParent(ObjectId parentId)
+			throws Exception {
+		CommitBuilder cb = new CommitBuilder();
+		cb.setTreeId(tr.tree().getId());
+		cb.setParentId(parentId);
+		cb.setAuthor(new PersonIdent("Author", "author@example.com",
+				tr.getInstant(), tr.getTimeZoneId()));
+		cb.setCommitter(new PersonIdent("Committer", "committer@example.com",
+				tr.getInstant(), tr.getTimeZoneId()));
+		cb.setMessage("Commit with specific parent");
+
+		try (ObjectInserter ins = tr.getRepository().newObjectInserter()) {
+			ObjectId id = ins.insert(cb);
+			ins.flush();
+			return tr.getRevWalk().parseCommit(id);
+		}
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java
index 21fde3e..2cdca73 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushConnectionTest.java
@@ -14,6 +14,7 @@
 import static org.eclipse.jgit.transport.BasePackPushConnection.CAPABILITY_SIDE_BAND_64K;
 import static org.eclipse.jgit.transport.RemoteRefUpdate.Status.REJECTED_OTHER_REASON;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import java.io.IOException;
@@ -23,7 +24,9 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Random;
 
+import org.eclipse.jgit.errors.TooLargePackException;
 import org.eclipse.jgit.errors.TransportException;
 import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
 import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
@@ -50,6 +53,9 @@ public class PushConnectionTest {
 	private ObjectId obj3;
 	private String refName = "refs/tags/blob";
 
+	private long maxPackSize = 0; // the maximum pack file size used by the
+									// server (0 means no limit)
+
 	@Before
 	public void setUp() throws Exception {
 		server = newRepo("server");
@@ -57,6 +63,9 @@ public void setUp() throws Exception {
 		processedRefs = new ArrayList<>();
 		testProtocol = new TestProtocol<>(null, (Object req, Repository db) -> {
 			ReceivePack rp = new ReceivePack(db);
+			if (maxPackSize > 0) {
+				rp.setMaxPackSizeLimit(maxPackSize);
+			}
 			rp.setPreReceiveHook((ReceivePack receivePack,
 					Collection<ReceiveCommand> cmds) -> {
 				for (ReceiveCommand cmd : cmds) {
@@ -170,6 +179,46 @@ public void limitCommandBytes() throws IOException {
 	}
 
 	@Test
+	public void limitPackSize() throws IOException {
+		// this maxPackSize leads to an unPackError
+		maxPackSize = 1;
+
+		try (ObjectInserter ins = client.newObjectInserter()) {
+			// 1024 * 5 means five times the server side buffer size. We need data several
+			// times bigger the server side buffer size. This is necessary in order to cause
+			// the server buffer overflow when the client transmits data. This is necessary
+			// in order to enable the "JGit-Receive-Pack" thread to receive and begin
+			// processing data before the client is able to transfer all the data. When
+			// processing the first bytes of data, the server will detect that an error has
+			// occurred, write an error message and close the pipe. Then the client, when
+			// trying to write the remaining bytes, will receive a “Pipe closed” exception,
+			// which is what we need. The client must then check the error message from the
+			// server and throw an appropriate exception corresponding to that error message
+			// from the server.
+			byte[] arr = new byte[1024 * 5];
+			new Random(1).nextBytes(arr);
+			obj2 = ins.insert(Constants.OBJ_BLOB, arr);
+			ins.flush();
+		}
+
+		Map<String, RemoteRefUpdate> updates = new HashMap<>();
+		RemoteRefUpdate rru = new RemoteRefUpdate(
+				null, null, obj2, "refs/test/limitPackSize",
+				false, null, ObjectId.zeroId());
+		updates.put(rru.getRemoteName(), rru);
+
+		try (Transport tn = testProtocol.open(uri, client, "server");
+				 PushConnection connection = tn.openPush()) {
+			try {
+				connection.push(NullProgressMonitor.INSTANCE, updates);
+				fail("server did not abort");
+			} catch (Exception e) {
+				assertTrue(e instanceof TooLargePackException);
+			}
+		}
+	}
+
+	@Test
 	public void commandOrder() throws Exception {
 		List<RemoteRefUpdate> updates = new ArrayList<>();
 		try (TestRepository<?> tr = new TestRepository<>(client)) {
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
index 5dedccd..dca75e2 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -117,6 +117,7 @@
 cannotMoveIndexTo=Cannot move index to {0}
 cannotMovePackTo=Cannot move pack to {0}
 cannotOpenService=cannot open {0}
+cannotOpenMidx=Cannot open midx at {0}: {1}
 cannotParseDate=The date specification "{0}" could not be parsed with the following formats: {1}
 cannotParseGitURIish=Cannot parse Git URI-ish
 cannotPullOnARepoWithState=Cannot pull into a repository with state: {0}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
index 58b4d3d..12ba893 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
@@ -44,7 +44,7 @@
 /**
  * Repo XML manifest parser.
  *
- * @see <a href="https://code.google.com/p/git-repo/">git-repo project page</a>
+ * @see <a href="https://gerrit.googlesource.com/git-repo/">git-repo project page</a>
  * @since 4.0
  */
 public class ManifestParser extends DefaultHandler {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
index be77fca..392ca92 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
@@ -58,7 +58,7 @@
  * work in git submodule, so we'll skip all the sub projects
  * (&quot;foo/bar&quot; in the example) while converting.
  *
- * @see <a href="https://code.google.com/p/git-repo/">git-repo project page</a>
+ * @see <a href="https://gerrit.googlesource.com/git-repo/">git-repo project page</a>
  * @since 3.4
  */
 public class RepoCommand extends GitCommand<RevCommit> {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
index 2630da3..07eb12d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
@@ -27,7 +27,7 @@
 /**
  * The representation of a repo sub project.
  *
- * @see <a href="https://code.google.com/p/git-repo/">git-repo project page</a>
+ * @see <a href="https://gerrit.googlesource.com/git-repo/">git-repo project page</a>
  * @since 4.0
  */
 public class RepoProject implements Comparable<RepoProject> {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index db4a4e2..4251f4c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -147,6 +147,7 @@ public static JGitText get() {
 	/***/ public String cannotMoveIndexTo;
 	/***/ public String cannotMovePackTo;
 	/***/ public String cannotOpenService;
+    /***/ public String cannotOpenMidx;
 	/***/ public String cannotParseDate;
 	/***/ public String cannotParseGitURIish;
 	/***/ public String cannotPullOnARepoWithState;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriter.java
index 6ead06d..32b4d14 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsMidxWriter.java
@@ -77,6 +77,13 @@ public static DfsPackDescription writeMidx(ProgressMonitor pm,
 		PackIndexMerger.Builder dataBuilder = PackIndexMerger.builder();
 		try (DfsReader ctx = objdb.newReader()) {
 			for (DfsPackFile pack : packs) {
+				if (pack instanceof DfsPackFileMidx) {
+					// asObjectsToPack assumes one packid per pack while
+					// calculating midx offsets. We need to fix that before
+					// accepting midx to build new midx.
+					throw new IOException(
+							"MIDX not supported to build new midx"); //$NON-NLS-1$
+				}
 				dataBuilder.addPack(pack.getPackDescription().getPackName(),
 						pack.getPackIndex(ctx));
 			}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java
index fc6596e..3f457f2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java
@@ -677,7 +677,7 @@ private PackList scanPacksImpl(PackList old) throws IOException {
 	 *            pack description
 	 * @return the dfs packfile
 	 */
-	protected DfsPackFile createDfsPackFile(DfsBlockCache cache,
+	public DfsPackFile createDfsPackFile(DfsBlockCache cache,
 			DfsPackDescription dsc) {
 		return new DfsPackFile(cache, dsc);
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java
index 8860cce..fbe641e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java
@@ -26,6 +26,7 @@
 import java.util.List;
 import java.util.Set;
 
+import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.internal.storage.file.PackIndex;
@@ -79,6 +80,62 @@ public class DfsPackCompactor {
 	private RevFlag isBase;
 
 	/**
+	 * Hook invoked after the compact calculation is done, but before committing
+	 * the resulting packs.
+	 * <p>
+	 * The hook implementations must not modify the incoming collections.
+	 * Instead, they should return any extra packs to commit or remove in a
+	 * {@link Packs} record, which the caller will combine with the calculated
+	 * results.
+	 */
+	public interface PreCommitHook {
+		/**
+		 * Extra packs to commit and remove as result of the hook execution.
+		 *
+		 * @param toCommit
+		 *            packs that this hook wants to add to the compactor
+		 *            transaction
+		 * @param toRemove
+		 *            packs that this hook wants to remove in the compactor
+		 *            transaction
+		 */
+		record Packs(List<DfsPackDescription> toCommit,
+				List<DfsPackDescription> toRemove) {
+		}
+
+		/**
+		 * Apply the hook.
+		 *
+		 * @param newPacks
+		 *            new packs created by this compaction. Read only.
+		 * @param removedPacks
+		 *            packs that are being replaced by this compaction. Read
+		 *            only.
+		 * @return Packs containing extra packs to commit and remove, or null if
+		 *         none.
+		 * @throws IOException
+		 *             an error occurred in the hook.
+		 */
+		@Nullable
+		Packs apply(List<DfsPackDescription> newPacks,
+				Set<DfsPackDescription> removedPacks) throws IOException;
+	}
+
+	private PreCommitHook preCommitHook;
+
+	/**
+	 * Set the pre-commit hook.
+	 *
+	 * @param hook
+	 *            pre-commit hook.
+	 * @return {@code this}
+	 */
+	public DfsPackCompactor setPreCommitHook(PreCommitHook hook) {
+		this.preCommitHook = hook;
+		return this;
+	}
+
+	/**
 	 * Initialize a pack compactor.
 	 *
 	 * @param repository
@@ -196,8 +253,15 @@ public void compact(ProgressMonitor pm) throws IOException {
 			}
 			compactPacks(ctx, pm);
 
-			List<DfsPackDescription> commit = getNewPacks();
-			Collection<DfsPackDescription> remove = toPrune();
+			List<DfsPackDescription> commit = new ArrayList<>(getNewPacks());
+			Set<DfsPackDescription> remove = toPrune();
+			if (preCommitHook != null) {
+				PreCommitHook.Packs extra = preCommitHook.apply(commit, remove);
+				if (extra != null) {
+					commit.addAll(extra.toCommit());
+					remove.addAll(extra.toRemove());
+				}
+			}
 			if (!commit.isEmpty() || !remove.isEmpty()) {
 				objdb.commitPack(commit, remove);
 			}
@@ -318,7 +382,7 @@ public List<PackStatistics> getNewPackStatistics() {
 				: Collections.emptyList();
 	}
 
-	private Collection<DfsPackDescription> toPrune() {
+	private Set<DfsPackDescription> toPrune() {
 		Set<DfsPackDescription> packs = new HashSet<>();
 		for (DfsPackFile pack : srcPacks) {
 			packs.add(pack.getPackDescription());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidx.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidx.java
index 50ae998..402bb24 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidx.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackFileMidx.java
@@ -90,9 +90,10 @@ protected DfsPackFileMidx(DfsBlockCache cache, DfsPackDescription desc) {
 	public abstract DfsPackFileMidx getMultipackIndexBase();
 
 	/**
-	 * Packs indexed by this multipack index (base NOT included)
+	 * Packs indexed by this multipack index (base NOT included) in midx order.
 	 *
-	 * @return packs indexed by this multipack index
+	 * @return packs indexed by this multipack index in the order used inside
+	 *         the midx.
 	 */
 	public abstract List<DfsPackFile> getCoveredPacks();
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/MidxPackList.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/MidxPackList.java
index f485725..70c9b85 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/MidxPackList.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/MidxPackList.java
@@ -41,18 +41,23 @@ public final class MidxPackList {
 	 *            list of packs (regular or tip midxs)
 	 * @return a MidxPackList instance
 	 */
-	public static MidxPackList create(DfsPackFile[] packs) {
-		return new MidxPackList(packs);
+	public static MidxPackList create(DfsPackFile... packs) {
+		return new MidxPackList(Arrays.asList(packs));
 	}
 
 	private final List<DfsPackFile> packs;
 
-	private MidxPackList(DfsPackFile[] packs) {
-		this.packs = Arrays.asList(packs);
+	private MidxPackList(List<DfsPackFile> packs) {
+		this.packs = packs;
 	}
 
 	/**
 	 * Get all plain packs in the list, either top-level or inside midxs
+	 * <p>
+	 * Inside midx, the packs are in reverse lookup order. This code restores
+	 * their original order. i.e. the list with packs [INSERT, midx(COMPACT-2,
+	 * COMPACT-3), midx(GC, COMPACT-1)] becomes [INSERT, COMPACT-3, COMPACT-2,
+	 * COMPACT-1, GC].
 	 *
 	 * @return a list of all "real" packs in this pack list, either top level or
 	 *         inside midxs.
@@ -63,7 +68,11 @@ public List<DfsPackFile> getAllPlainPacks() {
 		while (!pending.isEmpty()) {
 			DfsPackFile pack = pending.poll();
 			if (pack instanceof DfsPackFileMidx midxPack) {
-				plainPacks.addAll(midxPack.getCoveredPacks());
+				// Midx order is the reverse of object lookup order
+				ArrayList<DfsPackFile> coveredPacks = new ArrayList<>(
+						midxPack.getCoveredPacks());
+				Collections.reverse(coveredPacks);
+				plainPacks.addAll(coveredPacks);
 				if (midxPack.getMultipackIndexBase() != null) {
 					pending.add(midxPack.getMultipackIndexBase());
 				}
@@ -104,8 +113,8 @@ public List<DfsPackFileMidx> getAllMidxPacks() {
 	 *            a single pack
 	 * @return all the midxs that include (directly or indirectly) the pack
 	 */
-	Set<DfsPackFileMidx> findAllCoveringMidxs(DfsPackFile pack) {
-		return findAllCoveringMidxs(List.of(pack));
+	Set<DfsPackFileMidx> findAllCoveringMidxs(DfsPackFile... pack) {
+		return findAllCoveringMidxs(Arrays.asList(pack));
 	}
 
 	/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/MidxWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/MidxWriter.java
index 91f60b6..8143bbb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/MidxWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/MidxWriter.java
@@ -9,16 +9,40 @@
  */
 package org.eclipse.jgit.internal.storage.file;
 
+import static org.eclipse.jgit.internal.storage.pack.PackExt.BITMAP_INDEX;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
 
+import org.eclipse.jgit.internal.revwalk.RefAdvancerWalk;
+import org.eclipse.jgit.internal.storage.midx.MidxMetadataReader;
+import org.eclipse.jgit.internal.storage.midx.MultiPackIndex;
 import org.eclipse.jgit.internal.storage.midx.MultiPackIndexWriter;
 import org.eclipse.jgit.internal.storage.midx.PackIndexMerger;
+import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
+import org.eclipse.jgit.internal.storage.pack.PackBitmapCalculator;
+import org.eclipse.jgit.internal.storage.pack.PackBitmapIndexWriter;
 import org.eclipse.jgit.internal.storage.pack.PackExt;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdOwnerMap;
 import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.storage.pack.PackConfig;
+import org.eclipse.jgit.util.Base64;
+import org.eclipse.jgit.util.FileUtils;
 
 /**
  * Helper to write multipack indexes.
@@ -26,36 +50,179 @@
 public class MidxWriter {
 
 	/**
+	 * Do not build a midx if there are less than this amount of packs to cover.
+	 */
+	private static final int MIN_PACKS_FOR_MIDX = 2;
+
+	/**
 	 * Write a mdix over the packs
 	 *
 	 * @param pm
 	 *            a progress monitor
+	 * @param repo
+	 *            the repository
 	 * @param packs
 	 *            packs to cover with the midx
 	 * @param midxOut
 	 *            file to write the resulting midx
+	 * @param packConfig
+	 *            config for the bitmap writing. Null to skip writing bitmaps.
 	 * @throws IOException
 	 *             an error reading any of the input packs or indexes
 	 */
-	public static void writeMidx(ProgressMonitor pm, Collection<Pack> packs,
-			File midxOut) throws IOException {
+	public static void writeMidx(ProgressMonitor pm, Repository repo,
+			Collection<Pack> packs, File midxOut, PackConfig packConfig)
+			throws IOException {
+
+		Collection<Pack> packList = flattenMidxPackList(packs).stream()
+				.sorted(Comparator.comparing(Pack::getPackName)).toList();
+		if (packList.size() < MIN_PACKS_FOR_MIDX) {
+			return;
+		}
 		PackIndexMerger.Builder builder = PackIndexMerger.builder();
 		builder.setProgressMonitor(pm);
-
-		Collection<Pack> packList = packs.stream()
-				.sorted(Comparator.comparing(Pack::getPackName)).toList();
-		pm.beginTask("Adding packs to midx", packList.size());
+		pm.beginTask("Adding packs to midx", packList.size()); //$NON-NLS-1$
 		for (Pack pack : packList) {
+			if (pack instanceof PackMidx) {
+				throw new IllegalArgumentException(
+						"Building midx from other midx not supported yet");
+			}
 			PackFile packFile = pack.getPackFile().create(PackExt.INDEX);
 			builder.addPack(packFile.getName(), pack.getIndex());
+
+			pm.update(1);
+		}
+		PackIndexMerger data = builder.build();
+		pm.endTask();
+
+		File oldMidxBitmaps = null;
+		if (midxOut.exists()) {
+			MidxMetadataReader.MidxMetadata midxMetadata = MidxMetadataReader
+					.read(midxOut);
+			byte[] checksum = midxMetadata.checksum();
+			String midxBitmapsPath = midxOut.getAbsoluteFile() + "-" //$NON-NLS-1$
+					+ ObjectId.fromRaw(checksum).name() + "." //$NON-NLS-1$
+					+ BITMAP_INDEX.getExtension();
+			File previousBitmaps = new File(midxBitmapsPath);
+			if (previousBitmaps.exists()) {
+				oldMidxBitmaps = previousBitmaps;
+			}
+		}
+
+		String midxFilename = midxOut.getAbsolutePath();
+		File midxOutTmp = new File(
+				midxFilename + BITMAP_INDEX.getTmpExtension());
+		MultiPackIndexWriter writer = new MultiPackIndexWriter();
+		MultiPackIndexWriter.Result result;
+		try (FileOutputStream out = new FileOutputStream(
+				midxOutTmp.getAbsolutePath())) {
+			result = writer.write(pm, out, data);
+		}
+
+		File midxOutBitmaps = new File(midxOut.getAbsoluteFile() + "-" //$NON-NLS-1$
+				+ ObjectId.fromRaw(Base64.decode(result.checksum())).name()
+				+ "." + BITMAP_INDEX.getExtension());
+		File midxOutBitmapsTmp = null;
+		if (packConfig != null) {
+			midxOutBitmapsTmp = new File(midxOut.getAbsolutePath() + "-" //$NON-NLS-1$
+					+ ObjectId.fromRaw(Base64.decode(result.checksum())).name()
+					+ BITMAP_INDEX.getTmpExtension());
+			createAndAttachBitmaps(pm, repo, midxOutBitmapsTmp,
+					Base64.decode(result.checksum()), data, packList,
+					new PackConfig(repo));
+		}
+
+		FileUtils.rename(midxOutTmp.getAbsoluteFile(),
+				midxOut.getAbsoluteFile(), StandardCopyOption.ATOMIC_MOVE);
+		if (midxOutBitmapsTmp != null) {
+			FileUtils.rename(midxOutBitmapsTmp.getAbsoluteFile(),
+					midxOutBitmaps.getAbsoluteFile(),
+					StandardCopyOption.ATOMIC_MOVE);
+		}
+
+		if (oldMidxBitmaps != null && !oldMidxBitmaps.equals(midxOutBitmaps)) {
+			FileUtils.delete(oldMidxBitmaps);
+		}
+	}
+
+	private static void createAndAttachBitmaps(ProgressMonitor pm,
+			Repository repo, File midxBitmapsOut, byte[] checksum,
+			PackIndexMerger data, Collection<Pack> packs, PackConfig cfg)
+			throws IOException {
+
+		// TODO(ifrade): Verify we duplicate the behaviour about tags of regular
+		// bitmapping
+		List<ObjectId> allHeads = repo.getRefDatabase()
+				.getRefsByPrefix(Constants.R_HEADS).stream()
+				.map(r -> r.getObjectId()).filter(Objects::nonNull).toList();
+		if (allHeads.isEmpty()) {
+			return;
+		}
+
+		ObjectIdOwnerMap<ObjectToPack> byId = new ObjectIdOwnerMap<>();
+		List<ObjectToPack> otps = asObjectsToPack(pm,
+				(WindowCursor) repo.newObjectReader(), data,
+				new ArrayList<>(packs), byId);
+
+		RefAdvancerWalk adv = new RefAdvancerWalk(repo, c -> byId.contains(c));
+		Set<RevCommit> inPack = adv.advance(allHeads);
+
+		PackBitmapIndexBuilder writeBitmaps = new PackBitmapIndexBuilder(otps);
+		int commitCount = writeBitmaps.getCommits().cardinality();
+
+		PackBitmapCalculator calculator = new PackBitmapCalculator(cfg);
+		// This will do ctx.getBitmapIndex() to reuse/copy previous bitmaps
+		calculator.calculate(repo.newObjectReader(),
+				NullProgressMonitor.INSTANCE, commitCount, inPack,
+				new HashSet<>(), writeBitmaps);
+		try (FileOutputStream out = new FileOutputStream(
+				midxBitmapsOut.getAbsolutePath())) {
+			PackBitmapIndexWriter pbiWriter = new PackBitmapIndexWriterV1(out);
+			pbiWriter.write(writeBitmaps, checksum);
+		}
+	}
+
+	private static List<ObjectToPack> asObjectsToPack(ProgressMonitor pm,
+			WindowCursor ctx, PackIndexMerger data, List<Pack> packs,
+			ObjectIdOwnerMap<ObjectToPack> byId) throws IOException {
+		long[] accPackSize = new long[packs.size()];
+		for (int i = 1; i < packs.size(); i++) {
+			long prevValue = accPackSize[i - 1];
+			accPackSize[i] = prevValue
+					+ packs.get(i - 1).getPackFile().length();
+		}
+
+		pm.beginTask("Converting midx to ObjectsToPack", //$NON-NLS-1$
+				data.getUniqueObjectCount());
+		List<ObjectToPack> result = new ArrayList<>(
+				data.getUniqueObjectCount());
+		MultiPackIndex.MidxIterator it = data.bySha1Iterator();
+		while (it.hasNext()) {
+			MultiPackIndex.MutableEntry entry = it.next();
+			int objectType = packs.get(entry.getPackId()).getObjectType(ctx,
+					entry.getOffset());
+			ObjectToPack o = new ObjectToPack(entry.getObjectId().toObjectId(),
+					objectType);
+			o.setOffset(accPackSize[entry.getPackId()] + entry.getOffset());
+			result.add(o);
+			byId.add(o);
 			pm.update(1);
 		}
 		pm.endTask();
+		return result;
+	}
 
-		MultiPackIndexWriter writer = new MultiPackIndexWriter();
-		try (FileOutputStream out = new FileOutputStream(
-				midxOut.getAbsolutePath())) {
-			writer.write(pm, out, builder.build());
+	static List<Pack> flattenMidxPackList(Collection<Pack> packs) {
+		List<Pack> output = new ArrayList<>();
+		for (Pack p : packs) {
+			List<Pack> coveredPacks = new ArrayList<>(p.getCoveredPacks());
+			if (coveredPacks.isEmpty()) {
+				output.add(p);
+			} else {
+				Collections.reverse(coveredPacks);
+				output.addAll(coveredPacks);
+			}
 		}
+		return Collections.unmodifiableList(output);
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java
index 8988b41..4e299e6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/Pack.java
@@ -14,10 +14,10 @@
 
 import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX;
 import static org.eclipse.jgit.internal.storage.pack.PackExt.KEEP;
+import static org.eclipse.jgit.internal.storage.pack.PackExt.OBJECT_SIZE_INDEX;
 import static org.eclipse.jgit.internal.storage.pack.PackExt.REVERSE_INDEX;
 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_CORE_SECTION;
 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PACKED_INDEX_GIT_USE_STRONGREFS;
-import static org.eclipse.jgit.internal.storage.pack.PackExt.OBJECT_SIZE_INDEX;
 
 import java.io.EOFException;
 import java.io.File;
@@ -36,6 +36,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -61,6 +62,7 @@
 import org.eclipse.jgit.internal.util.Optionally;
 import org.eclipse.jgit.lib.AbbreviatedObjectId;
 import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.BitmapIndex;
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
@@ -169,6 +171,28 @@ public Pack(Config cfg, File packFile, @Nullable PackFile bitmapIdxFile) {
 		length = Long.MAX_VALUE;
 	}
 
+	/**
+	 * Set the checksum of this pack
+	 *
+	 * @param checksum
+	 *            the checksum
+	 */
+	protected void setPackChecksum(byte[] checksum) {
+		this.packChecksum = checksum;
+	}
+
+	/**
+	 * Packs covered by this pack
+	 * <p>
+	 * For regular packs, this list is empty. For midx packs, this list has the
+	 * names of packs indexed by the midx.
+	 *
+	 * @return list of packs covered by this pack.
+	 */
+	protected List<Pack> getCoveredPacks() {
+		return Collections.emptyList();
+	}
+
 	private PackIndex idx() throws IOException {
 		Optional<PackIndex> optional = loadedIdx.getOptional();
 		if (optional.isPresent()) {
@@ -198,10 +222,9 @@ private synchronized PackIndex memoizeIdxIfNeeded() throws IOException {
 						Long.valueOf(System.currentTimeMillis()
 								- start)));
 			}
-				if (packChecksum == null) {
+			if (packChecksum == null) {
 				packChecksum = idx.getChecksum();
-				fileSnapshot.setChecksum(
-						ObjectId.fromRaw(packChecksum));
+				fileSnapshot.setChecksum(ObjectId.fromRaw(packChecksum));
 			} else if (!Arrays.equals(packChecksum,
 					idx.getChecksum())) {
 				throw new PackMismatchException(MessageFormat
@@ -416,6 +439,7 @@ void resolve(Set<ObjectId> matches, AbbreviatedObjectId id, int matchLimit)
 	 *            packs to close
 	 */
 	public static void close(Set<Pack> packs) {
+		// TODO(ifrade): purge also nested packs in midx
 		WindowCache.purge(packs);
 		packs.forEach(p -> p.closeIndices());
 	}
@@ -428,7 +452,12 @@ public void close() {
 		closeIndices();
 	}
 
-	private synchronized void closeIndices() {
+	/**
+	 * Clear the indexes referenced in this pack.
+	 * <p>
+	 * Subclasses override this method to clear references to any index they add
+	 */
+	protected synchronized void closeIndices() {
 		loadedIdx = Optionally.empty();
 		reverseIdx = Optionally.empty();
 		bitmapIdx = Optionally.empty();
@@ -1316,8 +1345,8 @@ private synchronized PackBitmapIndex memoizeBitmapIndexIfNeeded() throws IOExcep
 			return optional.get();
 		}
 		try {
-			PackBitmapIndex idx = PackBitmapIndex.open(bitmapIdxFile, idx(),
-					getReverseIdx());
+			PackBitmapIndex idx = PackBitmapIndex.open(bitmapIdxFile,
+					getIndex(), getReverseIdx());
 			// At this point, idx() will have set packChecksum.
 			if (Arrays.equals(packChecksum, idx.getPackChecksum())) {
 				bitmapIdx = optionally(idx);
@@ -1342,7 +1371,34 @@ void setBitmapIndexFile(PackFile bitmapIndexFile) {
 		this.bitmapIdxFile = bitmapIndexFile;
 	}
 
-	private PackReverseIndex getReverseIdx() throws IOException {
+	/**
+	 * Return the pack if all its objects are included in the need bitmaps.
+	 *
+	 * @param needBitmaps
+	 *            bitmap with needed objects. Modified in this method: If a pack
+	 *            is fully included in the bitmap, the pack objects are removed
+	 *            from the bitmap.
+	 * @return list of packs fully included in the bitmap
+	 * @throws IOException
+	 *             an error reading the bitmap index of this pack
+	 */
+	protected List<Pack> fullyIncludedIn(BitmapIndex.BitmapBuilder needBitmaps)
+			throws IOException {
+		PackBitmapIndex bitmapIndex = getBitmapIndex();
+		if (needBitmaps.removeAllOrNone(bitmapIndex)) {
+			return Collections.singletonList(this);
+		}
+		return Collections.emptyList();
+	}
+
+	/**
+	 * Get the reverse index of this pack
+	 *
+	 * @return a reverse index
+	 * @throws IOException
+	 *             an error loading or calculating the reverse index.
+	 */
+	protected PackReverseIndex getReverseIdx() throws IOException {
 		Optional<PackReverseIndex> optional = reverseIdx.getOptional();
 		if (optional.isPresent()) {
 			return optional.get();
@@ -1399,7 +1455,16 @@ public String toString() {
 				+ ObjectId.fromRaw(packChecksum).name() + "]";
 	}
 
-	private <T> Optionally<T> optionally(T element) {
+	/**
+	 * Wrap the reference in an Optionally
+	 *
+	 * @param element
+	 *            reference
+	 * @return Optionally with the reference inside
+	 * @param <T>
+	 *            the type
+	 */
+	protected <T> Optionally<T> optionally(T element) {
 		return useStrongRefs ? new Optionally.Hard<>(element) : new Optionally.Soft<>(element);
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java
index ffbc073..54100ec 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackBitmapIndexRemapper.java
@@ -36,6 +36,8 @@ public class PackBitmapIndexRemapper
 	private final BitSet inflated;
 	private final int[] prevToNewMapping;
 
+	private final boolean reuseOldBitmapAsIs;
+
 	/**
 	 * A PackBitmapIndex that maps the positions in the prevBitmapIndex to the
 	 * ones in the newIndex.
@@ -65,6 +67,7 @@ private PackBitmapIndexRemapper(PackBitmapIndex newPackIndex) {
 		this.newPackIndex = newPackIndex;
 		this.inflated = null;
 		this.prevToNewMapping = null;
+		this.reuseOldBitmapAsIs = false;
 	}
 
 	private PackBitmapIndexRemapper(
@@ -73,10 +76,18 @@ private PackBitmapIndexRemapper(
 		this.newPackIndex = newPackIndex;
 		inflated = new BitSet(newPackIndex.getObjectCount());
 
-		prevToNewMapping = new int[oldPackIndex.getObjectCount()];
-		for (int pos = 0; pos < prevToNewMapping.length; pos++)
-			prevToNewMapping[pos] = newPackIndex.findPosition(
-					oldPackIndex.getObject(pos));
+		int[] prevToNewMappingTmp = new int[oldPackIndex.getObjectCount()];
+		boolean allPositionsMatch = true;
+		for (int pos = 0; pos < prevToNewMappingTmp.length; pos++) {
+			prevToNewMappingTmp[pos] = newPackIndex
+					.findPosition(oldPackIndex.getObject(pos));
+			if (prevToNewMappingTmp[pos] != pos) {
+				allPositionsMatch = false;
+			}
+		}
+		this.reuseOldBitmapAsIs = allPositionsMatch;
+		// We do not need it!
+		this.prevToNewMapping = allPositionsMatch ? null : prevToNewMappingTmp;
 	}
 
 	@Override
@@ -169,10 +180,24 @@ public EWAHCompressedBitmap getBitmap(AnyObjectId objectId) {
 		if (newPackIndex.findPosition(objectId) == -1)
 			return null;
 
+		if (reuseOldBitmapAsIs) {
+			return oldBitmap.getBitmap();
+		}
+
 		inflated.clear();
-		for (IntIterator i = oldBitmap.getBitmapWithoutCaching()
-				.intIterator(); i.hasNext();)
+		EWAHCompressedBitmap oldEWAHBitmap = oldBitmap
+				.getBitmapWithoutCaching();
+		if (oldEWAHBitmap.sizeInBits() > oldPackIndex.getObjectCount()) {
+			throw new IllegalStateException(String.format(
+					"Bitmap from old index has %d bits but index has only %d objects (new index has %d objects)",
+					oldEWAHBitmap.sizeInBits(), oldPackIndex.getObjectCount(),
+					newPackIndex.getObjectCount()));
+		}
+
+		for (IntIterator i = oldEWAHBitmap.intIterator(); i.hasNext();) {
 			inflated.set(prevToNewMapping[i.next()]);
+		}
+
 		bitmap = inflated.toEWAHCompressedBitmap();
 		bitmap.trim();
 		return bitmap;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java
index 872bb9e..2e06f3c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackDirectory.java
@@ -13,6 +13,7 @@
 import static org.eclipse.jgit.internal.storage.pack.PackExt.BITMAP_INDEX;
 import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX;
 import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK;
+import static org.eclipse.jgit.lib.Constants.MIDX_FILE;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -20,10 +21,12 @@
 import java.io.InputStream;
 import java.nio.file.Files;
 import java.text.MessageFormat;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Deque;
 import java.util.EnumMap;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -32,6 +35,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
 
 import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.errors.CorruptObjectException;
@@ -45,6 +49,7 @@
 import org.eclipse.jgit.lib.AbbreviatedObjectId;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.CoreConfig;
 import org.eclipse.jgit.lib.CoreConfig.TrustStat;
 import org.eclipse.jgit.lib.ObjectId;
@@ -79,6 +84,8 @@ class PackDirectory {
 
 	private final TrustStat trustPackStat;
 
+	private final boolean useMidx;
+
 	/**
 	 * Initialize a reference to an on-disk 'pack' directory.
 	 *
@@ -92,6 +99,8 @@ class PackDirectory {
 		this.directory = directory;
 		packList = new AtomicReference<>(NO_PACKS);
 		trustPackStat = config.get(CoreConfig.KEY).getTrustPackStat();
+		useMidx = config.getBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
+				ConfigConstants.CONFIG_KEY_MULTIPACKINDEX, true);
 	}
 
 	/**
@@ -122,8 +131,7 @@ Collection<Pack> getPacks() {
 				list = scanPacks(list);
 			}
 		} while (searchPacksAgain(list));
-		Pack[] packs = list.packs;
-		return Collections.unmodifiableCollection(Arrays.asList(packs));
+		return Collections.unmodifiableCollection(Arrays.asList(list.packs));
 	}
 
 	@Override
@@ -136,7 +144,8 @@ public String toString() {
 	 *
 	 * @param objectId
 	 *            identity of the object to test for existence of.
-	 * @return {@code true} if the specified object is stored in this PackDirectory.
+	 * @return {@code true} if the specified object is stored in this
+	 *         PackDirectory.
 	 */
 	boolean has(AnyObjectId objectId) {
 		return getPack(objectId) != null;
@@ -379,7 +388,8 @@ boolean searchPacksAgain(PackList old) {
 		case AFTER_OPEN:
 			try (InputStream stream = Files
 					.newInputStream(directory.toPath())) {
-				// open the pack directory to refresh attributes (on some NFS clients)
+				// open the pack directory to refresh attributes (on some NFS
+				// clients)
 			} catch (IOException e) {
 				// ignore
 			}
@@ -470,6 +480,7 @@ private PackList scanPacks(PackList original) {
 	private PackList scanPacksImpl(PackList old) {
 		final Map<String, Pack> forReuse = reuseMap(old);
 		final FileSnapshot snapshot = FileSnapshot.save(directory);
+
 		Map<String, Map<PackExt, PackFile>> packFilesByExtById = getPackFilesByExtById();
 		List<Pack> list = new ArrayList<>(packFilesByExtById.size());
 		boolean foundNew = false;
@@ -496,10 +507,32 @@ private PackList scanPacksImpl(PackList old) {
 				continue;
 			}
 
-			list.add(new Pack(config, packFile, packFilesByExt.get(BITMAP_INDEX)));
+			list.add(new Pack(config, packFile,
+					packFilesByExt.get(BITMAP_INDEX)));
 			foundNew = true;
 		}
 
+		PackMidx theMidx = null;
+		File midx = new File(directory, MIDX_FILE);
+		if (useMidx && midx.exists()) {
+			Pack oldMidx = forReuse.get(midx.getName());
+			if (oldMidx != null
+					&& !oldMidx.getFileSnapshot().isModified(midx)) {
+				// Reuse the previous instance
+				forReuse.remove(midx.getName());
+				theMidx = (PackMidx) oldMidx;
+			} else {
+				try {
+					theMidx = new PackMidx(config, midx, list);
+					foundNew = true;
+				} catch (IOException e) {
+					// pass
+					LOG.warn(MessageFormat.format(JGitText.get().cannotOpenMidx,
+							midx.getAbsolutePath(), e.getMessage()));
+				}
+			}
+		}
+
 		// If we did not discover any new files, the modification time was not
 		// changed, and we did not remove any files, then the set of files is
 		// the same as the set we were given. Instead of building a new object
@@ -516,6 +549,22 @@ private PackList scanPacksImpl(PackList old) {
 			return new PackList(snapshot, NO_PACKS.packs);
 		}
 
+		if (useMidx && theMidx != null) {
+			// Replace the covered packs with the midx in the list
+			Set<String> coveredPackNames = theMidx.getCoveredPacks().stream()
+					.map(p -> p.getPackName())
+					.collect(Collectors.toUnmodifiableSet());
+			int packsBefore = list.size();
+			list = list.stream()
+					.filter(p -> !coveredPackNames.contains(p.getPackName()))
+					.collect(Collectors.toCollection(ArrayList::new));
+			int packsAfter = list.size();
+			LOG.debug(String.format(
+					"Mangling packlist: midx replaces %d packs (list went from %d to %d packs)", //$NON-NLS-1$
+					coveredPackNames.size(), packsBefore, packsAfter));
+			list.add(theMidx);
+		}
+
 		final Pack[] r = list.toArray(new Pack[0]);
 		Arrays.sort(r, Pack.SORT);
 		return new PackList(snapshot, r);
@@ -523,7 +572,9 @@ private PackList scanPacksImpl(PackList old) {
 
 	private static Map<String, Pack> reuseMap(PackList old) {
 		final Map<String, Pack> forReuse = new HashMap<>();
-		for (Pack p : old.packs) {
+		Deque<Pack> queue = new ArrayDeque<>(List.of(old.packs));
+		while (!queue.isEmpty()) {
+			Pack p = queue.removeFirst();
 			if (p.invalid()) {
 				// The pack instance is corrupted, and cannot be safely used
 				// again. Do not include it in our reuse map.
@@ -532,6 +583,8 @@ private static Map<String, Pack> reuseMap(PackList old) {
 				continue;
 			}
 
+			queue.addAll(p.getCoveredPacks());
+
 			final Pack prior = forReuse.put(p.getPackFile().getName(), p);
 			if (prior != null) {
 				// This should never occur. It should be impossible for us
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackMidx.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackMidx.java
new file mode 100644
index 0000000..672d0bc
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackMidx.java
@@ -0,0 +1,544 @@
+/*
+ * Copyright (C) 2026, Google LLC
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.internal.storage.file;
+
+import static java.util.stream.Collectors.toMap;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.zip.DataFormatException;
+
+import org.eclipse.jgit.errors.CorruptObjectException;
+import org.eclipse.jgit.errors.LargeObjectException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.errors.PackInvalidException;
+import org.eclipse.jgit.errors.PackMismatchException;
+import org.eclipse.jgit.internal.storage.midx.MidxMetadataReader;
+import org.eclipse.jgit.internal.storage.midx.MultiPackIndex;
+import org.eclipse.jgit.internal.storage.midx.MultiPackIndexLoader;
+import org.eclipse.jgit.internal.storage.pack.PackExt;
+import org.eclipse.jgit.internal.storage.pack.PackOutputStream;
+import org.eclipse.jgit.internal.util.Optionally;
+import org.eclipse.jgit.lib.AbbreviatedObjectId;
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.BitmapIndex;
+import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectLoader;
+
+/**
+ * A pack that uses internally a midx
+ *
+ * This pack answers what it can directly from the midx (e.g. hasObject) and
+ * sends to the right pack other calls (e.g. reading the actual object).
+ */
+public class PackMidx extends Pack {
+	private final List<Pack> packsInIdOrder;
+
+	private final OffsetCalculator offsetCalculator;
+
+	private Optionally<MultiPackIndex> midx = Optionally.empty();
+
+	private volatile PackIndex idx;
+
+	private volatile PackReverseIndex ridx;
+
+	// TODO(ifrade): Encapsulate invalid/invalidatingCause in Pack to reuse here
+	private IOException invalidatingCause;
+
+	/**
+	 * Construct a reader for existing, pre-indexed packfiles.
+	 *
+	 * @param cfg
+	 *            configuration this directory consults for write settings.
+	 * @param midxFile
+	 *            path of the <code>.midx</code> file holding the data.
+	 * @param knownPacks
+	 *            packs in the repo to find the packs covered by this midx
+	 * @throws IOException
+	 *             an error reading any of the files involved
+	 */
+	public PackMidx(Config cfg, File midxFile, List<Pack> knownPacks)
+			throws IOException {
+		super(cfg, midxFile, null);
+		MidxMetadataReader.MidxMetadata midxMeta = MidxMetadataReader
+				.read(midxFile);
+		// Maybe we could load only the packnames chunk at this point
+		setPackChecksum(midxMeta.checksum());
+		String[] packNames = midxMeta.packNames().toArray(new String[0]);
+
+		Map<String, Pack> knownPacksByName = knownPacks.stream()
+				.collect(toMap(
+						p -> p.getPackFile().create(PackExt.INDEX).getName(),
+						Function.identity()));
+		packsInIdOrder = Arrays.stream(packNames).map(knownPacksByName::get)
+				.filter(Objects::nonNull)
+				.collect(Collectors.toUnmodifiableList());
+		if (packsInIdOrder.size() != packNames.length) {
+			throw new IOException("Midx refers to packs not in the pack list"); //$NON-NLS-1$
+		}
+		offsetCalculator = new OffsetCalculator(packsInIdOrder.stream()
+				.mapToLong(p -> p.getPackFile().length()).toArray());
+
+		ObjectId checksumHex = ObjectId.fromRaw(midxMeta.checksum());
+		File midxBitmaps = new File(midxFile.getParentFile(), String.format(
+				"%s-%s.bitmap", Constants.MIDX_FILE, checksumHex.name()));
+		if (midxBitmaps.exists()) {
+			setBitmapIndexFile(new PackFile(midxBitmaps));
+		}
+	}
+
+	/**
+	 * Return the packs covered by this midx (in midx order)
+	 *
+	 * @return packs covered by this midx
+	 */
+	@Override
+	public List<Pack> getCoveredPacks() {
+		return packsInIdOrder;
+	}
+
+	@Override
+	public PackFile getPackFile() {
+		return super.getPackFile();
+	}
+
+	@Override
+	protected List<Pack> fullyIncludedIn(BitmapIndex.BitmapBuilder needBitmaps)
+			throws IOException {
+		PackBitmapIndex bitmapIndex = getBitmapIndex();
+		if (needBitmaps.removeAllOrNone(bitmapIndex)) {
+			return getCoveredPacks();
+		}
+		return Collections.emptyList();
+	}
+
+	@Override
+	public PackIndex getIndex() {
+		if (idx == null) {
+			synchronized (this) {
+				if (idx == null) {
+					try {
+						idx = new MidxPackIndex(getMidx(), offsetCalculator);
+					} catch (IOException e) {
+						throw new UncheckedIOException(e);
+					}
+				}
+			}
+		}
+		return idx;
+	}
+
+	@Override
+	public PackReverseIndex getReverseIdx() {
+		if (ridx == null) {
+			synchronized (this) {
+				if (ridx == null) {
+					try {
+						ridx = new MidxPackReverseIndex(getMidx(),
+								offsetCalculator);
+					} catch (IOException e) {
+						throw new UncheckedIOException(e);
+					}
+				}
+			}
+		}
+		return ridx;
+	}
+
+	@Override
+	public boolean hasObjectSizeIndex() throws IOException {
+		return false;
+	}
+
+	@Override
+	public long getObjectSizeIndexCount() throws IOException {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public long getIndexedObjectSize(AnyObjectId id) throws IOException {
+		throw new UnsupportedOperationException();
+	}
+
+	@Override
+	public boolean hasObject(AnyObjectId id) throws IOException {
+		return getMidx().hasObject(id);
+	}
+
+	@Override
+	public boolean shouldBeKept() {
+		return false;
+	}
+
+	@Override
+	ObjectLoader get(WindowCursor curs, AnyObjectId id) throws IOException {
+		MultiPackIndex.PackOffset packOffset = getMidx().find(id);
+		if (packOffset == null) {
+			return null;
+		}
+		return packsInIdOrder.get(packOffset.getPackId()).get(curs, id);
+	}
+
+	@Override
+	void resolve(Set<ObjectId> matches, AbbreviatedObjectId id, int matchLimit)
+			throws IOException {
+		getMidx().resolve(matches, id, matchLimit);
+	}
+
+	@Override
+	protected synchronized void closeIndices() {
+		for (Pack p : getCoveredPacks()) {
+			p.closeIndices();
+		}
+		midx = Optionally.empty();
+		super.closeIndices();
+	}
+
+	@Override
+	public Iterator<PackIndex.MutableEntry> iterator() {
+		return getIndex().iterator();
+	}
+
+	@Override
+	long getObjectCount() throws IOException {
+		return getMidx().getObjectCount();
+	}
+
+	@Override
+	ObjectId findObjectForOffset(long offset) throws IOException {
+		MultiPackIndex.PackOffset decode = offsetCalculator.decode(offset);
+		if (decode == null) {
+			return null;
+		}
+		MultiPackIndex theMidx = getMidx();
+		int bitmapPosition = theMidx.findBitmapPosition(decode);
+		if (bitmapPosition < 0) {
+			throw new IllegalStateException(
+					"Object in midx without ridx position");
+		}
+
+		return theMidx.getObjectAtBitmapPosition(bitmapPosition);
+	}
+
+	@Override
+	ObjectId getPackChecksum() {
+		try {
+			return ObjectId.fromRaw(getMidx().getChecksum());
+		} catch (IOException e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	@Override
+	void copyPackAsIs(PackOutputStream out, WindowCursor curs)
+			throws IOException {
+		for (Pack p : packsInIdOrder) {
+			p.copyPackAsIs(out, curs);
+		}
+	}
+
+	@Override
+	boolean beginWindowCache() throws IOException {
+		boolean startedWindow = false;
+		for (Pack p : packsInIdOrder) {
+			startedWindow |= p.beginWindowCache();
+		}
+		return startedWindow;
+	}
+
+	@Override
+	boolean endWindowCache() {
+		boolean lastWindow = false;
+		for (Pack p : packsInIdOrder) {
+			lastWindow |= p.endWindowCache();
+		}
+		return lastWindow;
+	}
+
+	@Override
+	ByteArrayWindow read(long pos, int size) throws IOException {
+		MultiPackIndex.PackOffset po = offsetCalculator.decode(pos);
+		return packsInIdOrder.get(po.getPackId()).read(po.getOffset(), size);
+	}
+
+	@Override
+	ByteWindow mmap(long pos, int size) throws IOException {
+		MultiPackIndex.PackOffset po = offsetCalculator.decode(pos);
+		return packsInIdOrder.get(po.getPackId()).mmap(po.getOffset(), size);
+	}
+
+	@Override
+	ObjectLoader load(WindowCursor curs, long pos)
+			throws IOException, LargeObjectException {
+		MultiPackIndex.PackOffset po = offsetCalculator.decode(pos);
+		return packsInIdOrder.get(po.getPackId()).load(curs, po.getOffset());
+	}
+
+	@Override
+	byte[] getDeltaHeader(WindowCursor wc, long pos)
+			throws IOException, DataFormatException {
+		MultiPackIndex.PackOffset po = offsetCalculator.decode(pos);
+		return packsInIdOrder.get(po.getPackId()).getDeltaHeader(wc,
+				po.getOffset());
+	}
+
+	@Override
+	int getObjectType(WindowCursor curs, long pos) throws IOException {
+		MultiPackIndex.PackOffset po = offsetCalculator.decode(pos);
+		return packsInIdOrder.get(po.getPackId()).getObjectType(curs,
+				po.getOffset());
+	}
+
+	@Override
+	long getObjectSize(WindowCursor curs, AnyObjectId id) throws IOException {
+		MultiPackIndex.PackOffset po = getMidx().find(id);
+		if (po == null) {
+			return -1;
+		}
+		return packsInIdOrder.get(po.getPackId()).getObjectSize(curs,
+				po.getOffset());
+	}
+
+	@Override
+	long getObjectSize(WindowCursor curs, long pos) throws IOException {
+		MultiPackIndex.PackOffset po = offsetCalculator.decode(pos);
+		return packsInIdOrder.get(po.getPackId()).getObjectSize(curs,
+				po.getOffset());
+	}
+
+	@Override
+	LocalObjectRepresentation representation(WindowCursor curs,
+			AnyObjectId objectId) throws IOException {
+		MultiPackIndex.PackOffset po = getMidx().find(objectId);
+		if (po == null) {
+			return null;
+		}
+		return packsInIdOrder.get(po.getPackId()).representation(curs,
+				objectId);
+	}
+
+	private MultiPackIndex getMidx() throws IOException {
+		Optional<MultiPackIndex> optional = midx.getOptional();
+		if (optional.isPresent()) {
+			return optional.get();
+		}
+		return memoizeMidxIfNeeded();
+	}
+
+	private synchronized MultiPackIndex memoizeMidxIfNeeded()
+			throws IOException {
+		if (invalid()) {
+			throw new PackInvalidException(getPackFile(), invalidatingCause);
+		}
+		Optional<MultiPackIndex> optional = midx.getOptional();
+		if (optional.isPresent()) {
+			return optional.get();
+		}
+
+		try {
+			MultiPackIndex loadedMidx = MultiPackIndexLoader
+					.open(getPackFile());
+			midx = optionally(loadedMidx);
+			return loadedMidx;
+		} catch (IOException e) {
+			setInvalid();
+			invalidatingCause = e;
+			throw e;
+		}
+	}
+
+	private static class OffsetCalculator {
+		private final MultiPackIndex.PackOffset mutablePo = new MultiPackIndex.PackOffset();
+
+		private final long[] accSizes;
+
+		OffsetCalculator(long[] packSizes) {
+			accSizes = new long[packSizes.length];
+			accSizes[0] = 0;
+			for (int i = 1; i < packSizes.length; i++) {
+				accSizes[i] = accSizes[i - 1] + packSizes[i - 1];
+			}
+		}
+
+		long encode(MultiPackIndex.PackOffset po) {
+			if (po == null) {
+				return -1;
+			}
+			return accSizes[po.getPackId()] + po.getOffset();
+		}
+
+		long encode(int packId, long offset) {
+			return accSizes[packId] + offset;
+		}
+
+		MultiPackIndex.PackOffset decode(long totalOffset) {
+			if (totalOffset < 0) {
+				return null;
+			}
+
+			for (int i = accSizes.length - 1; i >= 0; i--) {
+				if (totalOffset >= accSizes[i]) {
+					return mutablePo.setValues(i, totalOffset - accSizes[i]);
+				}
+			}
+			return null;
+		}
+	}
+
+	private static class MidxPackIndex implements PackIndex {
+
+		private final MultiPackIndex midx;
+
+		private final OffsetCalculator offsetCalculator;
+
+		MidxPackIndex(MultiPackIndex midx, OffsetCalculator offsetCalculator) {
+			this.midx = midx;
+			this.offsetCalculator = offsetCalculator;
+		}
+
+		@Override
+		public Iterator<MutableEntry> iterator() {
+			MultiPackIndex.MidxIterator it = midx.iterator();
+			return new Iterator<MutableEntry>() {
+
+				private final MutableEntry me = new MutableEntry();
+
+				@Override
+				public boolean hasNext() {
+					return it.hasNext();
+				}
+
+				@Override
+				public MutableEntry next() {
+					MultiPackIndex.MutableEntry entry = it.next();
+					me.idBuffer.fromObjectId(entry.getObjectId());
+					me.offset = offsetCalculator.encode(entry.getPackId(),
+							entry.getOffset());
+					return me;
+				}
+			};
+		}
+
+		@Override
+		public long getObjectCount() {
+			return midx.getObjectCount();
+		}
+
+		@Override
+		public long getOffset64Count() {
+			return 0;
+		}
+
+		@Override
+		public ObjectId getObjectId(long nthPosition) {
+			if (nthPosition < 0) {
+				throw new IllegalArgumentException();
+			}
+			return midx.getObjectAt((int) nthPosition);
+		}
+
+		@Override
+		public long getOffset(long nthPosition) {
+			ObjectId objectAt = midx.getObjectAt((int) nthPosition);
+			MultiPackIndex.PackOffset packOffset = midx.find(objectAt);
+			return offsetCalculator.encode(packOffset);
+		}
+
+		@Override
+		public long findOffset(AnyObjectId objId) {
+			MultiPackIndex.PackOffset packOffset = midx.find(objId);
+			return offsetCalculator.encode(packOffset);
+		}
+
+		@Override
+		public int findPosition(AnyObjectId objId) {
+			return midx.findPosition(objId);
+		}
+
+		@Override
+		public long findCRC32(AnyObjectId objId)
+				throws MissingObjectException, UnsupportedOperationException {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public boolean hasCRC32Support() {
+			return false;
+		}
+
+		@Override
+		public void resolve(Set<ObjectId> matches, AbbreviatedObjectId id,
+				int matchLimit) throws IOException {
+			midx.resolve(matches, id, matchLimit);
+		}
+
+		@Override
+		public byte[] getChecksum() {
+			return midx.getChecksum();
+		}
+	}
+
+	private static final class MidxPackReverseIndex
+			implements PackReverseIndex {
+
+		private final MultiPackIndex midx;
+
+		private final OffsetCalculator offsetCalculator;
+
+		MidxPackReverseIndex(MultiPackIndex midx,
+				OffsetCalculator offsetCalculator) {
+			this.midx = midx;
+			this.offsetCalculator = offsetCalculator;
+		}
+
+		@Override
+		public void verifyPackChecksum(String packFilePath)
+				throws PackMismatchException {
+
+		}
+
+		@Override
+		public ObjectId findObject(long offset) {
+			MultiPackIndex.PackOffset po = offsetCalculator.decode(offset);
+			int revPos = midx.findBitmapPosition(po);
+			return midx.getObjectAtBitmapPosition(revPos);
+		}
+
+		@Override
+		public long findNextOffset(long offset, long maxOffset)
+				throws CorruptObjectException {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public int findPosition(long offset) {
+			MultiPackIndex.PackOffset po = offsetCalculator.decode(offset);
+			return midx.findBitmapPosition(po);
+		}
+
+		@Override
+		public ObjectId findObjectByPosition(int nthPosition) {
+			return midx.getObjectAtBitmapPosition(nthPosition);
+		}
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
index 9fa3ff3..cbf3566 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
@@ -1320,6 +1320,7 @@ class LooseItems {
 	 *            path of a loose ref relative to the repository root
 	 */
 	void refreshPathToLooseRef(Path refPath) {
+		boolean failed = false;
 		for (int i = 1; i < refPath.getNameCount(); i++) {
 			File dir = fileFor(refPath.subpath(0, i).toString());
 			// Use Files.newInputStream(Path) as it is consistent with other
@@ -1328,7 +1329,16 @@ void refreshPathToLooseRef(Path refPath) {
 			try (InputStream stream = Files.newInputStream(dir.toPath())) {
 				// open the dir to refresh attributes (on some NFS clients)
 			} catch (IOException e) {
-				break; // loose ref may not exist
+				failed = true;
+				break; // directory may not exist
+			}
+		}
+		if (!failed) {
+			try (InputStream stream = Files.newInputStream(refPath)) {
+				// open the loose ref to refresh attributes (on some NFS
+				// clients)
+			} catch (IOException e) {
+				// loose ref may not exist
 			}
 		}
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogEntryImpl.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogEntryImpl.java
index 6870d76..9fb7ffc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogEntryImpl.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogEntryImpl.java
@@ -57,33 +57,21 @@ public class ReflogEntryImpl implements Serializable, ReflogEntry {
 		}
 	}
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.jgit.internal.storage.file.ReflogEntry#getOldId()
-	 */
 	@Override
 	public ObjectId getOldId() {
 		return oldId;
 	}
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.jgit.internal.storage.file.ReflogEntry#getNewId()
-	 */
 	@Override
 	public ObjectId getNewId() {
 		return newId;
 	}
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.jgit.internal.storage.file.ReflogEntry#getWho()
-	 */
 	@Override
 	public PersonIdent getWho() {
 		return who;
 	}
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.jgit.internal.storage.file.ReflogEntry#getComment()
-	 */
 	@Override
 	public String getComment() {
 		return comment;
@@ -96,9 +84,6 @@ public String toString() {
 				+ ", " + getComment() + "]";
 	}
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.jgit.internal.storage.file.ReflogEntry#parseCheckout()
-	 */
 	@Override
 	public CheckoutEntry parseCheckout() {
 		if (getComment().startsWith(CheckoutEntryImpl.CHECKOUT_MOVING_FROM)) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java
index f1888eb..98bc108 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ReflogReaderImpl.java
@@ -44,25 +44,16 @@ class ReflogReaderImpl implements ReflogReader {
 		logName = new File(logBaseDir, Constants.L_LOGS + refname);
 	}
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.jgit.internal.storage.file.ReflogReaader#getLastEntry()
-	 */
 	@Override
 	public ReflogEntry getLastEntry() throws IOException {
 		return getReverseEntry(0);
 	}
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.jgit.internal.storage.file.ReflogReaader#getReverseEntries()
-	 */
 	@Override
 	public List<ReflogEntry> getReverseEntries() throws IOException {
 		return getReverseEntries(Integer.MAX_VALUE);
 	}
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.jgit.internal.storage.file.ReflogReaader#getReverseEntry(int)
-	 */
 	@Override
 	public ReflogEntry getReverseEntry(int number) throws IOException {
 		if (number < 0)
@@ -89,9 +80,6 @@ public ReflogEntry getReverseEntry(int number) throws IOException {
 		return null;
 	}
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.jgit.internal.storage.file.ReflogReaader#getReverseEntries(int)
-	 */
 	@Override
 	public List<ReflogEntry> getReverseEntries(int max) throws IOException {
 		final byte[] log;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
index 33459ef..cf485a4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
@@ -12,6 +12,7 @@
 package org.eclipse.jgit.internal.storage.file;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
@@ -26,6 +27,7 @@
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException;
 import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.internal.storage.commitgraph.CommitGraph;
 import org.eclipse.jgit.internal.storage.pack.CachedPack;
 import org.eclipse.jgit.internal.storage.pack.ObjectReuseAsIs;
 import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
@@ -35,7 +37,6 @@
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.BitmapIndex;
 import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
-import org.eclipse.jgit.internal.storage.commitgraph.CommitGraph;
 import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.InflaterCache;
@@ -115,13 +116,15 @@ public Optional<CommitGraph> getCommitGraph() {
 	@Override
 	public Collection<CachedPack> getCachedPacksAndUpdate(
 			BitmapBuilder needBitmap) throws IOException {
+		List<CachedPack> toUseAsIs = new ArrayList<>();
 		for (Pack pack : db.getPacks()) {
-			PackBitmapIndex index = pack.getBitmapIndex();
-			if (needBitmap.removeAllOrNone(index))
-				return Collections.<CachedPack> singletonList(
-						new LocalCachedPack(Collections.singletonList(pack)));
+			List<Pack> packs = pack.fullyIncludedIn(needBitmap);
+			if (packs.isEmpty()) {
+				continue;
+			}
+			toUseAsIs.add(new LocalCachedPack(packs));
 		}
-		return Collections.emptyList();
+		return toUseAsIs;
 	}
 
 	@Override
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MidxMetadataReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MidxMetadataReader.java
new file mode 100644
index 0000000..26c0bb4
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MidxMetadataReader.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2024, GerritForge Inc. and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.internal.storage.midx;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.CHUNK_LOOKUP_WIDTH;
+import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_CHUNKID_PACKNAMES;
+import static org.eclipse.jgit.internal.storage.midx.MultiPackIndexConstants.MIDX_SIGNATURE;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.util.Base64;
+import org.eclipse.jgit.util.IO;
+import org.eclipse.jgit.util.NB;
+import org.eclipse.jgit.util.io.SilentFileInputStream;
+
+/**
+ * Read only basic metadata from the midx without loading the whole file in
+ * memory.
+ * <p>
+ * In some cases we need only a bit of information from the midx and we do not
+ * need it yet fully loaded in memory. For example:
+ * <ul>
+ * <li>We need the checksum of the previous midx to delete its bitmaps</li>
+ * <li>When opening the repo, we need the names of packs referenced by the midx
+ * to check they exist</li>
+ * </ul>
+ */
+public class MidxMetadataReader {
+
+	private MidxMetadataReader() {
+	}
+
+	/**
+	 * Metadata useful before loading the full midx
+	 *
+	 * @param packNames
+	 *            list of packs in this midx (in midx order).
+	 * @param checksumB64
+	 *            checksum of the midx, encoded in Base64
+	 */
+	public record MidxMetadata(List<String> packNames, String checksumB64) {
+		/**
+		 * Return the checksum as byte[]
+		 *
+		 * @return checksum in byte[] format
+		 */
+		public byte[] checksum() {
+			return Base64.decode(checksumB64);
+		}
+	}
+
+	/**
+	 * Open an existing MultiPackIndex file and read its metadata
+	 *
+	 * @param midxFile
+	 *            existing multi-pack-index to read.
+	 * @return the metadata
+	 * @throws FileNotFoundException
+	 *             the file does not exist.
+	 * @throws MultiPackIndexFormatException
+	 *             MultiPackIndex file's format is different from we expected.
+	 * @throws java.io.IOException
+	 *             the file exists but could not be read due to security errors
+	 *             or unexpected data corruption.
+	 */
+	public static MidxMetadata read(File midxFile) throws FileNotFoundException,
+			MultiPackIndexFormatException, IOException {
+		try (SilentFileInputStream fd = new SilentFileInputStream(midxFile)) {
+			try {
+				return read(fd);
+			} catch (MultiPackIndexFormatException fe) {
+				throw fe;
+			} catch (IOException ioe) {
+				throw new IOException(
+						MessageFormat.format(JGitText.get().unreadableMIDX,
+								midxFile.getAbsolutePath()),
+						ioe);
+			}
+		}
+	}
+
+	/**
+	 * Read metadata from an existing MultiPackIndex from a buffered stream.
+	 *
+	 * @param fd
+	 *            stream to read the multipack-index file from. The stream must
+	 *            be buffered as some small IOs are performed against the
+	 *            stream. The caller is responsible for closing the stream.
+	 * @return the metadata
+	 * @throws MultiPackIndexFormatException
+	 *             the MultiPackIndex file's format is different from we
+	 *             expected.
+	 * @throws java.io.IOException
+	 *             the stream cannot be read.
+	 */
+	public static MidxMetadata read(InputStream fd)
+			throws MultiPackIndexFormatException, IOException {
+		byte[] hdr = new byte[12];
+		IO.readFully(fd, hdr, 0, hdr.length);
+
+		int magic = NB.decodeInt32(hdr, 0);
+
+		if (magic != MIDX_SIGNATURE) {
+			throw new MultiPackIndexFormatException(JGitText.get().notAMIDX);
+		}
+
+		// Check MultiPackIndex version
+		int v = hdr[4];
+		if (v != 1) {
+			throw new MultiPackIndexFormatException(MessageFormat.format(
+					JGitText.get().unsupportedMIDXVersion, Integer.valueOf(v)));
+		}
+
+		// Read the object Id version (1 byte)
+		// 1 => SHA-1
+		// 2 => SHA-256
+		// TODO: If the hash type does not match the repository's hash
+		// algorithm,
+		// the multi-pack-index file should be ignored with a warning
+		// presented to the user.
+		int commitIdVersion = hdr[5];
+		if (commitIdVersion != 1) {
+			throw new MultiPackIndexFormatException(
+					JGitText.get().incorrectOBJECT_ID_LENGTH);
+		}
+
+		// Read the number of "chunkOffsets" (1 byte)
+		int chunkCount = hdr[6];
+
+		// Read the number of multi-pack-index files (1 byte)
+		// This value is currently always zero.
+		// TODO populate this
+		// int numberOfMultiPackIndexFiles = hdr[7];
+
+		// Number of packfiles (4 bytes)
+		int packCount = NB.decodeInt32(hdr, 8);
+
+		ChunkIndex chunkIndex = ChunkIndex.read(fd, chunkCount);
+		int currentPos = hdr.length + chunkIndex.getBytesRead();
+		long packNamesStart = chunkIndex.getStartOffset(MIDX_CHUNKID_PACKNAMES);
+		long packNamesEnd = chunkIndex.getEndOffset(MIDX_CHUNKID_PACKNAMES);
+
+		IO.skipFully(fd, packNamesStart - currentPos);
+		byte[] packNamesBuffer = new byte[(int) (packNamesEnd
+				- packNamesStart)];
+		IO.readFully(fd, packNamesBuffer);
+		List<String> packNames = List
+				.of(new String(packNamesBuffer, UTF_8).split("\u0000"));
+		if (packCount != packNames.size()) {
+			throw new MultiPackIndexFormatException(MessageFormat.format(
+					JGitText.get().multiPackIndexPackCountMismatch, packCount,
+					packNames.size()));
+		}
+
+		// We should be at packNamesEnd
+		long endLastChunk = chunkIndex.getLastOffset();
+		IO.skipFully(fd, endLastChunk - packNamesEnd);
+		byte[] checksum = new byte[20];
+		IO.readFully(fd, checksum, 0, 20);
+
+		return new MidxMetadata(packNames, Base64.encodeBytes(checksum));
+	}
+
+	private static final class ChunkIndex {
+
+		private final List<ChunkSegment> chunks;
+
+		private final int byteSize;
+
+		static ChunkIndex read(InputStream fd, int chunkCount)
+				throws IOException {
+			byte[] lookupBuffer = new byte[CHUNK_LOOKUP_WIDTH
+					* (chunkCount + 1)];
+
+			IO.readFully(fd, lookupBuffer, 0, lookupBuffer.length);
+
+			List<ChunkSegment> chunks = new ArrayList<>(chunkCount + 1);
+			for (int i = 0; i <= chunkCount; i++) {
+				// chunks[chunkCount] is just a marker, in order to record the
+				// length of the last chunk.
+				int id = NB.decodeInt32(lookupBuffer, i * 12);
+				long offset = NB.decodeInt64(lookupBuffer, i * 12 + 4);
+				chunks.add(new ChunkSegment(id, offset));
+			}
+			return new ChunkIndex(chunks, lookupBuffer.length);
+		}
+
+		private ChunkIndex(List<ChunkSegment> chunks, int bytesRead) {
+			this.chunks = chunks;
+			this.byteSize = bytesRead;
+		}
+
+		/**
+		 * Bytes read from the stream while reading the chunks
+		 *
+		 * @return number of bytes consumed from the stream
+		 */
+		int getBytesRead() {
+			return byteSize;
+		}
+
+		long getStartOffset(int chunkId) {
+			for (ChunkSegment c : chunks) {
+				if (c.id() == chunkId) {
+					return c.offset();
+				}
+			}
+			throw new IllegalArgumentException("Asking for unknown chunk"); //$NON-NLS-1$
+		}
+
+		long getEndOffset(int chunkId) {
+			int pos = -1;
+			for (int i = 0; i < chunks.size(); i++) {
+				if (chunks.get(i).id() == chunkId) {
+					pos = i;
+					break;
+				}
+			}
+			if (pos == -1) {
+				throw new IllegalArgumentException("Asking for unknown chunk"); //$NON-NLS-1$
+			}
+
+			return chunks.get(pos + 1).offset();
+		}
+
+		long getLastOffset() {
+			return chunks.get(chunks.size() - 1).offset();
+		}
+	}
+
+	private record ChunkSegment(int id, long offset) {
+	}
+
+	/**
+	 * Thrown if a MultiPackIndex doesn't have the expected file format
+	 */
+	public static class MultiPackIndexFormatException extends IOException {
+
+		private static final long serialVersionUID = 1L;
+
+		/**
+		 * Construct an exception.
+		 *
+		 * @param why
+		 *            description of the type of error.
+		 */
+		MultiPackIndexFormatException(String why) {
+			super(why);
+		}
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriter.java
index 00c2a93..6b54b5f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/MultiPackIndexWriter.java
@@ -97,7 +97,7 @@ public Result write(ProgressMonitor monitor, OutputStream outputStream,
 			writeHeader(out, chunkHeaders.size(), data.getPackCount());
 			writeChunkLookup(out, chunkHeaders);
 
-			monitor.beginTask("Writing midx chuncks", chunkHeaders.size());
+			monitor.beginTask("Writing midx chunks", chunkHeaders.size());
 			WriteContext ctx = new WriteContext(out, data);
 			for (ChunkHeader chunk : chunkHeaders) {
 				chunk.writerFn.write(ctx);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/PackIndexMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/PackIndexMerger.java
index 8584176..9e78930 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/PackIndexMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/midx/PackIndexMerger.java
@@ -53,7 +53,8 @@ public class PackIndexMerger {
 	/**
 	 * Builder collecting the inputs for the merger.
 	 * <p>
-	 * Order matters. Packs will appear in the midx in the order they are added.
+	 * Order matters. In case of duplicates, the merger chooses the object in
+	 * the first pack it appears.
 	 */
 	public static class Builder {
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/connectivity/TreeWalkConnectivityChecker.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/connectivity/TreeWalkConnectivityChecker.java
new file mode 100644
index 0000000..cfe6bcf
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/transport/connectivity/TreeWalkConnectivityChecker.java
@@ -0,0 +1,447 @@
+/*
+ * Copyright (C) 2026, Google LLC and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.internal.transport.connectivity;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectIdSubclassMap;
+import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.ObjectReachabilityChecker;
+import org.eclipse.jgit.revwalk.ObjectWalk;
+import org.eclipse.jgit.revwalk.ReachabilityChecker;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.ConnectivityChecker;
+import org.eclipse.jgit.transport.ReceiveCommand;
+import org.eclipse.jgit.treewalk.TreeWalk;
+
+/**
+ * A connectivity checker that avoids the object allocations that occur when
+ * doing standard graph coloring via {@code ObjectWalk}.
+ *
+ * {@code TreeWalkConnectivityChecker} requires the {@code PackParser} to report
+ * new objects in the pack, and will fail immediately if that is not configured.
+ *
+ * The {@code ObjectWalk}-based algorithm marks objects interesting and
+ * uninteresting and parses new subtrees and blobs to propagate those states.
+ * Each propagation of state to a child node requires a Java object allocation.
+ * This algorithm is closer to the diff algorithm. It parses tree objects at
+ * common paths and compares hash values in those trees. Objects only need to be
+ * created for subtrees that differ.
+ *
+ * The tree connectivity part of this algorithm always creates O(commits + tree
+ * objects in the new pack) Java objects, independent of where the parent commit
+ * is in the graph, and independent of the number of references. (Caveat, it
+ * does a standard reachability check if a parent commit is not in advertised
+ * "haves", and a standard object reachability check for any base objects
+ * referenced in a thin pack.) The {@code ObjectWalk}-based algorithm is
+ * equivalent to this algorithm when the parents of new commits are all in the
+ * advertised "haves", creating O(commit + tree objects in the new pack) Java
+ * objects. It is much less efficient otherwise, creating either O(tree objects
+ * in checkout) or O(all objects in checkout) Java objects.
+ *
+ * This algorithm first validates that the commits in the commands (new branch
+ * tips) are connected. Starting with those commits, it walks back until a
+ * commit not in the pack is found, or until a commit with no parents is found.
+ * If a parent commit id is not in the database, connectivity fails. If the
+ * parent commit is in the database and was present in the "haves" advertised
+ * for the client, it moves on to verifying tree connectivity. Otherwise, it
+ * performs a reachability check to make sure the client has access to the
+ * unadvertised parent commit, and proceeds to verifying tree connectivity if
+ * that succeeds.
+ *
+ * Tree connectivity is verified for every commit in the receive pack that was
+ * visited when checking commit connectivity. For each commit, get its root tree
+ * and the root trees of its parents. For each path segment in the child
+ * commit's root tree, do the following (includes recursing into differing
+ * subtrees, where the same actions are applied):
+ * <ul>
+ * <li>if a blob or subtree's id is identical to one of the parent's blob or
+ * subtree's ids, continue/li>
+ * <li>if a new blob id is not present in the database, connectivity fails</li>
+ * <li>if a new subtree id is present in the pack, traverse into the subtree to
+ * continue the check, performing the same actions in this list</li>
+ * <li>if the new subtree id is not in the pack but is present in the database,
+ * continue/li>
+ * <li>if the new subtree id is not in either the pack or the database,
+ * connectivity fails</li>
+ * </ul>
+ */
+public class TreeWalkConnectivityChecker implements ConnectivityChecker {
+	private ObjectIdSubclassMap<ObjectId> objectsInPack;
+
+	private Set<ObjectId> advertisedHaves;
+
+	@Override
+	public void checkConnectivity(ConnectivityCheckInfo connectivityCheckInfo,
+			Set<ObjectId> haves, ProgressMonitor pm) throws IOException {
+
+		if (!connectivityCheckInfo.getParser().needNewObjectIds()) {
+			throw new IllegalStateException(
+					"PackParser.setNeedNewObjectIds(true) must be set"); //$NON-NLS-1$
+		}
+
+		Repository repo = connectivityCheckInfo.getRepository();
+		RevWalk rw = connectivityCheckInfo.getWalk();
+		this.objectsInPack = connectivityCheckInfo.getParser()
+				.getNewObjectIds();
+		this.advertisedHaves = haves;
+
+		Set<RevCommit> nonAdvertisedParentCommitsOutsidePack = new HashSet<>();
+		List<RevCommit> newCommitsToVerify = extractCommitsToVerify(rw, repo,
+				connectivityCheckInfo.getCommands(),
+				nonAdvertisedParentCommitsOutsidePack, pm);
+
+		/*
+		 * This class underreports the full set of objects parsed and does not
+		 * advance the progress monitor in the checkReachability() and
+		 * checkThinPackBases() methods. These methods invoke {@code
+		 * ReachabilityChecker} and @{code ObjectReachabilityChecker}, neither
+		 * of which take a progress monitor. Pushes are generally based on
+		 * commits near branch tips, so the checkers normally do minimal walks.
+		 * Setup for these checkers involves at a minimum marking all "haves" as
+		 * starts, so we capture that in the progress monitor.
+		 */
+		if (!nonAdvertisedParentCommitsOutsidePack.isEmpty()) {
+			pm.update(advertisedHaves.size());
+			checkReachability(rw, repo, nonAdvertisedParentCommitsOutsidePack);
+		}
+
+		checkThinPackBases(rw, connectivityCheckInfo);
+
+		verifyTreeConnectivity(rw, repo, newCommitsToVerify,
+				connectivityCheckInfo.isCheckObjects(), pm);
+	}
+
+	/**
+	 * Extracts commits that need to be verified and identifies parent commits
+	 * outside the pack.
+	 *
+	 * @param rw
+	 *            the RevWalk to use
+	 * @param repo
+	 *            the repository
+	 * @param commands
+	 *            the receive commands
+	 * @param nonAdvertisedParentCommitsOutsidePack
+	 *            set to populate with parent commits outside the pack and not
+	 *            in the advertised set (haves)
+	 * @param pm
+	 *            progress monitor
+	 * @return list of new commits in the pack that require verification
+	 * @throws IOException
+	 *             if an I/O error occurs
+	 */
+	private List<RevCommit> extractCommitsToVerify(RevWalk rw, Repository repo,
+			List<ReceiveCommand> commands,
+			Set<RevCommit> nonAdvertisedParentCommitsOutsidePack,
+			ProgressMonitor pm) throws IOException {
+
+		List<RevCommit> newCommitsToVerify = new ArrayList<>();
+
+		// Gather new commits from the receive commands
+		for (ReceiveCommand cmd : commands) {
+			if (cmd.getType() != ReceiveCommand.Type.DELETE
+					&& !advertisedHaves.contains(cmd.getNewId())) {
+				rw.markStart(rw.parseCommit(cmd.getNewId()));
+			}
+		}
+
+		// Walk commits in the receive pack, recording both commits in the pack
+		// and parent commits outside the pack
+		RevCommit commit;
+		while ((commit = rw.next()) != null) {
+			pm.update(1);
+			if (objectsInPack.contains(commit)) {
+				newCommitsToVerify.add(commit);
+			} else {
+				// Commit not in pack, check object database
+				if (!repo.getObjectDatabase().has(commit)) {
+					throw new MissingObjectException(commit.getId(),
+							Constants.TYPE_COMMIT);
+				}
+				// Advertised parents are reachable, only track non-advertised
+				if (!advertisedHaves.contains(commit.getId())) {
+					nonAdvertisedParentCommitsOutsidePack.add(commit);
+				}
+				rw.markUninteresting(commit);
+			}
+		}
+
+		return newCommitsToVerify;
+	}
+
+	/**
+	 * Performs reachability checks for parent commits outside the pack.
+	 *
+	 * @param rw
+	 *            the RevWalk to use
+	 * @param repo
+	 *            the repository
+	 * @param nonAdvertisedParentCommitsOutsidePack
+	 *            parent commits to check visibility for
+	 * @throws IOException
+	 *             if an I/O error occurs
+	 */
+	private void checkReachability(RevWalk rw, Repository repo,
+			Set<RevCommit> nonAdvertisedParentCommitsOutsidePack)
+			throws IOException {
+
+		try {
+			// First try with the smaller set of advertised haves
+			ReachabilityChecker checker = rw.getObjectReader()
+					.createReachabilityChecker(rw);
+			Stream<RevCommit> starterCommits = advertisedHaves.stream()
+					.map(id -> parseCommitOrNull(rw, id)).filter(Objects::nonNull);
+
+			Optional<RevCommit> unreachable = checker.areAllReachable(
+					nonAdvertisedParentCommitsOutsidePack, starterCommits);
+
+			if (unreachable.isPresent()) {
+				// Fallback to check against full ref database
+				Stream<RevCommit> allRefCommits = repo.getRefDatabase()
+						.getRefs().stream()
+						.map(ref -> parseCommitOrNull(rw, ref.getObjectId()))
+						.filter(Objects::nonNull);
+				unreachable = checker.areAllReachable(
+						nonAdvertisedParentCommitsOutsidePack, allRefCommits);
+				if (unreachable.isPresent()) {
+					throw new MissingObjectException(unreachable.get().getId(),
+							Constants.TYPE_COMMIT);
+				}
+			}
+		} catch (UncheckedIOException e) {
+			throw e.getCause();
+		}
+	}
+
+	/**
+	 * Validates that base objects referenced in a thin pack are reachable.
+	 *
+	 * @param rw
+	 *            the RevWalk to use
+	 * @param connectivityCheckInfo
+	 *            the connectivity check info
+	 * @throws IOException
+	 *             if an I/O error occurs
+	 */
+	private void checkThinPackBases(RevWalk rw,
+			ConnectivityCheckInfo connectivityCheckInfo) throws IOException {
+
+		if (!connectivityCheckInfo.isCheckObjects()) {
+			return;
+		}
+		ObjectIdSubclassMap<ObjectId> baseObjectIds = connectivityCheckInfo
+				.getParser().getBaseObjectIds();
+
+		try (ObjectWalk ow = new ObjectWalk(rw.getObjectReader())) {
+			ObjectReachabilityChecker checker = rw.getObjectReader()
+					.createObjectReachabilityChecker(ow);
+
+			List<RevObject> targetObjs = StreamSupport
+					.stream(baseObjectIds.spliterator(), false)
+					.map(id -> parseAnyUnchecked(ow, id))
+					.collect(Collectors.toList());
+
+			// First try with the smaller set of advertised haves
+			Stream<RevObject> starterObjs = advertisedHaves.stream()
+					.map(id -> parseAnyUnchecked(ow, id))
+					.filter(Objects::nonNull);
+
+			Optional<RevObject> unreachable = checker
+					.areAllReachable(targetObjs, starterObjs);
+			if (unreachable.isPresent()) {
+				// Fallback to check against full ref database
+				Stream<RevObject> allRefCommits = connectivityCheckInfo
+						.getRepository().getRefDatabase().getRefs().stream()
+						.map(ref -> parseAnyUnchecked(ow, ref.getObjectId()))
+						.filter(Objects::nonNull);
+				unreachable = checker.areAllReachable(targetObjs,
+						allRefCommits);
+				if (unreachable.isPresent()) {
+					throw new MissingObjectException(unreachable.get().getId(),
+							Constants.TYPE_COMMIT);
+				}
+			}
+		} catch (UncheckedIOException e) {
+			throw e.getCause();
+		}
+	}
+
+	/**
+	 * Verifies tree connectivity for the new commits.
+	 *
+	 * @param rw
+	 *            the RevWalk to use
+	 * @param repo
+	 *            the repository
+	 * @param newCommitsToVerify
+	 *            commits to verify
+	 * @param checkObjects
+	 *            whether to check objects
+	 * @param pm
+	 *            progress monitor
+	 * @throws IOException
+	 *             if an I/O error occurs
+	 */
+	private void verifyTreeConnectivity(RevWalk rw, Repository repo,
+			List<RevCommit> newCommitsToVerify, boolean checkObjects,
+			ProgressMonitor pm) throws IOException {
+
+		for (RevCommit c : newCommitsToVerify) {
+			verifyTreeConnectivityForCommit(c, rw, repo, checkObjects, pm);
+		}
+	}
+
+	/**
+	 * Verifies tree connectivity for a single commit.
+	 *
+	 * @param c
+	 *            the commit
+	 * @param rw
+	 *            the RevWalk to use
+	 * @param repo
+	 *            the repository
+	 * @param checkObjects
+	 *            whether to check objects
+	 * @param pm
+	 *            progress monitor
+	 * @throws IOException
+	 *             if an I/O error occurs
+	 */
+	private void verifyTreeConnectivityForCommit(RevCommit c, RevWalk rw,
+			Repository repo, boolean checkObjects, ProgressMonitor pm)
+			throws IOException {
+		try (TreeWalk tw = new TreeWalk(rw.getObjectReader())) {
+			tw.setRecursive(false);
+			tw.addTree(c.getTree());
+			pm.update(1);
+			for (RevCommit p : c.getParents()) {
+				tw.addTree(p.getTree());
+				pm.update(1);
+			}
+
+			while (tw.next()) {
+				if (tw.getFileMode(0) == FileMode.MISSING) {
+					continue; // Object deleted or moved
+				}
+
+				if (tw.getFileMode(0) == FileMode.GITLINK) {
+					continue; // Skip submodule entries
+				}
+
+				ObjectId newObjId = tw.getObjectId(0);
+				if (matchesAnyParent(tw, newObjId)) {
+					continue; // matched via object ids
+				}
+
+				if (!tw.isSubtree()) {
+					/*
+					 * Blob case. objectsInPack are already in the object
+					 * database, but the map lookup is faster than the database
+					 * search, so try the map lookup first.
+					 */
+					if (!objectsInPack.contains(newObjId) && (checkObjects
+							|| !repo.getObjectDatabase().has(newObjId))) {
+						throw new MissingObjectException(newObjId,
+								tw.getFileMode(0).getObjectType());
+					}
+				} else {
+					// Subtree case
+					if (objectsInPack.contains(newObjId)) {
+						tw.enterSubtree();
+						pm.update(1 + c.getParentCount());
+					} else if (checkObjects
+							|| !repo.getObjectDatabase().has(newObjId)) {
+						throw new MissingObjectException(newObjId,
+								FileMode.TREE.getObjectType());
+					}
+				} // Else object is in the database
+			}
+		}
+	}
+
+	/**
+	 * Parses an object, throwing UncheckedIOException on failure. For use with
+	 * streams.
+	 *
+	 * @param rw
+	 *            the RevWalk to use
+	 * @param id
+	 *            the object ID
+	 * @return the parsed object
+	 */
+	private static RevObject parseAnyUnchecked(RevWalk rw, ObjectId id) {
+		try {
+			return rw.parseAny(id);
+		} catch (IOException e) {
+			throw new UncheckedIOException(e);
+		}
+	}
+
+	/**
+	 * Parses an object as a commit, peeling tags if necessary. Returns null if
+	 * the object is not a commit or cannot be peeled to a commit. Throws
+	 * UncheckedIOException on other I/O failures. For use with streams.
+	 *
+	 * @param rw
+	 *          the RevWalk to use
+	 * @param id
+	 *          the object ID
+	 * @return the parsed commit, or null
+	 */
+	private static RevCommit parseCommitOrNull(RevWalk rw, ObjectId id) {
+		try {
+			return rw.parseCommit(id);
+		} catch (IncorrectObjectTypeException e) {
+			return null;
+		} catch (IOException e) {
+			throw new UncheckedIOException(e);
+		}
+	}
+
+	/**
+	 * Checks if the new object ID matches any parent tree's object ID at the
+	 * current path.
+	 *
+	 * @param tw
+	 *            the TreeWalk
+	 * @param newObjId
+	 *            the new object ID
+	 * @return true if matches any parent
+	 */
+	private static boolean matchesAnyParent(TreeWalk tw, ObjectId newObjId) {
+		for (int i = 1; i < tw.getTreeCount(); i++) {
+			if (tw.getFileMode(i) != FileMode.MISSING
+					&& newObjId.equals(tw.getObjectId(i))) {
+				return true;
+			}
+		}
+		return false;
+	}
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
index 9de8392..5265e76 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
@@ -839,6 +839,13 @@ public static int decodeTypeString(final AnyObjectId id,
 	 */
 	public static final int COMMIT_GENERATION_NOT_COMPUTED = 0;
 
+	/**
+	 * Name of the .git/objects/packs/multi-pack-index file.
+	 *
+	 * @since 7.7
+	 */
+	public static final String MIDX_FILE = "multi-pack-index";
+
 	private Constants() {
 		// Hide the default constructor
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
index 9a96fdc..415c1ce 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
@@ -14,7 +14,6 @@
 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_ATOMIC;
 
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.OutputStream;
 import java.text.MessageFormat;
 import java.util.Collection;
@@ -173,9 +172,11 @@ protected TransportException noRepository(Throwable cause) {
 	 *             if any exception occurs.
 	 * @since 3.0
 	 */
+	@SuppressWarnings("Finally")
 	protected void doPush(final ProgressMonitor monitor,
 			final Map<String, RemoteRefUpdate> refUpdates,
 			OutputStream outputStream) throws TransportException {
+		Throwable suppressedThrowable = null;
 		try {
 			writeCommands(refUpdates.values(), monitor, outputStream);
 
@@ -183,28 +184,45 @@ protected void doPush(final ProgressMonitor monitor,
 				transmitOptions();
 			if (writePack)
 				writePack(refUpdates, monitor);
-			if (sentCommand) {
-				if (capableReport)
-					readStatusReport(refUpdates);
-				if (capableSideBand) {
-					// Ensure the data channel is at EOF, so we know we have
-					// read all side-band data from all channels and have a
-					// complete copy of the messages (if any) buffered from
-					// the other data channels.
-					//
-					int b = in.read();
-					if (0 <= b) {
-						throw new TransportException(uri, MessageFormat.format(
-								JGitText.get().expectedEOFReceived,
-								Character.valueOf((char) b)));
-					}
-				}
-			}
 		} catch (TransportException e) {
+			suppressedThrowable = e;
 			throw e;
 		} catch (Exception e) {
-			throw new TransportException(uri, e.getMessage(), e);
+			TransportException transportException = new TransportException(uri, e.getMessage(), e);
+			suppressedThrowable = transportException;
+			throw transportException;
 		} finally {
+			try {
+				if (sentCommand) {
+					if (capableReport) {
+						readStatusReport(refUpdates);
+					}
+					if (capableSideBand) {
+						// Ensure the data channel is at EOF, so we know we have
+						// read all side-band data from all channels and have a
+						// complete copy of the messages (if any) buffered from
+						// the other data channels.
+						//
+						int b = in.read();
+						if (0 <= b) {
+							throw new TransportException(uri, MessageFormat.format(
+									JGitText.get().expectedEOFReceived,
+									Character.valueOf((char) b)));
+						}
+					}
+				}
+			} catch (TransportException e) {
+				if (suppressedThrowable != null) {
+					e.addSuppressed(suppressedThrowable);
+				}
+				throw e;
+			} catch (Exception e) {
+				TransportException transportException = new TransportException(uri, e.getMessage(), e);
+				if (suppressedThrowable != null) {
+					transportException.addSuppressed(suppressedThrowable);
+				}
+				throw transportException;
+			}
 			if (in instanceof SideBandInputStream) {
 				((SideBandInputStream) in).drainMessages();
 			}
@@ -324,12 +342,7 @@ private void writePack(final Map<String, RemoteRefUpdate> refUpdates,
 			writer.setReuseValidatingObjects(false);
 			writer.setDeltaBaseAsOffset(capableOfsDelta);
 			writer.preparePack(monitor, newObjects, remoteObjects);
-
-			OutputStream packOut = out;
-			if (capableSideBand) {
-				packOut = new CheckingSideBandOutputStream(in, out);
-			}
-			writer.writePack(monitor, monitor, packOut);
+			writer.writePack(monitor, monitor, out);
 
 			packTransferTime = writer.getStatistics().getTimeWriting();
 		}
@@ -429,48 +442,4 @@ public List<String> getPushOptions() {
 	public boolean isUseBitmaps() {
 		return useBitmaps;
 	}
-
-	private static class CheckingSideBandOutputStream extends OutputStream {
-		private final InputStream in;
-		private final OutputStream out;
-
-		CheckingSideBandOutputStream(InputStream in, OutputStream out) {
-			this.in = in;
-			this.out = out;
-		}
-
-		@Override
-		public void write(int b) throws IOException {
-			write(new byte[] { (byte) b });
-		}
-
-		@Override
-		public void write(byte[] buf, int ptr, int cnt) throws IOException {
-			try {
-				out.write(buf, ptr, cnt);
-			} catch (IOException e) {
-				throw checkError(e);
-			}
-		}
-
-		@Override
-		public void flush() throws IOException {
-			try {
-				out.flush();
-			} catch (IOException e) {
-				throw checkError(e);
-			}
-		}
-
-		private IOException checkError(IOException e1) {
-			try {
-				in.read();
-			} catch (TransportException e2) {
-				return e2;
-			} catch (IOException e2) {
-				return e1;
-			}
-			return e1;
-		}
-	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
index e1f2b19..e842f47 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PackParser.java
@@ -254,7 +254,13 @@ public void setNeedNewObjectIds(boolean b) {
 			newObjectIds = null;
 	}
 
-	private boolean needNewObjectIds() {
+	/**
+	 * Whether the parser is configured to keep track of new objects.
+	 *
+	 * @return {@code true} if new objects are tracked, {@code false} otherwise.
+	 * @since 7.7
+	 */
+	public boolean needNewObjectIds() {
 		return newObjectIds != null;
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
index 3d9c81c..8b05d41 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
@@ -34,6 +34,8 @@
 import java.io.OutputStream;
 import java.io.UncheckedIOException;
 import java.text.MessageFormat;
+import java.time.Duration;
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -236,6 +238,8 @@ public class ReceivePack {
 	private PushCertificate pushCert;
 
 	private ReceivedPackStatistics stats;
+	private long timeReceiving;
+	private long timeCheckingConnectivity;
 
 	/**
 	 * Connectivity checker to use.
@@ -1103,8 +1107,9 @@ public long getPackSize() {
 	 * @return if the client is a shallow repository, the list of edge commits
 	 *         that define the client's shallow boundary. Empty set if the
 	 *         client is earlier than Git 1.9, or is a full clone.
+	 * @since 7.7
 	 */
-	private Set<ObjectId> getClientShallowCommits() {
+	protected Set<ObjectId> getClientShallowCommits() {
 		return clientShallowCommits;
 	}
 
@@ -1202,11 +1207,16 @@ private Map<String, Ref> getAdvertisedOrDefaultRefs() throws IOException {
 	 */
 	protected void receivePackAndCheckConnectivity() throws IOException,
 			LargeObjectException, SubmoduleValidationException {
+		Instant start = Instant.now();
 		receivePack();
+		timeReceiving = Duration.between(start, Instant.now()).toMillis();
+
 		if (needCheckConnectivity()) {
 			checkSubmodules();
 			checkConnectivity();
 		}
+		timeCheckingConnectivity = Duration.between(start, Instant.now())
+				.toMillis() - timeReceiving;
 		parser = null;
 	}
 
@@ -2226,6 +2236,7 @@ public void receiveWithExceptionPropagation(InputStream input,
 	}
 
 	private void service() throws IOException {
+		Instant startNegotiating = Instant.now();
 		if (isBiDirectionalPipe()) {
 			sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut));
 			pckOut.flush();
@@ -2235,6 +2246,8 @@ private void service() throws IOException {
 			return;
 
 		recvCommands();
+		long timeNegotiating = Duration.between(startNegotiating, Instant.now())
+				.toMillis();
 
 		if (hasCommands()) {
 			try (PostReceiveExecutor e = new PostReceiveExecutor()) {
@@ -2249,6 +2262,8 @@ private void service() throws IOException {
 					}
 				}
 
+				Instant startProcessing = Instant.now();
+				long timePreReceiveHooks = 0;
 				try {
 					setAtomic(isCapabilityEnabled(CAPABILITY_ATOMIC));
 
@@ -2257,8 +2272,10 @@ private void service() throws IOException {
 						failPendingCommands();
 					}
 
+					Instant startPreReceive = Instant.now();
 					preReceive.onPreReceive(
 							this, filterCommands(Result.NOT_ATTEMPTED));
+					timePreReceiveHooks = Duration.between(startPreReceive, Instant.now()).toMillis();
 					if (atomic && anyRejects()) {
 						failPendingCommands();
 					}
@@ -2266,6 +2283,18 @@ private void service() throws IOException {
 				} finally {
 					unlockPack();
 				}
+				long timeProcessingCommands = Duration
+						.between(startProcessing, Instant.now()).toMillis() - timePreReceiveHooks;
+
+				ReceivedPackStatistics.Builder statsBuilder = stats != null
+						? ReceivedPackStatistics.Builder.toBuilder(stats)
+						: new ReceivedPackStatistics.Builder();
+				stats = statsBuilder.setTimeNegotiating(timeNegotiating)
+						.setTimeReceiving(timeReceiving)
+						.setTimeCheckingConnectivity(timeCheckingConnectivity)
+						.setTimePreReceiveHooks(timePreReceiveHooks)
+						.setTimeProcessingCommands(timeProcessingCommands)
+						.build();
 
 				sendStatusReport(null);
 			}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivedPackStatistics.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivedPackStatistics.java
index 8887e26..39fadd6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivedPackStatistics.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivedPackStatistics.java
@@ -34,6 +34,12 @@ public class ReceivedPackStatistics {
 	private long numDeltaBlob;
 	private long numDeltaTag;
 
+	private long timeNegotiating;
+	private long timeReceiving;
+	private long timeCheckingConnectivity;
+	private long timePreReceiveHooks;
+	private long timeProcessingCommands;
+
 	/**
 	 * Get number of bytes read from the input stream
 	 *
@@ -155,6 +161,59 @@ public long getNumDeltaTag() {
 		return numDeltaTag;
 	}
 
+	/**
+	 * Get time in milliseconds spent in the negotiation phase
+	 *
+	 * @return time in milliseconds spent in the negotiation phase
+	 * @since 7.7
+	 */
+	public long getTimeNegotiating() {
+		return timeNegotiating;
+	}
+
+	/**
+	 * Get time in milliseconds spent receiving the pack
+	 *
+	 * @return time in milliseconds spent receiving the pack
+	 * @since 7.7
+	 */
+	public long getTimeReceiving() {
+		return timeReceiving;
+	}
+
+	/**
+	 * Get time in milliseconds spent checking the connectivity of the received
+	 * pack
+	 *
+	 * @return time in milliseconds spent checking the connectivity of the
+	 *         received pack
+	 * @since 7.7
+	 */
+	public long getTimeCheckingConnectivity() {
+		return timeCheckingConnectivity;
+	}
+
+	/**
+	 * Get time in milliseconds spent in pre-receive hooks
+	 *
+	 * @return time in milliseconds spent in pre-receive hooks
+	 * @since 7.7
+	 */
+	public long getTimePreReceiveHooks() {
+		return timePreReceiveHooks;
+	}
+
+	/**
+	 * Get time in milliseconds spent processing commands (validation
+	 * and ref updates)
+	 *
+	 * @return time in milliseconds spent processing commands
+	 * @since 7.7
+	 */
+	public long getTimeProcessingCommands() {
+		return timeProcessingCommands;
+	}
+
 	/** A builder for {@link ReceivedPackStatistics}. */
 	public static class Builder {
 		private long numBytesRead;
@@ -173,6 +232,41 @@ public static class Builder {
 		private long numDeltaBlob;
 		private long numDeltaTag;
 
+		private long timeNegotiating;
+		private long timeReceiving;
+		private long timeCheckingConnectivity;
+		private long timePreReceiveHooks;
+		private long timeProcessingCommands;
+
+		/**
+		 * Initialize from an existing ReceivedPackStatistics.
+		 *
+		 * @param s
+		 *            existing ReceivedPackStatistics object
+		 * @return new Builder instance
+		 * @since 7.7
+		 */
+		public static Builder toBuilder(ReceivedPackStatistics s) {
+			Builder b = new Builder();
+			b.numBytesRead = s.getNumBytesRead();
+			b.numWholeCommit = s.getNumWholeCommit();
+			b.numWholeTree = s.getNumWholeTree();
+			b.numWholeBlob = s.getNumWholeBlob();
+			b.numWholeTag = s.getNumWholeTag();
+			b.numOfsDelta = s.getNumOfsDelta();
+			b.numRefDelta = s.getNumRefDelta();
+			b.numDeltaCommit = s.getNumDeltaCommit();
+			b.numDeltaTree = s.getNumDeltaTree();
+			b.numDeltaBlob = s.getNumDeltaBlob();
+			b.numDeltaTag = s.getNumDeltaTag();
+			b.timeNegotiating = s.getTimeNegotiating();
+			b.timeReceiving = s.getTimeReceiving();
+			b.timeCheckingConnectivity = s.getTimeCheckingConnectivity();
+			b.timePreReceiveHooks = s.getTimePreReceiveHooks();
+			b.timeProcessingCommands = s.getTimeProcessingCommands();
+			return b;
+		}
+
 		/**
 		 * Set number of bytes read from the input stream
 		 *
@@ -226,6 +320,63 @@ public Builder addWholeObject(int type) {
 		}
 
 		/**
+		 * @param timeNegotiating
+		 *            time in milliseconds spent in the negotiation phase
+		 * @return this
+		 * @since 7.7
+		 */
+		public Builder setTimeNegotiating(long timeNegotiating) {
+			this.timeNegotiating = timeNegotiating;
+			return this;
+		}
+
+		/**
+		 * @param timeReceiving
+		 *            time in milliseconds spent receiving the pack
+		 * @return this
+		 * @since 7.7
+		 */
+		public Builder setTimeReceiving(long timeReceiving) {
+			this.timeReceiving = timeReceiving;
+			return this;
+		}
+
+		/**
+		 * @param timeCheckingConnectivity
+		 *            time in milliseconds spent checking the connectivity of
+		 *            the received pack
+		 * @return this
+		 * @since 7.7
+		 */
+		public Builder setTimeCheckingConnectivity(
+				long timeCheckingConnectivity) {
+			this.timeCheckingConnectivity = timeCheckingConnectivity;
+			return this;
+		}
+
+		/**
+		 * @param timePreReceiveHooks
+		 *                            time in milliseconds spent in pre-receive hooks
+		 * @return this
+		 * @since 7.7
+		 */
+		public Builder setTimePreReceiveHooks(long timePreReceiveHooks) {
+			this.timePreReceiveHooks = timePreReceiveHooks;
+			return this;
+		}
+
+		/**
+		 * @param timeProcessingCommands
+		 *            time in milliseconds spent processing commands
+		 * @return this
+		 * @since 7.7
+		 */
+		public Builder setTimeProcessingCommands(long timeProcessingCommands) {
+			this.timeProcessingCommands = timeProcessingCommands;
+			return this;
+		}
+
+		/**
 		 * Increment offset delta
 		 *
 		 * @return this
@@ -299,6 +450,11 @@ ReceivedPackStatistics build() {
 			s.numDeltaBlob = numDeltaBlob;
 			s.numDeltaTag = numDeltaTag;
 			s.numObjectsDuplicated = numObjectsDuplicated;
+			s.timeNegotiating = timeNegotiating;
+			s.timeReceiving = timeReceiving;
+			s.timeCheckingConnectivity = timeCheckingConnectivity;
+			s.timePreReceiveHooks = timePreReceiveHooks;
+			s.timeProcessingCommands = timeProcessingCommands;
 			return s;
 		}
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
index 41ab8ac..c3b2f61 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -189,9 +189,12 @@ void checkWants(UploadPack up, List<ObjectId> wants)
 				throws PackProtocolException, IOException;
 	}
 
-	/*
+	/**
 	 * {@link java.util.function.Consumer} doesn't allow throwing checked
 	 * exceptions. Define our own to propagate IOExceptions.
+	 *
+	 * @param <R>
+	 *            input argument
 	 */
 	@FunctionalInterface
 	private static interface IOConsumer<R> {
diff --git a/pom.xml b/pom.xml
index 8e00d87..1d65343 100644
--- a/pom.xml
+++ b/pom.xml
@@ -130,14 +130,14 @@
     <commons-compress-version>1.28.0</commons-compress-version>
     <osgi-core-version>6.0.0</osgi-core-version>
     <servlet-api-version>4.0.1</servlet-api-version>
-    <jetty-version>12.1.6</jetty-version>
+    <jetty-version>12.1.8</jetty-version>
     <japicmp-version>0.25.0</japicmp-version>
     <httpclient-version>4.5.14</httpclient-version>
     <httpcore-version>4.4.16</httpcore-version>
     <slf4j-version>2.0.17</slf4j-version>
     <maven-javadoc-plugin-version>3.12.0</maven-javadoc-plugin-version>
     <gson-version>2.13.2</gson-version>
-    <bouncycastle-version>1.83</bouncycastle-version>
+    <bouncycastle-version>1.84</bouncycastle-version>
     <spotbugs-maven-plugin-version>4.9.8.2</spotbugs-maven-plugin-version>
     <maven-project-info-reports-plugin-version>3.9.0</maven-project-info-reports-plugin-version>
     <maven-jxr-plugin-version>3.6.0</maven-jxr-plugin-version>
@@ -148,7 +148,7 @@
     <hamcrest-version>3.0</hamcrest-version>
     <assertj-version>3.27.7</assertj-version>
     <jna-version>5.18.1</jna-version>
-    <byte-buddy-version>1.18.5</byte-buddy-version>
+    <byte-buddy-version>1.18.8</byte-buddy-version>
 
     <!-- Properties to enable jacoco code coverage analysis -->
     <sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin>
@@ -917,13 +917,13 @@
       <dependency>
         <groupId>commons-logging</groupId>
         <artifactId>commons-logging</artifactId>
-        <version>1.3.5</version>
+        <version>1.3.6</version>
       </dependency>
 
       <dependency>
         <groupId>org.tukaani</groupId>
         <artifactId>xz</artifactId>
-        <version>1.11</version>
+        <version>1.12</version>
         <optional>true</optional>
       </dependency>
 
@@ -1026,7 +1026,7 @@
       <dependency>
         <groupId>org.mockito</groupId>
         <artifactId>mockito-core</artifactId>
-        <version>5.21.0</version>
+        <version>5.23.0</version>
       </dependency>
 
       <dependency>
diff --git a/tools/version.sh b/tools/version.sh
index 75f1a6a..6cc6a90 100755
--- a/tools/version.sh
+++ b/tools/version.sh
@@ -170,4 +170,4 @@
 	' $(git ls-files | grep pom.xml)
 
 find . -name '*~' | xargs rm -f
-git diff
+git --no-pager diff
diff --git a/tools/workspace_status.py b/tools/workspace_status.py
index 1186a4a..f56120c 100644
--- a/tools/workspace_status.py
+++ b/tools/workspace_status.py
@@ -23,7 +23,7 @@
 import sys
 
 ROOT = os.path.abspath(__file__)
-while not os.path.exists(os.path.join(ROOT, 'WORKSPACE')):
+while not os.path.exists(os.path.join(ROOT, 'MODULE.bazel')):
     ROOT = os.path.dirname(ROOT)
 CMD = ['git', 'describe', '--always', '--match', 'v[0-9].*', '--dirty']