D4979: wireprotov2: change how revisions are specified to changesetdata

indygreg (Gregory Szorc) phabricator at mercurial-scm.org
Fri Oct 12 08:17:28 UTC 2018


indygreg created this revision.
Herald added a subscriber: mercurial-devel.
Herald added a reviewer: hg-reviewers.

REVISION SUMMARY
  Right now, we have a handful of arguments for specifying the revisions
  whose data should be returned. Defining how all these arguments
  interact when various combinations are present is difficult.
  
  This commit establishes a new, generic mechanism for specifying
  revisions. Instead of a hodgepodge of arguments defining things, we
  have a list of dicts that specify revision selectors. The final set
  of revisions is a union of all these selectors.
  
  We implement support for specifying revisions based on:
  
  - An explicit list of changeset revisions
  - An explicit list of changeset revisions plus ancestry depth
  - A DAG range between changeset roots and heads
  
  If you squint hard enough, this problem has already been solved by
  revsets. But I'm reluctant to expose revsets to the wire protocol
  because that would require servers to implement a revset parser.
  Plus there are security and performance implications: the set
  of revision selectors needs to be narrowly and specifically tailored
  for what is appropriate to be executing on a server. Perhaps there
  would be a way for us to express the "parse tree" of a revset
  query, for example. I'm not sure. We can explore this space another
  time. For now, the new mechanism should bring sufficient flexibility
  while remaining relatively simple.
  
  The selector "types" are prefixed with "changeset" because I plan
  to add manifest and file-flavored selectors as well. This will enable
  us to e.g. select file revisions based on a range of changeset
  revisions.

REPOSITORY
  rHG Mercurial

REVISION DETAIL
  https://phab.mercurial-scm.org/D4979

AFFECTED FILES
  mercurial/exchangev2.py
  mercurial/help/internals/wireprotocolv2.txt
  mercurial/wireprototypes.py
  mercurial/wireprotov2server.py
  tests/test-clone.t
  tests/test-http-api-httpv2.t
  tests/test-http-api.t
  tests/test-http-protocol.t
  tests/test-ssh-bundle1.t
  tests/test-ssh-proto-unbundle.t
  tests/test-ssh-proto.t
  tests/test-ssh.t
  tests/test-wireproto-caching.t
  tests/test-wireproto-command-capabilities.t
  tests/test-wireproto-command-changesetdata.t
  tests/test-wireproto-content-redirects.t
  tests/test-wireproto-exchangev2.t
  tests/wireprotohelpers.sh

CHANGE DETAILS

diff --git a/tests/wireprotohelpers.sh b/tests/wireprotohelpers.sh
--- a/tests/wireprotohelpers.sh
+++ b/tests/wireprotohelpers.sh
@@ -1,4 +1,4 @@
-HTTPV2=exp-http-v2-0002
+HTTPV2=exp-http-v2-0003
 MEDIATYPE=application/mercurial-exp-framing-0006
 
 sendhttpraw() {
diff --git a/tests/test-wireproto-exchangev2.t b/tests/test-wireproto-exchangev2.t
--- a/tests/test-wireproto-exchangev2.t
+++ b/tests/test-wireproto-exchangev2.t
@@ -60,12 +60,15 @@
       'phase',
       'revision'
     ]),
-    'noderange': [
-      [],
-      [
-        '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
-        '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
-      ]
+    'revisions': [
+      {
+        'heads': [
+          '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
+          '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
+        ],
+        'roots': [],
+        'type': 'changesetdagrange'
+      }
     ]
   }
   received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
@@ -202,11 +205,14 @@
       'phase',
       'revision'
     ]),
-    'noderange': [
-      [],
-      [
-        'D2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0'
-      ]
+    'revisions': [
+      {
+        'heads': [
+          'D2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0'
+        ],
+        'roots': [],
+        'type': 'changesetdagrange'
+      }
     ]
   }
   received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
@@ -312,14 +318,17 @@
       'phase',
       'revision'
     ]),
-    'noderange': [
-      [
-        'D2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0'
-      ],
-      [
-        '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
-        '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
-      ]
+    'revisions': [
+      {
+        'heads': [
+          '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
+          '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
+        ],
+        'roots': [
+          'D2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0'
+        ],
+        'type': 'changesetdagrange'
+      }
     ]
   }
   received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
@@ -440,15 +449,18 @@
       'phase',
       'revision'
     ]),
-    'noderange': [
-      [
-        '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
-        '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
-      ],
-      [
-        '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
-        '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
-      ]
+    'revisions': [
+      {
+        'heads': [
+          '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
+          '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
+        ],
+        'roots': [
+          '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
+          '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
+        ],
+        'type': 'changesetdagrange'
+      }
     ]
   }
   received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
@@ -502,12 +514,15 @@
       'phase',
       'revision'
     ]),
-    'noderange': [
-      [],
-      [
-        '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
-        '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
-      ]
+    'revisions': [
+      {
+        'heads': [
+          '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
+          '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
+        ],
+        'roots': [],
+        'type': 'changesetdagrange'
+      }
     ]
   }
   received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
@@ -619,15 +634,18 @@
       'phase',
       'revision'
     ]),
-    'noderange': [
-      [
-        '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
-        '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
-      ],
-      [
-        '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
-        '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
-      ]
+    'revisions': [
+      {
+        'heads': [
+          '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
+          '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
+        ],
+        'roots': [
+          '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
+          '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
+        ],
+        'type': 'changesetdagrange'
+      }
     ]
   }
   received frame(size=9; request=1; stream=2; streamflags=stream-begin; type=stream-settings; flags=eos)
diff --git a/tests/test-wireproto-content-redirects.t b/tests/test-wireproto-content-redirects.t
--- a/tests/test-wireproto-content-redirects.t
+++ b/tests/test-wireproto-content-redirects.t
@@ -55,7 +55,7 @@
   s>     Accept-Encoding: identity\r\n
   s>     vary: X-HgProto-1,X-HgUpgrade-1\r\n
   s>     x-hgproto-1: cbor\r\n
-  s>     x-hgupgrade-1: exp-http-v2-0002\r\n
+  s>     x-hgupgrade-1: exp-http-v2-0003\r\n
   s>     accept: application/mercurial-0.1\r\n
   s>     host: $LOCALIP:$HGPORT\r\n (glob)
   s>     user-agent: Mercurial debugwireproto\r\n
@@ -65,12 +65,12 @@
   s>     Server: testing stub value\r\n
   s>     Date: $HTTP_DATE$\r\n
   s>     Content-Type: application/mercurial-cbor\r\n
-  s>     Content-Length: 1956\r\n
+  s>     Content-Length: 1871\r\n
   s>     \r\n
-  s>     \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0002\xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa5DnameHtarget-aHprotocolDhttpKsnirequired\xf4Ktlsversions\x82C1.2C1.3Duris\x81Shttp://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
+  s>     \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa5DnameHtarget-aHprotocolDhttpKsnirequired\xf4Ktlsversions\x82C1.2C1.3Duris\x81Shttp://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
   (remote redirect target target-a is compatible)
   sending capabilities command
-  s>     POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     accept: application/mercurial-exp-framing-0006\r\n
   s>     content-type: application/mercurial-exp-framing-0006\r\n
@@ -96,11 +96,11 @@
   s>     \xa1FstatusBok
   s>     \r\n
   received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  s>     5a2\r\n
-  s>     \x9a\x05\x00\x01\x00\x02\x041
-  s>     \xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa5DnameHtarget-aHprotocolDhttpKsnirequired\xf4Ktlsversions\x82C1.2C1.3Duris\x81Shttp://example.com/
+  s>     54d\r\n
+  s>     E\x05\x00\x01\x00\x02\x041
+  s>     \xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa5DnameHtarget-aHprotocolDhttpKsnirequired\xf4Ktlsversions\x82C1.2C1.3Duris\x81Shttp://example.com/
   s>     \r\n
-  received frame(size=1434; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
+  received frame(size=1349; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
   s>     8\r\n
   s>     \x00\x00\x00\x01\x00\x02\x002
   s>     \r\n
@@ -135,20 +135,9 @@
                 b'revision'
               ])
             },
-            b'noderange': {
-              b'default': None,
-              b'required': False,
+            b'revisions': {
+              b'required': True,
               b'type': b'list'
-            },
-            b'nodes': {
-              b'default': None,
-              b'required': False,
-              b'type': b'list'
-            },
-            b'nodesdepth': {
-              b'default': None,
-              b'required': False,
-              b'type': b'int'
             }
           },
           b'permissions': [
@@ -344,7 +333,7 @@
   s>     Accept-Encoding: identity\r\n
   s>     vary: X-HgProto-1,X-HgUpgrade-1\r\n
   s>     x-hgproto-1: cbor\r\n
-  s>     x-hgupgrade-1: exp-http-v2-0002\r\n
+  s>     x-hgupgrade-1: exp-http-v2-0003\r\n
   s>     accept: application/mercurial-0.1\r\n
   s>     host: $LOCALIP:$HGPORT\r\n (glob)
   s>     user-agent: Mercurial debugwireproto\r\n
@@ -354,13 +343,13 @@
   s>     Server: testing stub value\r\n
   s>     Date: $HTTP_DATE$\r\n
   s>     Content-Type: application/mercurial-cbor\r\n
-  s>     Content-Length: 1983\r\n
+  s>     Content-Length: 1898\r\n
   s>     \r\n
-  s>     \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0002\xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x82\xa3DnameHtarget-aHprotocolDhttpDuris\x81Shttp://example.com/\xa3DnameHtarget-bHprotocolGunknownDuris\x81Vunknown://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
+  s>     \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x82\xa3DnameHtarget-aHprotocolDhttpDuris\x81Shttp://example.com/\xa3DnameHtarget-bHprotocolGunknownDuris\x81Vunknown://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
   (remote redirect target target-a is compatible)
   (remote redirect target target-b uses unsupported protocol: unknown)
   sending capabilities command
-  s>     POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     accept: application/mercurial-exp-framing-0006\r\n
   s>     content-type: application/mercurial-exp-framing-0006\r\n
@@ -386,11 +375,11 @@
   s>     \xa1FstatusBok
   s>     \r\n
   received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  s>     5bd\r\n
-  s>     \xb5\x05\x00\x01\x00\x02\x041
-  s>     \xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x82\xa3DnameHtarget-aHprotocolDhttpDuris\x81Shttp://example.com/\xa3DnameHtarget-bHprotocolGunknownDuris\x81Vunknown://example.com/
+  s>     568\r\n
+  s>     `\x05\x00\x01\x00\x02\x041
+  s>     \xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x82\xa3DnameHtarget-aHprotocolDhttpDuris\x81Shttp://example.com/\xa3DnameHtarget-bHprotocolGunknownDuris\x81Vunknown://example.com/
   s>     \r\n
-  received frame(size=1461; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
+  received frame(size=1376; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
   s>     8\r\n
   s>     \x00\x00\x00\x01\x00\x02\x002
   s>     \r\n
@@ -425,20 +414,9 @@
                 b'revision'
               ])
             },
-            b'noderange': {
-              b'default': None,
-              b'required': False,
+            b'revisions': {
+              b'required': True,
               b'type': b'list'
-            },
-            b'nodes': {
-              b'default': None,
-              b'required': False,
-              b'type': b'list'
-            },
-            b'nodesdepth': {
-              b'default': None,
-              b'required': False,
-              b'type': b'int'
             }
           },
           b'permissions': [
@@ -641,7 +619,7 @@
   s>     Accept-Encoding: identity\r\n
   s>     vary: X-HgProto-1,X-HgUpgrade-1\r\n
   s>     x-hgproto-1: cbor\r\n
-  s>     x-hgupgrade-1: exp-http-v2-0002\r\n
+  s>     x-hgupgrade-1: exp-http-v2-0003\r\n
   s>     accept: application/mercurial-0.1\r\n
   s>     host: $LOCALIP:$HGPORT\r\n (glob)
   s>     user-agent: Mercurial debugwireproto\r\n
@@ -651,12 +629,12 @@
   s>     Server: testing stub value\r\n
   s>     Date: $HTTP_DATE$\r\n
   s>     Content-Type: application/mercurial-cbor\r\n
-  s>     Content-Length: 1943\r\n
+  s>     Content-Length: 1858\r\n
   s>     \r\n
-  s>     \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0002\xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKsnirequired\xf5Duris\x81Thttps://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
+  s>     \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKsnirequired\xf5Duris\x81Thttps://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
   (redirect target target-bad-tls requires SNI, which is unsupported)
   sending capabilities command
-  s>     POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     accept: application/mercurial-exp-framing-0006\r\n
   s>     content-type: application/mercurial-exp-framing-0006\r\n
@@ -682,11 +660,11 @@
   s>     \xa1FstatusBok
   s>     \r\n
   received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  s>     595\r\n
-  s>     \x8d\x05\x00\x01\x00\x02\x041
-  s>     \xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKsnirequired\xf5Duris\x81Thttps://example.com/
+  s>     540\r\n
+  s>     8\x05\x00\x01\x00\x02\x041
+  s>     \xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKsnirequired\xf5Duris\x81Thttps://example.com/
   s>     \r\n
-  received frame(size=1421; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
+  received frame(size=1336; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
   s>     8\r\n
   s>     \x00\x00\x00\x01\x00\x02\x002
   s>     \r\n
@@ -721,20 +699,9 @@
                 b'revision'
               ])
             },
-            b'noderange': {
-              b'default': None,
-              b'required': False,
+            b'revisions': {
+              b'required': True,
               b'type': b'list'
-            },
-            b'nodes': {
-              b'default': None,
-              b'required': False,
-              b'type': b'list'
-            },
-            b'nodesdepth': {
-              b'default': None,
-              b'required': False,
-              b'type': b'int'
             }
           },
           b'permissions': [
@@ -927,7 +894,7 @@
   s>     Accept-Encoding: identity\r\n
   s>     vary: X-HgProto-1,X-HgUpgrade-1\r\n
   s>     x-hgproto-1: cbor\r\n
-  s>     x-hgupgrade-1: exp-http-v2-0002\r\n
+  s>     x-hgupgrade-1: exp-http-v2-0003\r\n
   s>     accept: application/mercurial-0.1\r\n
   s>     host: $LOCALIP:$HGPORT\r\n (glob)
   s>     user-agent: Mercurial debugwireproto\r\n
@@ -937,12 +904,12 @@
   s>     Server: testing stub value\r\n
   s>     Date: $HTTP_DATE$\r\n
   s>     Content-Type: application/mercurial-cbor\r\n
-  s>     Content-Length: 1949\r\n
+  s>     Content-Length: 1864\r\n
   s>     \r\n
-  s>     \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0002\xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKtlsversions\x82B42B39Duris\x81Thttps://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
+  s>     \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKtlsversions\x82B42B39Duris\x81Thttps://example.com/Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
   (remote redirect target target-bad-tls requires unsupported TLS versions: 39, 42)
   sending capabilities command
-  s>     POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     accept: application/mercurial-exp-framing-0006\r\n
   s>     content-type: application/mercurial-exp-framing-0006\r\n
@@ -968,11 +935,11 @@
   s>     \xa1FstatusBok
   s>     \r\n
   received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  s>     59b\r\n
-  s>     \x93\x05\x00\x01\x00\x02\x041
-  s>     \xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKtlsversions\x82B42B39Duris\x81Thttps://example.com/
+  s>     546\r\n
+  s>     >\x05\x00\x01\x00\x02\x041
+  s>     \xa5Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Hredirect\xa2Fhashes\x82Fsha256Dsha1Gtargets\x81\xa4DnameNtarget-bad-tlsHprotocolEhttpsKtlsversions\x82B42B39Duris\x81Thttps://example.com/
   s>     \r\n
-  received frame(size=1427; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
+  received frame(size=1342; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
   s>     8\r\n
   s>     \x00\x00\x00\x01\x00\x02\x002
   s>     \r\n
@@ -1007,20 +974,9 @@
                 b'revision'
               ])
             },
-            b'noderange': {
-              b'default': None,
-              b'required': False,
+            b'revisions': {
+              b'required': True,
               b'type': b'list'
-            },
-            b'nodes': {
-              b'default': None,
-              b'required': False,
-              b'type': b'list'
-            },
-            b'nodesdepth': {
-              b'default': None,
-              b'required': False,
-              b'type': b'int'
             }
           },
           b'permissions': [
@@ -1249,11 +1205,11 @@
 Cached entry should be available on server
 
   $ sendhttpraw << EOF
-  > httprequest GET api/simplecache/64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca
+  > httprequest GET api/simplecache/47abb8efa5f01b8964d74917793ad2464db0fa2c
   >     user-agent: test
   > EOF
   using raw connection to peer
-  s>     GET /api/simplecache/64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca HTTP/1.1\r\n
+  s>     GET /api/simplecache/47abb8efa5f01b8964d74917793ad2464db0fa2c HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     user-agent: test\r\n
   s>     host: $LOCALIP:$HGPORT\r\n (glob)
@@ -1307,8 +1263,8 @@
 
   $ cat .hg/blackbox.log
   *> cacher constructed for manifestdata (glob)
-  *> cache miss for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
-  *> storing cache entry for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
+  *> cache miss for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
+  *> storing cache entry for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
   *> cacher constructed for manifestdata (glob)
-  *> cache hit for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
-  *> sending content redirect for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca to http://*:$HGPORT/api/simplecache/64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
+  *> cache hit for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
+  *> sending content redirect for 47abb8efa5f01b8964d74917793ad2464db0fa2c to http://*:$HGPORT/api/simplecache/47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
diff --git a/tests/test-wireproto-command-changesetdata.t b/tests/test-wireproto-command-changesetdata.t
--- a/tests/test-wireproto-command-changesetdata.t
+++ b/tests/test-wireproto-command-changesetdata.t
@@ -44,37 +44,100 @@
   > EOF
   creating http peer for wire protocol version 2
   sending changesetdata command
-  abort: noderange or nodes must be defined!
+  abort: missing required arguments: revisions!
   [255]
 
-Empty noderange heads results in an error
+Missing nodes for changesetexplicit results in error
+
+  $ sendhttpv2peer << EOF
+  > command changesetdata
+  >     revisions eval:[{b'type': b'changesetexplicit'}]
+  > EOF
+  creating http peer for wire protocol version 2
+  sending changesetdata command
+  abort: nodes key not present in changesetexplicit revision specifier!
+  [255]
+
+changesetexplicitdepth requires nodes and depth keys
 
   $ sendhttpv2peer << EOF
   > command changesetdata
-  >     noderange eval:[[],[]]
+  >     revisions eval:[{b'type': b'changesetexplicitdepth'}]
+  > EOF
+  creating http peer for wire protocol version 2
+  sending changesetdata command
+  abort: nodes key not present in changesetexplicitdepth revision specifier!
+  [255]
+
+  $ sendhttpv2peer << EOF
+  > command changesetdata
+  >     revisions eval:[{b'type': b'changesetexplicitdepth', b'nodes': []}]
+  > EOF
+  creating http peer for wire protocol version 2
+  sending changesetdata command
+  abort: depth key not present in changesetexplicitdepth revision specifier!
+  [255]
+
+  $ sendhttpv2peer << EOF
+  > command changesetdata
+  >     revisions eval:[{b'type': b'changesetexplicitdepth', b'depth': 42}]
   > EOF
   creating http peer for wire protocol version 2
   sending changesetdata command
-  abort: heads in noderange request cannot be empty!
+  abort: nodes key not present in changesetexplicitdepth revision specifier!
   [255]
 
-nodesdepth requires nodes argument
+changesetdagrange requires roots and heads keys
+
+  $ sendhttpv2peer << EOF
+  > command changesetdata
+  >     revisions eval:[{b'type': b'changesetdagrange'}]
+  > EOF
+  creating http peer for wire protocol version 2
+  sending changesetdata command
+  abort: roots key not present in changesetdagrange revision specifier!
+  [255]
+
+  $ sendhttpv2peer << EOF
+  > command changesetdata
+  >     revisions eval:[{b'type': b'changesetdagrange', b'roots': []}]
+  > EOF
+  creating http peer for wire protocol version 2
+  sending changesetdata command
+  abort: heads key not present in changesetdagrange revision specifier!
+  [255]
 
   $ sendhttpv2peer << EOF
   > command changesetdata
-  >     nodesdepth 42
-  >     noderange eval:[[], [b'ignored']]
+  >     revisions eval:[{b'type': b'changesetdagrange', b'heads': [b'dummy']}]
+  > EOF
+  creating http peer for wire protocol version 2
+  sending changesetdata command
+  abort: roots key not present in changesetdagrange revision specifier!
+  [255]
+
+Empty changesetdagrange heads results in an error
+
+  $ sendhttpv2peer << EOF
+  > command changesetdata
+  >     revisions eval:[{b'type': b'changesetdagrange', b'heads': [], b'roots': []}]
   > EOF
   creating http peer for wire protocol version 2
   sending changesetdata command
-  abort: nodesdepth requires the nodes argument!
+  abort: heads key in changesetdagrange cannot be empty!
   [255]
 
-Sending just noderange heads sends all revisions
+Sending just dagrange heads sends all revisions
 
   $ sendhttpv2peer << EOF
   > command changesetdata
-  >     noderange eval:[[], [b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd', b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11']]
+  >     revisions eval:[{
+  >         b'type': b'changesetdagrange',
+  >         b'roots': [],
+  >         b'heads': [
+  >             b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd',
+  >             b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11',
+  >         ]}]
   > EOF
   creating http peer for wire protocol version 2
   sending changesetdata command
@@ -100,7 +163,12 @@
 
   $ sendhttpv2peer << EOF
   > command changesetdata
-  >     noderange eval:[[b'\x33\x90\xef\x85\x00\x73\xfb\xc2\xf0\xdf\xff\x22\x44\x34\x2c\x8e\x92\x29\x01\x3a'], [b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd']]
+  >     revisions eval:[{
+  >         b'type': b'changesetdagrange',
+  >         b'roots': [b'\x33\x90\xef\x85\x00\x73\xfb\xc2\xf0\xdf\xff\x22\x44\x34\x2c\x8e\x92\x29\x01\x3a'],
+  >         b'heads': [
+  >             b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd',
+  >         ]}]
   > EOF
   creating http peer for wire protocol version 2
   sending changesetdata command
@@ -120,7 +188,9 @@
 
   $ sendhttpv2peer << EOF
   > command changesetdata
-  >     nodes eval:[b'\x33\x90\xef\x85\x00\x73\xfb\xc2\xf0\xdf\xff\x22\x44\x34\x2c\x8e\x92\x29\x01\x3a']
+  >     revisions eval:[{
+  >         b'type': b'changesetexplicit',
+  >         b'nodes': [b'\x33\x90\xef\x85\x00\x73\xfb\xc2\xf0\xdf\xff\x22\x44\x34\x2c\x8e\x92\x29\x01\x3a']}]
   > EOF
   creating http peer for wire protocol version 2
   sending changesetdata command
@@ -137,8 +207,16 @@
 
   $ sendhttpv2peer << EOF
   > command changesetdata
-  >     noderange eval:[[b'\x75\x92\x91\x7e\x1c\x3e\x82\x67\x7c\xb0\xa4\xbc\x71\x5c\xa2\x5d\xd1\x2d\x28\xc1'], [b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd']]
-  >     nodes eval:[b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11']
+  >     revisions eval:[
+  >         {
+  >             b'type': b'changesetexplicit',
+  >             b'nodes': [b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11'],
+  >         },
+  >         {
+  >             b'type': b'changesetdagrange',
+  >             b'roots': [b'\x75\x92\x91\x7e\x1c\x3e\x82\x67\x7c\xb0\xa4\xbc\x71\x5c\xa2\x5d\xd1\x2d\x28\xc1'],
+  >             b'heads': [b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd'],
+  >         }]
   > EOF
   creating http peer for wire protocol version 2
   sending changesetdata command
@@ -158,8 +236,10 @@
 
   $ sendhttpv2peer << EOF
   > command changesetdata
-  >     nodes eval:[b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11']
-  >     nodesdepth eval:1
+  >     revisions eval:[{
+  >         b'type': b'changesetexplicitdepth',
+  >         b'nodes': [b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11'],
+  >         b'depth': 1}] 
   > EOF
   creating http peer for wire protocol version 2
   sending changesetdata command
@@ -176,8 +256,10 @@
 
   $ sendhttpv2peer << EOF
   > command changesetdata
-  >     nodes eval:[b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11']
-  >     nodesdepth eval:2
+  >     revisions eval:[{
+  >         b'type': b'changesetexplicitdepth',
+  >         b'nodes': [b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11'],
+  >         b'depth': 2}]
   > EOF
   creating http peer for wire protocol version 2
   sending changesetdata command
@@ -197,8 +279,10 @@
 
   $ sendhttpv2peer << EOF
   > command changesetdata
-  >     nodes eval:[b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11', b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd']
-  >     nodesdepth eval:2
+  >     revisions eval:[{
+  >         b'type': b'changesetexplicitdepth',
+  >         b'nodes': [b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11', b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd'],
+  >         b'depth': 2}]
   > EOF
   creating http peer for wire protocol version 2
   sending changesetdata command
@@ -225,7 +309,11 @@
   $ sendhttpv2peer << EOF
   > command changesetdata
   >     fields eval:[b'parents']
-  >     nodes eval:[b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11']
+  >     revisions eval:[{
+  >         b'type': b'changesetexplicit',
+  >         b'nodes': [
+  >             b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11',
+  >         ]}]
   > EOF
   creating http peer for wire protocol version 2
   sending changesetdata command
@@ -247,7 +335,11 @@
   $ sendhttpv2peer << EOF
   > command changesetdata
   >     fields eval:[b'phase']
-  >     nodes eval:[b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd']
+  >     revisions eval:[{
+  >         b'type': b'changesetexplicit',
+  >         b'nodes': [
+  >             b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd',
+  >         ]}]
   > EOF
   creating http peer for wire protocol version 2
   sending changesetdata command
@@ -266,7 +358,11 @@
   $ sendhttpv2peer << EOF
   > command changesetdata
   >     fields eval:[b'revision']
-  >     nodes eval:[b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11']
+  >     revisions eval:[{
+  >         b'type': b'changesetexplicit',
+  >         b'nodes': [
+  >             b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11',
+  >         ]}]
   > EOF
   creating http peer for wire protocol version 2
   sending changesetdata command
@@ -291,7 +387,13 @@
   $ sendhttpv2peer << EOF
   > command changesetdata
   >     fields eval:[b'bookmarks']
-  >     noderange eval:[[], [b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd', b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11']]
+  >     revisions eval:[{
+  >         b'type': b'changesetdagrange',
+  >         b'roots': [],
+  >         b'heads': [
+  >             b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd',
+  >             b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11',
+  >         ]}]
   > EOF
   creating http peer for wire protocol version 2
   sending changesetdata command
@@ -322,7 +424,13 @@
   $ sendhttpv2peer << EOF
   > command changesetdata
   >     fields eval:[b'bookmarks']
-  >     noderange eval:[[], [b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd', b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11']]
+  >     revisions eval:[{
+  >         b'type': b'changesetdagrange',
+  >         b'roots': [],
+  >         b'heads': [
+  >             b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd',
+  >             b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11',
+  >         ]}]
   > EOF
   creating http peer for wire protocol version 2
   sending changesetdata command
@@ -356,7 +464,13 @@
   $ sendhttpv2peer << EOF
   > command changesetdata
   >     fields eval:[b'bookmarks', b'revision']
-  >     noderange eval:[[b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11'], [b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd', b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11']]
+  >     revisions eval:[{
+  >         b'type': b'changesetdagrange',
+  >         b'roots': [b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11'],
+  >         b'heads': [
+  >             b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd',
+  >             b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11',
+  >         ]}]
   > EOF
   creating http peer for wire protocol version 2
   sending changesetdata command
@@ -401,7 +515,11 @@
   $ sendhttpv2peer << EOF
   > command changesetdata
   >     fields eval:[b'parents', b'revision']
-  >     nodes eval:[b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11']
+  >     revisions eval:[{
+  >         b'type': b'changesetexplicit',
+  >         b'nodes': [
+  >             b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11',
+  >         ]}]
   > EOF
   creating http peer for wire protocol version 2
   sending changesetdata command
@@ -431,7 +549,13 @@
   $ sendhttpv2peer << EOF
   > command changesetdata
   >     fields eval:[b'phase', b'parents', b'revision']
-  >     noderange eval:[[b'\x33\x90\xef\x85\x00\x73\xfb\xc2\xf0\xdf\xff\x22\x44\x34\x2c\x8e\x92\x29\x01\x3a'], [b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd', b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11']]
+  >     revisions eval:[{
+  >         b'type': b'changesetdagrange',
+  >         b'roots': [b'\x33\x90\xef\x85\x00\x73\xfb\xc2\xf0\xdf\xff\x22\x44\x34\x2c\x8e\x92\x29\x01\x3a'],
+  >         b'heads': [
+  >             b'\x0b\xb8\xad\x89\x4a\x15\xb1\x53\x80\xb2\xa2\xa5\xb1\x83\xe2\x0f\x2a\x4b\x28\xdd',
+  >             b'\xea\xe5\xf8\x2c\x2e\x62\x23\x68\xd2\x7d\xae\xcb\x76\xb7\xe3\x93\xd0\xf2\x42\x11',
+  >         ]}]
   > EOF
   creating http peer for wire protocol version 2
   sending changesetdata command
diff --git a/tests/test-wireproto-command-capabilities.t b/tests/test-wireproto-command-capabilities.t
--- a/tests/test-wireproto-command-capabilities.t
+++ b/tests/test-wireproto-command-capabilities.t
@@ -198,15 +198,15 @@
   $ sendhttpraw << EOF
   > httprequest GET ?cmd=capabilities
   >    user-agent: test
-  >    x-hgupgrade-1: exp-http-v2-0002 foo bar
+  >    x-hgupgrade-1: exp-http-v2-0003 foo bar
   >    x-hgproto-1: cbor
   > EOF
   using raw connection to peer
   s>     GET /?cmd=capabilities HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     user-agent: test\r\n
   s>     x-hgproto-1: cbor\r\n
-  s>     x-hgupgrade-1: exp-http-v2-0002 foo bar\r\n
+  s>     x-hgupgrade-1: exp-http-v2-0003 foo bar\r\n
   s>     host: $LOCALIP:$HGPORT\r\n (glob)
   s>     \r\n
   s> makefile('rb', None)
@@ -216,12 +216,12 @@
   s>     Content-Type: application/mercurial-cbor\r\n
   s>     Content-Length: *\r\n (glob)
   s>     \r\n
-  s>     \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0002\xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
+  s>     \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
   cbor> [
     {
       b'apibase': b'api/',
       b'apis': {
-        b'exp-http-v2-0002': {
+        b'exp-http-v2-0003': {
           b'commands': {
             b'branchmap': {
               b'args': {},
@@ -248,20 +248,9 @@
                     b'revision'
                   ])
                 },
-                b'noderange': {
-                  b'default': None,
-                  b'required': False,
+                b'revisions': {
+                  b'required': True,
                   b'type': b'list'
-                },
-                b'nodes': {
-                  b'default': None,
-                  b'required': False,
-                  b'type': b'list'
-                },
-                b'nodesdepth': {
-                  b'default': None,
-                  b'required': False,
-                  b'type': b'int'
                 }
               },
               b'permissions': [
@@ -424,7 +413,7 @@
   s>     Accept-Encoding: identity\r\n
   s>     vary: X-HgProto-1,X-HgUpgrade-1\r\n
   s>     x-hgproto-1: cbor\r\n
-  s>     x-hgupgrade-1: exp-http-v2-0002\r\n
+  s>     x-hgupgrade-1: exp-http-v2-0003\r\n
   s>     accept: application/mercurial-0.1\r\n
   s>     host: $LOCALIP:$HGPORT\r\n (glob)
   s>     user-agent: Mercurial debugwireproto\r\n
@@ -436,9 +425,9 @@
   s>     Content-Type: application/mercurial-cbor\r\n
   s>     Content-Length: *\r\n (glob)
   s>     \r\n
-  s>     \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0002\xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
+  s>     \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
   sending capabilities command
-  s>     POST /api/exp-http-v2-0002/ro/capabilities HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/ro/capabilities HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     accept: application/mercurial-exp-framing-0006\r\n
   s>     content-type: application/mercurial-exp-framing-0006\r\n
@@ -464,11 +453,11 @@
   s>     \xa1FstatusBok
   s>     \r\n
   received frame(size=11; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
-  s>     522\r\n
-  s>     \x1a\x05\x00\x01\x00\x02\x041
-  s>     \xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1
+  s>     4cd\r\n
+  s>     \xc5\x04\x00\x01\x00\x02\x041
+  s>     \xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1
   s>     \r\n
-  received frame(size=1306; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
+  received frame(size=1221; request=1; stream=2; streamflags=encoded; type=command-response; flags=continuation)
   s>     8\r\n
   s>     \x00\x00\x00\x01\x00\x02\x002
   s>     \r\n
@@ -503,20 +492,9 @@
                 b'revision'
               ])
             },
-            b'noderange': {
-              b'default': None,
-              b'required': False,
+            b'revisions': {
+              b'required': True,
               b'type': b'list'
-            },
-            b'nodes': {
-              b'default': None,
-              b'required': False,
-              b'type': b'list'
-            },
-            b'nodesdepth': {
-              b'default': None,
-              b'required': False,
-              b'type': b'int'
             }
           },
           b'permissions': [
diff --git a/tests/test-wireproto-caching.t b/tests/test-wireproto-caching.t
--- a/tests/test-wireproto-caching.t
+++ b/tests/test-wireproto-caching.t
@@ -121,13 +121,13 @@
 
   $ cat .hg/blackbox.log
   *> cacher constructed for manifestdata (glob)
-  *> cache miss for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
-  *> storing cache entry for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
+  *> cache miss for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
+  *> storing cache entry for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
   *> cacher constructed for manifestdata (glob)
-  *> cache hit for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
+  *> cache hit for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
   *> cacher constructed for manifestdata (glob)
-  *> cache miss for 1cf89363ec234c6b92d5961281eaa5713e7493f9 (glob)
-  *> storing cache entry for 1cf89363ec234c6b92d5961281eaa5713e7493f9 (glob)
+  *> cache miss for 37326a83e9843f15161fce9d1e92d06b795d5e8e (glob)
+  *> storing cache entry for 37326a83e9843f15161fce9d1e92d06b795d5e8e (glob)
 
   $ cat error.log
 
@@ -188,10 +188,10 @@
 
   $ cat .hg/blackbox.log
   *> cacher constructed for manifestdata (glob)
-  *> cache miss for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
-  *> storing cache entry for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
+  *> cache miss for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
+  *> storing cache entry for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
   *> cacher constructed for manifestdata (glob)
-  *> cache hit for 64b3162af49ea3c88e8ce2785e03ed7b88a2d6ca (glob)
+  *> cache hit for 47abb8efa5f01b8964d74917793ad2464db0fa2c (glob)
 
   $ cat error.log
 
@@ -235,20 +235,9 @@
                 b'revision'
               ])
             },
-            b'noderange': {
-              b'default': None,
-              b'required': False,
+            b'revisions': {
+              b'required': True,
               b'type': b'list'
-            },
-            b'nodes': {
-              b'default': None,
-              b'required': False,
-              b'type': b'list'
-            },
-            b'nodesdepth': {
-              b'default': None,
-              b'required': False,
-              b'type': b'int'
             }
           },
           b'permissions': [
@@ -416,7 +405,7 @@
 
   $ cat .hg/blackbox.log
   *> cacher constructed for manifestdata (glob)
-  *> cache miss for 904560928eb95650358f0829d9399b256822eb26 (glob)
+  *> cache miss for 2cba2a7d0d1575fea2fe68f597e97a7c2ac2f705 (glob)
   *> cacher exiting due to error (glob)
 
   $ killdaemons.py
diff --git a/tests/test-ssh.t b/tests/test-ssh.t
--- a/tests/test-ssh.t
+++ b/tests/test-ssh.t
@@ -508,13 +508,13 @@
   $ hg pull --debug ssh://user@dummy/remote --config devel.debug.peer-request=yes
   pulling from ssh://user@dummy/remote
   running .* ".*/dummyssh" ['"]user at dummy['"] ('|")hg -R remote serve --stdio('|") (re)
-  sending upgrade request: * proto=exp-ssh-v2-0002 (glob) (sshv2 !)
+  sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
   devel-peer-request: hello+between
   devel-peer-request:   pairs: 81 bytes
   sending hello command
   sending between command
   remote: 427 (sshv1 !)
-  protocol upgraded to exp-ssh-v2-0002 (sshv2 !)
+  protocol upgraded to exp-ssh-v2-0003 (sshv2 !)
   remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
   remote: 1 (sshv1 !)
   devel-peer-request: protocaps
diff --git a/tests/test-ssh-proto.t b/tests/test-ssh-proto.t
--- a/tests/test-ssh-proto.t
+++ b/tests/test-ssh-proto.t
@@ -954,7 +954,7 @@
   $ hg --config experimental.sshpeer.advertise-v2=true --debug debugpeer ssh://user@dummy/server
   running * "*/tests/dummyssh" 'user at dummy' 'hg -R server serve --stdio' (glob) (no-windows !)
   running * "*\tests/dummyssh" "user at dummy" "hg -R server serve --stdio" (glob) (windows !)
-  sending upgrade request: * proto=exp-ssh-v2-0002 (glob)
+  sending upgrade request: * proto=exp-ssh-v2-0003 (glob)
   devel-peer-request: hello+between
   devel-peer-request:   pairs: 81 bytes
   sending hello command
@@ -984,7 +984,7 @@
 
   $ hg debugwireproto --localssh --peer raw << EOF
   > raw
-  >     upgrade this-is-some-token proto=exp-ssh-v2-0002\n
+  >     upgrade this-is-some-token proto=exp-ssh-v2-0003\n
   >     hello\n
   >     between\n
   >     pairs 81\n
@@ -995,13 +995,13 @@
   > EOF
   using raw connection to peer
   i> write(153) -> 153:
-  i>     upgrade this-is-some-token proto=exp-ssh-v2-0002\n
+  i>     upgrade this-is-some-token proto=exp-ssh-v2-0003\n
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   o> readline() -> 44:
-  o>     upgraded this-is-some-token exp-ssh-v2-0002\n
+  o>     upgraded this-is-some-token exp-ssh-v2-0003\n
   o> readline() -> 4:
   o>     426\n
   o> readline() -> 427:
@@ -1012,12 +1012,12 @@
   $ hg --config experimental.sshpeer.advertise-v2=true --debug debugpeer ssh://user@dummy/server
   running * "*/tests/dummyssh" 'user at dummy' 'hg -R server serve --stdio' (glob) (no-windows !)
   running * "*\tests/dummyssh" "user at dummy" "hg -R server serve --stdio" (glob) (windows !)
-  sending upgrade request: * proto=exp-ssh-v2-0002 (glob)
+  sending upgrade request: * proto=exp-ssh-v2-0003 (glob)
   devel-peer-request: hello+between
   devel-peer-request:   pairs: 81 bytes
   sending hello command
   sending between command
-  protocol upgraded to exp-ssh-v2-0002
+  protocol upgraded to exp-ssh-v2-0003
   remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
   devel-peer-request: protocaps
   devel-peer-request:   caps: * bytes (glob)
@@ -1031,12 +1031,12 @@
   $ hg --config experimental.sshpeer.advertise-v2=true --debug debugcapabilities ssh://user@dummy/server
   running * "*/tests/dummyssh" 'user at dummy' 'hg -R server serve --stdio' (glob) (no-windows !)
   running * "*\tests/dummyssh" "user at dummy" "hg -R server serve --stdio" (glob) (windows !)
-  sending upgrade request: * proto=exp-ssh-v2-0002 (glob)
+  sending upgrade request: * proto=exp-ssh-v2-0003 (glob)
   devel-peer-request: hello+between
   devel-peer-request:   pairs: 81 bytes
   sending hello command
   sending between command
-  protocol upgraded to exp-ssh-v2-0002
+  protocol upgraded to exp-ssh-v2-0003
   remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
   devel-peer-request: protocaps
   devel-peer-request:   caps: * bytes (glob)
@@ -1087,7 +1087,7 @@
 
   $ hg debugwireproto --localssh --peer raw << EOF
   > raw
-  >      upgrade this-is-some-token proto=exp-ssh-v2-0002\n
+  >      upgrade this-is-some-token proto=exp-ssh-v2-0003\n
   >      hello\n
   >      between\n
   >      pairs 81\n
@@ -1102,13 +1102,13 @@
   > EOF
   using raw connection to peer
   i> write(153) -> 153:
-  i>     upgrade this-is-some-token proto=exp-ssh-v2-0002\n
+  i>     upgrade this-is-some-token proto=exp-ssh-v2-0003\n
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   o> readline() -> 44:
-  o>     upgraded this-is-some-token exp-ssh-v2-0002\n
+  o>     upgraded this-is-some-token exp-ssh-v2-0003\n
   o> readline() -> 4:
   o>     426\n
   o> readline() -> 427:
@@ -1124,7 +1124,7 @@
 
   $ hg debugwireproto --localssh --peer raw << EOF
   > raw
-  >     upgrade this-is-some-token proto=exp-ssh-v2-0002\n
+  >     upgrade this-is-some-token proto=exp-ssh-v2-0003\n
   >     hello\n
   >     between\n
   >     pairs 81\n
@@ -1140,13 +1140,13 @@
   > EOF
   using raw connection to peer
   i> write(153) -> 153:
-  i>     upgrade this-is-some-token proto=exp-ssh-v2-0002\n
+  i>     upgrade this-is-some-token proto=exp-ssh-v2-0003\n
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   o> readline() -> 44:
-  o>     upgraded this-is-some-token exp-ssh-v2-0002\n
+  o>     upgraded this-is-some-token exp-ssh-v2-0003\n
   o> readline() -> 4:
   o>     426\n
   o> readline() -> 427:
@@ -1236,14 +1236,14 @@
 
   $ hg debugwireproto --localssh --peer raw << EOF
   > raw
-  >     upgrade token proto=exp-ssh-v2-0002\n
+  >     upgrade token proto=exp-ssh-v2-0003\n
   >     invalid\n
   > readline
   > readavailable
   > EOF
   using raw connection to peer
   i> write(44) -> 44:
-  i>     upgrade token proto=exp-ssh-v2-0002\n
+  i>     upgrade token proto=exp-ssh-v2-0003\n
   i>     invalid\n
   o> readline() -> 1:
   o>     \n
@@ -1253,15 +1253,15 @@
 
   $ hg debugwireproto --localssh --peer raw << EOF
   > raw
-  >     upgrade token proto=exp-ssh-v2-0002\n
+  >     upgrade token proto=exp-ssh-v2-0003\n
   >     hello\n
   >     invalid\n
   > readline
   > readavailable
   > EOF
   using raw connection to peer
   i> write(50) -> 50:
-  i>     upgrade token proto=exp-ssh-v2-0002\n
+  i>     upgrade token proto=exp-ssh-v2-0003\n
   i>     hello\n
   i>     invalid\n
   o> readline() -> 1:
@@ -1272,16 +1272,16 @@
 
   $ hg debugwireproto --localssh --peer raw << EOF
   > raw
-  >     upgrade token proto=exp-ssh-v2-0002\n
+  >     upgrade token proto=exp-ssh-v2-0003\n
   >     hello\n
   >     between\n
   >     invalid\n
   > readline
   > readavailable
   > EOF
   using raw connection to peer
   i> write(58) -> 58:
-  i>     upgrade token proto=exp-ssh-v2-0002\n
+  i>     upgrade token proto=exp-ssh-v2-0003\n
   i>     hello\n
   i>     between\n
   i>     invalid\n
@@ -1368,14 +1368,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -1448,14 +1448,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -1512,14 +1512,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -1582,14 +1582,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -1661,14 +1661,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -1746,14 +1746,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -1834,14 +1834,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -1909,14 +1909,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -1979,14 +1979,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -2058,14 +2058,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -2164,14 +2164,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
diff --git a/tests/test-ssh-proto-unbundle.t b/tests/test-ssh-proto-unbundle.t
--- a/tests/test-ssh-proto-unbundle.t
+++ b/tests/test-ssh-proto-unbundle.t
@@ -100,14 +100,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -285,14 +285,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -412,14 +412,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -539,14 +539,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -666,14 +666,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -796,14 +796,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -925,14 +925,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -1054,14 +1054,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -1186,14 +1186,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -1322,14 +1322,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -1451,14 +1451,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -1584,14 +1584,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -1729,14 +1729,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -1858,14 +1858,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
@@ -1992,14 +1992,14 @@
   testing ssh2
   creating ssh peer from handshake results
   i> write(171) -> 171:
-  i>     upgrade * proto=exp-ssh-v2-0002\n (glob)
+  i>     upgrade * proto=exp-ssh-v2-0003\n (glob)
   i>     hello\n
   i>     between\n
   i>     pairs 81\n
   i>     0000000000000000000000000000000000000000-0000000000000000000000000000000000000000
   i> flush() -> None
   o> readline() -> 62:
-  o>     upgraded * exp-ssh-v2-0002\n (glob)
+  o>     upgraded * exp-ssh-v2-0003\n (glob)
   o> readline() -> 4:
   o>     426\n
   o> read(426) -> 426: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
diff --git a/tests/test-ssh-bundle1.t b/tests/test-ssh-bundle1.t
--- a/tests/test-ssh-bundle1.t
+++ b/tests/test-ssh-bundle1.t
@@ -479,11 +479,11 @@
   $ hg pull --debug ssh://user@dummy/remote
   pulling from ssh://user@dummy/remote
   running .* ".*/dummyssh" ['"]user at dummy['"] ('|")hg -R remote serve --stdio('|") (re)
-  sending upgrade request: * proto=exp-ssh-v2-0002 (glob) (sshv2 !)
+  sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
   sending hello command
   sending between command
   remote: 427 (sshv1 !)
-  protocol upgraded to exp-ssh-v2-0002 (sshv2 !)
+  protocol upgraded to exp-ssh-v2-0003 (sshv2 !)
   remote: capabilities: batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset getbundle known lookup protocaps pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
   remote: 1 (sshv1 !)
   sending protocaps command
diff --git a/tests/test-http-protocol.t b/tests/test-http-protocol.t
--- a/tests/test-http-protocol.t
+++ b/tests/test-http-protocol.t
@@ -254,7 +254,7 @@
   s>     Accept-Encoding: identity\r\n
   s>     vary: X-HgProto-1,X-HgUpgrade-1\r\n
   s>     x-hgproto-1: cbor\r\n
-  s>     x-hgupgrade-1: exp-http-v2-0002\r\n
+  s>     x-hgupgrade-1: exp-http-v2-0003\r\n
   s>     accept: application/mercurial-0.1\r\n
   s>     host: $LOCALIP:$HGPORT\r\n (glob)
   s>     user-agent: Mercurial debugwireproto\r\n
@@ -303,7 +303,7 @@
   s>     Accept-Encoding: identity\r\n
   s>     vary: X-HgProto-1,X-HgUpgrade-1\r\n
   s>     x-hgproto-1: cbor\r\n
-  s>     x-hgupgrade-1: exp-http-v2-0002\r\n
+  s>     x-hgupgrade-1: exp-http-v2-0003\r\n
   s>     accept: application/mercurial-0.1\r\n
   s>     host: $LOCALIP:$HGPORT\r\n (glob)
   s>     user-agent: Mercurial debugwireproto\r\n
@@ -315,9 +315,9 @@
   s>     Content-Type: application/mercurial-cbor\r\n
   s>     Content-Length: *\r\n (glob)
   s>     \r\n
-  s>     \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0002\xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionInoderange\xa3Gdefault\xf6Hrequired\xf4DtypeDlistEnodes\xa3Gdefault\xf6Hrequired\xf4DtypeDlistJnodesdepth\xa3Gdefault\xf6Hrequired\xf4DtypeCintKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
+  s>     \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0003\xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa2Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x84IbookmarksGparentsEphaseHrevisionIrevisions\xa2Hrequired\xf5DtypeDlistKpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDpath\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xa3Gdefault\xf4Hrequired\xf4DtypeDboolKpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\xa3Gdefault\x80Hrequired\xf4DtypeDlistKpermissions\x81DpullHlistkeys\xa2Dargs\xa1Inamespace\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullFlookup\xa2Dargs\xa1Ckey\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullLmanifestdata\xa3Dargs\xa4Ffields\xa4Gdefault\xd9\x01\x02\x80Hrequired\xf4DtypeCsetKvalidvalues\xd9\x01\x02\x82GparentsHrevisionKhaveparents\xa3Gdefault\xf4Hrequired\xf4DtypeDboolEnodes\xa2Hrequired\xf5DtypeDlistDtree\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpullTrecommendedbatchsize\x1a\x00\x01\x86\xa0Gpushkey\xa2Dargs\xa4Ckey\xa2Hrequired\xf5DtypeEbytesInamespace\xa2Hrequired\xf5DtypeEbytesCnew\xa2Hrequired\xf5DtypeEbytesCold\xa2Hrequired\xf5DtypeEbytesKpermissions\x81DpushQframingmediatypes\x81X&application/mercurial-exp-framing-0006Rpathfilterprefixes\xd9\x01\x02\x82Epath:Lrootfilesin:Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xd3batch branchmap $USUAL_BUNDLE2_CAPS$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
   sending heads command
-  s>     POST /api/exp-http-v2-0002/ro/heads HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/ro/heads HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     accept: application/mercurial-exp-framing-0006\r\n
   s>     content-type: application/mercurial-exp-framing-0006\r\n
diff --git a/tests/test-http-api.t b/tests/test-http-api.t
--- a/tests/test-http-api.t
+++ b/tests/test-http-api.t
@@ -218,11 +218,11 @@
 Accessing a known but not enabled API yields a different error
 
   $ send << EOF
-  > httprequest GET api/exp-http-v2-0002
+  > httprequest GET api/exp-http-v2-0003
   >     user-agent: test
   > EOF
   using raw connection to peer
-  s>     GET /api/exp-http-v2-0002 HTTP/1.1\r\n
+  s>     GET /api/exp-http-v2-0003 HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     user-agent: test\r\n
   s>     host: $LOCALIP:$HGPORT\r\n (glob)
@@ -234,7 +234,7 @@
   s>     Content-Type: text/plain\r\n
   s>     Content-Length: 33\r\n
   s>     \r\n
-  s>     API exp-http-v2-0002 not enabled\n
+  s>     API exp-http-v2-0003 not enabled\n
 
 Restart server with support for HTTP v2 API
 
@@ -269,7 +269,7 @@
   s>     \r\n
   s>     APIs can be accessed at /api/<name>, where <name> can be one of the following:\n
   s>     \n
-  s>     exp-http-v2-0002
+  s>     exp-http-v2-0003
 
   $ send << EOF
   > httprequest GET api/
@@ -290,4 +290,4 @@
   s>     \r\n
   s>     APIs can be accessed at /api/<name>, where <name> can be one of the following:\n
   s>     \n
-  s>     exp-http-v2-0002
+  s>     exp-http-v2-0003
diff --git a/tests/test-http-api-httpv2.t b/tests/test-http-api-httpv2.t
--- a/tests/test-http-api-httpv2.t
+++ b/tests/test-http-api-httpv2.t
@@ -18,7 +18,7 @@
   >     user-agent: test
   > EOF
   using raw connection to peer
-  s>     GET /api/exp-http-v2-0002 HTTP/1.1\r\n
+  s>     GET /api/exp-http-v2-0003 HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     user-agent: test\r\n
   s>     host: $LOCALIP:$HGPORT\r\n (glob)
@@ -30,7 +30,7 @@
   s>     Content-Type: text/plain\r\n
   s>     Content-Length: 33\r\n
   s>     \r\n
-  s>     API exp-http-v2-0002 not enabled\n
+  s>     API exp-http-v2-0003 not enabled\n
 
 Restart server with support for HTTP v2 API
 
@@ -46,7 +46,7 @@
   >     user-agent: test
   > EOF
   using raw connection to peer
-  s>     POST /api/exp-http-v2-0002/ro/badcommand HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/ro/badcommand HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     user-agent: test\r\n
   s>     host: $LOCALIP:$HGPORT\r\n (glob)
@@ -67,7 +67,7 @@
   >     user-agent: test
   > EOF
   using raw connection to peer
-  s>     GET /api/exp-http-v2-0002/ro/customreadonly HTTP/1.1\r\n
+  s>     GET /api/exp-http-v2-0003/ro/customreadonly HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     user-agent: test\r\n
   s>     host: $LOCALIP:$HGPORT\r\n (glob)
@@ -88,7 +88,7 @@
   >     user-agent: test
   > EOF
   using raw connection to peer
-  s>     POST /api/exp-http-v2-0002/ro/customreadonly HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/ro/customreadonly HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     user-agent: test\r\n
   s>     host: $LOCALIP:$HGPORT\r\n (glob)
@@ -110,7 +110,7 @@
   >     user-agent: test
   > EOF
   using raw connection to peer
-  s>     POST /api/exp-http-v2-0002/ro/customreadonly HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/ro/customreadonly HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     accept: invalid\r\n
   s>     user-agent: test\r\n
@@ -134,7 +134,7 @@
   >     content-type: badmedia
   > EOF
   using raw connection to peer
-  s>     POST /api/exp-http-v2-0002/ro/customreadonly HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/ro/customreadonly HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     accept: application/mercurial-exp-framing-0006\r\n
   s>     content-type: badmedia\r\n
@@ -160,7 +160,7 @@
   >     frame 1 1 stream-begin command-request new cbor:{b'name': b'customreadonly'}
   > EOF
   using raw connection to peer
-  s>     POST /api/exp-http-v2-0002/ro/customreadonly HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/ro/customreadonly HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     *\r\n (glob)
   s>     content-type: application/mercurial-exp-framing-0006\r\n
@@ -196,7 +196,7 @@
   > EOF
   creating http peer for wire protocol version 2
   sending customreadonly command
-  s>     POST /api/exp-http-v2-0002/ro/customreadonly HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/ro/customreadonly HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     accept: application/mercurial-exp-framing-0006\r\n
   s>     content-type: application/mercurial-exp-framing-0006\r\n
@@ -247,7 +247,7 @@
   >     user-agent: test
   > EOF
   using raw connection to peer
-  s>     GET /api/exp-http-v2-0002/rw/customreadonly HTTP/1.1\r\n
+  s>     GET /api/exp-http-v2-0003/rw/customreadonly HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     user-agent: test\r\n
   s>     host: $LOCALIP:$HGPORT\r\n (glob)
@@ -268,7 +268,7 @@
   >     user-agent: test
   > EOF
   using raw connection to peer
-  s>     GET /api/exp-http-v2-0002/rw/badcommand HTTP/1.1\r\n
+  s>     GET /api/exp-http-v2-0003/rw/badcommand HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     user-agent: test\r\n
   s>     host: $LOCALIP:$HGPORT\r\n (glob)
@@ -289,7 +289,7 @@
   >     user-agent: test
   > EOF
   using raw connection to peer
-  s>     POST /api/exp-http-v2-0002/rw/customreadonly HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/rw/customreadonly HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     user-agent: test\r\n
   s>     host: $LOCALIP:$HGPORT\r\n (glob)
@@ -327,7 +327,7 @@
   >     frame 1 1 stream-begin command-request new cbor:{b'name': b'customreadonly'}
   > EOF
   using raw connection to peer
-  s>     POST /api/exp-http-v2-0002/rw/customreadonly HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/rw/customreadonly HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     accept: application/mercurial-exp-framing-0006\r\n
   s>     content-type: application/mercurial-exp-framing-0006\r\n
@@ -366,7 +366,7 @@
   >     accept: $MEDIATYPE
   > EOF
   using raw connection to peer
-  s>     POST /api/exp-http-v2-0002/rw/badcommand HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/rw/badcommand HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     accept: application/mercurial-exp-framing-0006\r\n
   s>     user-agent: test\r\n
@@ -388,7 +388,7 @@
   >     user-agent: test
   > EOF
   using raw connection to peer
-  s>     POST /api/exp-http-v2-0002/ro/debugreflect HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/ro/debugreflect HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     user-agent: test\r\n
   s>     host: $LOCALIP:$HGPORT\r\n (glob)
@@ -428,7 +428,7 @@
   >     frame 1 1 stream-begin command-request new cbor:{b'name': b'command1', b'args': {b'foo': b'val1', b'bar1': b'val'}}
   > EOF
   using raw connection to peer
-  s>     POST /api/exp-http-v2-0002/ro/debugreflect HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/ro/debugreflect HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     accept: application/mercurial-exp-framing-0006\r\n
   s>     content-type: application/mercurial-exp-framing-0006\r\n
@@ -459,7 +459,7 @@
   >     frame 1 1 stream-begin command-request new cbor:{b'name': b'customreadonly'}
   > EOF
   using raw connection to peer
-  s>     POST /api/exp-http-v2-0002/ro/customreadonly HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/ro/customreadonly HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     accept: application/mercurial-exp-framing-0006\r\n
   s>     content-type: application/mercurial-exp-framing-0006\r\n
@@ -501,7 +501,7 @@
   >     frame 3 1 0 command-request new cbor:{b'name': b'customreadonly'}
   > EOF
   using raw connection to peer
-  s>     POST /api/exp-http-v2-0002/ro/multirequest HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/ro/multirequest HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     *\r\n (glob)
   s>     *\r\n (glob)
@@ -554,7 +554,7 @@
   >     frame 1 1 0 command-request continuation IbookmarksDnameHlistkeys
   > EOF
   using raw connection to peer
-  s>     POST /api/exp-http-v2-0002/ro/multirequest HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/ro/multirequest HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     accept: application/mercurial-exp-framing-0006\r\n
   s>     content-type: application/mercurial-exp-framing-0006\r\n
@@ -619,7 +619,7 @@
   >     frame 1 1 stream-begin command-request new cbor:{b'name': b'pushkey'}
   > EOF
   using raw connection to peer
-  s>     POST /api/exp-http-v2-0002/ro/multirequest HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/ro/multirequest HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     accept: application/mercurial-exp-framing-0006\r\n
   s>     content-type: application/mercurial-exp-framing-0006\r\n
@@ -645,7 +645,7 @@
   creating http peer for wire protocol version 2
   sending heads command
   wire protocol version 2 encoder referenced in config (badencoder) is not known; ignoring
-  s>     POST /api/exp-http-v2-0002/ro/heads HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/ro/heads HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     accept: application/mercurial-exp-framing-0006\r\n
   s>     content-type: application/mercurial-exp-framing-0006\r\n
@@ -694,7 +694,7 @@
   > EOF
   creating http peer for wire protocol version 2
   sending heads command
-  s>     POST /api/exp-http-v2-0002/ro/heads HTTP/1.1\r\n
+  s>     POST /api/exp-http-v2-0003/ro/heads HTTP/1.1\r\n
   s>     Accept-Encoding: identity\r\n
   s>     accept: application/mercurial-exp-framing-0006\r\n
   s>     content-type: application/mercurial-exp-framing-0006\r\n
diff --git a/tests/test-clone.t b/tests/test-clone.t
--- a/tests/test-clone.t
+++ b/tests/test-clone.t
@@ -1177,38 +1177,38 @@
 #if windows
   $ hg clone "ssh://%26touch%20owned%20/" --debug
   running sh -c "read l; read l; read l" "&touch owned " "hg -R . serve --stdio"
-  sending upgrade request: * proto=exp-ssh-v2-0002 (glob) (sshv2 !)
+  sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
   sending hello command
   sending between command
   abort: no suitable response from remote hg!
   [255]
   $ hg clone "ssh://example.com:%26touch%20owned%20/" --debug
   running sh -c "read l; read l; read l" -p "&touch owned " example.com "hg -R . serve --stdio"
-  sending upgrade request: * proto=exp-ssh-v2-0002 (glob) (sshv2 !)
+  sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
   sending hello command
   sending between command
   abort: no suitable response from remote hg!
   [255]
 #else
   $ hg clone "ssh://%3btouch%20owned%20/" --debug
   running sh -c "read l; read l; read l" ';touch owned ' 'hg -R . serve --stdio'
-  sending upgrade request: * proto=exp-ssh-v2-0002 (glob) (sshv2 !)
+  sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
   sending hello command
   sending between command
   abort: no suitable response from remote hg!
   [255]
   $ hg clone "ssh://example.com:%3btouch%20owned%20/" --debug
   running sh -c "read l; read l; read l" -p ';touch owned ' example.com 'hg -R . serve --stdio'
-  sending upgrade request: * proto=exp-ssh-v2-0002 (glob) (sshv2 !)
+  sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
   sending hello command
   sending between command
   abort: no suitable response from remote hg!
   [255]
 #endif
 
   $ hg clone "ssh://v-alid.example.com/" --debug
   running sh -c "read l; read l; read l" v-alid\.example\.com ['"]hg -R \. serve --stdio['"] (re)
-  sending upgrade request: * proto=exp-ssh-v2-0002 (glob) (sshv2 !)
+  sending upgrade request: * proto=exp-ssh-v2-0003 (glob) (sshv2 !)
   sending hello command
   sending between command
   abort: no suitable response from remote hg!
diff --git a/mercurial/wireprotov2server.py b/mercurial/wireprotov2server.py
--- a/mercurial/wireprotov2server.py
+++ b/mercurial/wireprotov2server.py
@@ -777,6 +777,78 @@
     """
     return None
 
+def resolvenodes(repo, revisions):
+    """Resolve nodes from a revisions specifier data structure."""
+    cl = repo.changelog
+    clhasnode = cl.hasnode
+
+    seen = set()
+    nodes = []
+
+    if not isinstance(revisions, list):
+        raise error.WireprotoCommandError('revisions must be defined as an '
+                                          'array')
+
+    for spec in revisions:
+        if b'type' not in spec:
+            raise error.WireprotoCommandError(
+                'type key not present in revision specifier')
+
+        typ = spec[b'type']
+
+        if typ == b'changesetexplicit':
+            if b'nodes' not in spec:
+                raise error.WireprotoCommandError(
+                    'nodes key not present in changesetexplicit revision '
+                    'specifier')
+
+            for node in spec[b'nodes']:
+                if node not in seen:
+                    nodes.append(node)
+                    seen.add(node)
+
+        elif typ == b'changesetexplicitdepth':
+            for key in (b'nodes', b'depth'):
+                if key not in spec:
+                    raise error.WireprotoCommandError(
+                        '%s key not present in changesetexplicitdepth revision '
+                        'specifier', (key,))
+
+            for rev in repo.revs(b'ancestors(%ln, %d)', spec[b'nodes'],
+                                 spec[b'depth'] - 1):
+                node = cl.node(rev)
+
+                if node not in seen:
+                    nodes.append(node)
+                    seen.add(node)
+
+        elif typ == b'changesetdagrange':
+            for key in (b'roots', b'heads'):
+                if key not in spec:
+                    raise error.WireprotoCommandError(
+                        '%s key not present in changesetdagrange revision '
+                        'specifier', (key,))
+
+            if not spec[b'heads']:
+                raise error.WireprotoCommandError(
+                    'heads key in changesetdagrange cannot be empty')
+
+            if spec[b'roots']:
+                common = [n for n in spec[b'roots'] if clhasnode(n)]
+            else:
+                common = [nullid]
+
+            for n in discovery.outgoing(repo, common, spec[b'heads']).missing:
+                if n not in seen:
+                    nodes.append(n)
+                    seen.add(n)
+
+        else:
+            raise error.WireprotoCommandError(
+                'unknown revision specifier type: %s', (typ,))
+
+    return nodes
+
 @wireprotocommand('branchmap', permission='pull')
 def branchmapv2(repo, proto):
     yield {encoding.fromlocal(k): v
@@ -789,20 +861,12 @@
 @wireprotocommand(
     'changesetdata',
     args={
-        'noderange': {
-            'type': 'list',
-            'default': lambda: None,
-            'example': [[b'0123456...'], [b'abcdef...']],
-        },
-        'nodes': {
+        'revisions': {
             'type': 'list',
-            'default': lambda: None,
-            'example': [b'0123456...'],
-        },
-        'nodesdepth': {
-            'type': 'int',
-            'default': lambda: None,
-            'example': 10,
+            'example': [{
+                b'type': b'changesetexplicit',
+                b'nodes': [b'abcdef...'],
+            }],
         },
         'fields': {
             'type': 'set',
@@ -812,57 +876,12 @@
         },
     },
     permission='pull')
-def changesetdata(repo, proto, noderange, nodes, nodesdepth, fields):
+def changesetdata(repo, proto, revisions, fields):
     # TODO look for unknown fields and abort when they can't be serviced.
     # This could probably be validated by dispatcher using validvalues.
 
-    if noderange is None and nodes is None:
-        raise error.WireprotoCommandError(
-            'noderange or nodes must be defined')
-
-    if nodesdepth is not None and nodes is None:
-        raise error.WireprotoCommandError(
-            'nodesdepth requires the nodes argument')
-
-    if noderange is not None:
-        if len(noderange) != 2:
-            raise error.WireprotoCommandError(
-                'noderange must consist of 2 elements')
-
-        if not noderange[1]:
-            raise error.WireprotoCommandError(
-                'heads in noderange request cannot be empty')
-
     cl = repo.changelog
-    hasnode = cl.hasnode
-
-    seen = set()
-    outgoing = []
-
-    if nodes is not None:
-        outgoing = [n for n in nodes if hasnode(n)]
-
-        if nodesdepth:
-            outgoing = [cl.node(r) for r in
-                        repo.revs(b'ancestors(%ln, %d)', outgoing,
-                                  nodesdepth - 1)]
-
-        seen |= set(outgoing)
-
-    if noderange is not None:
-        if noderange[0]:
-            common = [n for n in noderange[0] if hasnode(n)]
-        else:
-            common = [nullid]
-
-        for n in discovery.outgoing(repo, common, noderange[1]).missing:
-            if n not in seen:
-                outgoing.append(n)
-            # Don't need to add to seen here because this is the final
-            # source of nodes and there should be no duplicates in this
-            # list.
-
-    seen.clear()
+    outgoing = resolvenodes(repo, revisions)
     publishing = repo.publishing()
 
     if outgoing:
diff --git a/mercurial/wireprototypes.py b/mercurial/wireprototypes.py
--- a/mercurial/wireprototypes.py
+++ b/mercurial/wireprototypes.py
@@ -25,8 +25,8 @@
 SSHV1 = 'ssh-v1'
 # These are advertised over the wire. Increment the counters at the end
 # to reflect BC breakages.
-SSHV2 = 'exp-ssh-v2-0002'
-HTTP_WIREPROTO_V2 = 'exp-http-v2-0002'
+SSHV2 = 'exp-ssh-v2-0003'
+HTTP_WIREPROTO_V2 = 'exp-http-v2-0003'
 
 NARROWCAP = 'exp-narrow-1'
 ELLIPSESCAP = 'exp-ellipses-1'
diff --git a/mercurial/help/internals/wireprotocolv2.txt b/mercurial/help/internals/wireprotocolv2.txt
--- a/mercurial/help/internals/wireprotocolv2.txt
+++ b/mercurial/help/internals/wireprotocolv2.txt
@@ -144,22 +144,15 @@
 
 The command accepts the following arguments:
 
-noderange
-   (array of arrays of bytestrings) An array of 2 elements, each being an
-   array of node bytestrings. The first array denotes the changelog revisions
-   that are already known to the client. The second array denotes the changelog
-   revision DAG heads to fetch. The argument essentially defines a DAG range
-   bounded by root and head nodes to fetch.
+revisions
+   (array of maps) Specifies revisions whose data is being requested. Each
+   value in the array is a map describing revisions. See the
+   *Revisions Specifiers* section below for the format of this map.
 
-   The roots array may be empty. The heads array must be defined.
-
-nodes
-   (array of bytestrings) Changelog revisions to request explicitly.
+   Data will be sent for the union of all revisions resolved by all
+   revision specifiers.
 
-nodesdepth
-   (unsigned integer) Number of ancestor revisions of elements in ``nodes``
-   to also fetch. When defined, for each element in ``nodes``, DAG ancestors
-   will be walked until at most N total revisions are emitted.
+   Only revision specifiers operating on changeset revisions are allowed.
 
 fields
    (set of bytestring) Which data associated with changelog revisions to
@@ -178,10 +171,6 @@
       The raw, revision data for the changelog entry. The hash of this data
       will match the revision's node value.
 
-The server resolves the set of revisions relevant to the request by taking
-the union of the ``noderange`` and ``nodes`` arguments. At least one of these
-arguments must be defined.
-
 The response bytestream starts with a CBOR map describing the data that follows.
 This map has the following bytestring keys:
 
@@ -238,13 +227,6 @@
    ``secret``, ``draft``, and ``public``. Only present if ``phase`` data
    is being requested.
 
-If nodes are requested via ``noderange``, they will be emitted in DAG order,
-parents always before children.
-
-If nodes are requested via ``nodes``, they will be emitted in requested order.
-
-Nodes from ``nodes`` are emitted before nodes from ``noderange``.
-
 The set of changeset revisions emitted may not match the exact set of
 changesets requested. Furthermore, the set of keys present on each
 map may vary. This is to facilitate emitting changeset updates as well
@@ -540,3 +522,40 @@
 
 TODO consider using binary to represent nodes is certain pushkey namespaces.
 TODO better define response type and meaning.
+
+Revision Specifiers
+===================
+
+A *revision specifier* is a map that evaluates to a set of revisions.
+
+A *revision specifier* has a ``type`` key that defines the revision
+selection type to perform. Other keys in the map are used in a
+type-specific manner.
+
+The following types are defined:
+
+changesetexplicit
+   An explicit set of enumerated changeset revisions.
+
+   The ``nodes`` key MUST contain an array of full binary nodes, expressed
+   as bytestrings.
+
+changesetexplicitdepth
+   Like ``changesetexplicit``, but contains a ``depth`` key defining the
+   unsigned integer number of ancestor revisions to also resolve. For each
+   value in ``nodes``, DAG ancestors will be walked until up to N total
+   revisions from that ancestry walk are present in the final resolved set.
+
+changesetdagrange
+   Defines revisions via a DAG range of changesets on the changelog.
+
+   The ``roots`` key MUST contain an array of full, binary node values
+   representing the *root* revisions.
+
+   The ``heads`` key MUST contain an array of full, binary nodes values
+   representing the *head* revisions.
+
+   The DAG range between ``roots`` and ``heads`` will be resolved and all
+   revisions between will be used. Nodes in ``roots`` are not part of the
+   resolved set. Nodes in ``heads`` are. The ``roots`` array may be empty.
+   The ``heads`` array MUST be defined.
diff --git a/mercurial/exchangev2.py b/mercurial/exchangev2.py
--- a/mercurial/exchangev2.py
+++ b/mercurial/exchangev2.py
@@ -105,7 +105,11 @@
     # to smaller segments, etc.
     with remote.commandexecutor() as e:
         objs = e.callcommand(b'changesetdata', {
-            b'noderange': [sorted(common), sorted(remoteheads)],
+            b'revisions': [{
+                b'type': b'changesetdagrange',
+                b'roots': sorted(common),
+                b'heads': sorted(remoteheads),
+            }],
             b'fields': {b'bookmarks', b'parents', b'phase', b'revision'},
         }).result()
 



To: indygreg, #hg-reviewers
Cc: mercurial-devel


More information about the Mercurial-devel mailing list