'@'-prefixed canonical repo names for Bzlmod repos

See https://docs.google.com/document/d/1N81qfCa8oskCk5LqTW-LNthy6EBrDot7bdUsjz6JFC4/edit#heading=h.z37pyziy8h33

* RepositoryName syntax is relaxed to allow an extra '@' in the beginning, signifying that the RepositoryName should bypass RepositoryMapping
* All repos generated by Bzlmod will have an extra '@' prefixed to their names (except for well-known modules)
* TODO: strip the '@' when generating paths under $outputBase/external or $execRoot/external

Work towards https://github.com/bazelbuild/bazel/issues/15593.

RELNOTES: When Bzlmod is enabled, all Bzlmod-generated repos will have an extra '@' prepended to their names. This effectively enables the canonical label literal syntax for Bzlmod-generated repos (`@@canonicalRepoName//pkg:target`; see https://docs.google.com/document/d/1N81qfCa8oskCk5LqTW-LNthy6EBrDot7bdUsjz6JFC4/edit?usp=sharing).
PiperOrigin-RevId: 454156392
Change-Id: I2fb08495f066cfd15cc344534925f674a63764f6
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunction.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunction.java
index 2bb385e..f2f80ad 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunction.java
@@ -160,6 +160,11 @@
     for (ModuleExtensionId id : extensionUsagesById.rowKeySet()) {
       String bestName =
           id.getBzlFileLabel().getRepository().getName() + "." + id.getExtensionName();
+      if (!bestName.startsWith("@")) {
+        // We have to special-case extensions hosted in well-known modules, because *all* repos
+        // generated by Bzlmod have to have an '@'-prefixed name, except well-known modules.
+        bestName = "@" + bestName;
+      }
       if (extensionUniqueNames.putIfAbsent(bestName, id) == null) {
         continue;
       }
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleKey.java b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleKey.java
index 56843a1..25a756d 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleKey.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleKey.java
@@ -31,8 +31,16 @@
    * Therefore, we have to keep its canonical repository name the same as its well known repository
    * name. Eg. "@com_google_protobuf//:protoc" is used for --proto_compiler flag.
    *
-   * <p>TODO(pcloudy): Remove this hack after figuring out a correct way to deal with the above
-   * situation.
+   * <p>NOTE(wyv): We don't prepend an '@' to the repo names of well-known modules. This is because
+   * we still need the repo name to be 'bazel_tools' (not '@bazel_tools') since the command line
+   * flags still don't go through repo mapping yet, and they're asking for '@bazel_tools//:thing',
+   * not '@@bazel_tools//:thing'. We can't switch to the latter syntax because it doesn't work if
+   * Bzlmod is not enabled. On the other hand, this means we cannot write '@@bazel_tools//:thing' to
+   * bypass repo mapping at all, which can be awkward.
+   *
+   * <p>TODO(wyv): After we get rid of usage of com_google_protobuf in flag defaults, and make all
+   * flag values go through repo mapping, we can remove the concept of well-known modules
+   * altogether.
    */
   private static final ImmutableMap<String, RepositoryName> WELL_KNOWN_MODULES =
       ImmutableMap.of(
@@ -69,9 +77,7 @@
     if (ROOT.equals(this)) {
       return RepositoryName.MAIN;
     }
-    if (getVersion().isEmpty()) {
-      return RepositoryName.createUnvalidated(getName() + ".override");
-    }
-    return RepositoryName.createUnvalidated(getName() + "." + getVersion());
+    return RepositoryName.createUnvalidated(
+        String.format("@%s.%s", getName(), getVersion().isEmpty() ? "override" : getVersion()));
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/RepositoryMapping.java b/src/main/java/com/google/devtools/build/lib/cmdline/RepositoryMapping.java
index c65a3c4..7ef10d1 100644
--- a/src/main/java/com/google/devtools/build/lib/cmdline/RepositoryMapping.java
+++ b/src/main/java/com/google/devtools/build/lib/cmdline/RepositoryMapping.java
@@ -81,16 +81,20 @@
    * Returns the canonical repository name associated with the given apparent repo name. The
    * provided apparent repo name is assumed to be valid.
    */
-  public RepositoryName get(String apparentRepoName) {
-    RepositoryName canonicalRepoName = repositoryMapping().get(apparentRepoName);
+  public RepositoryName get(String preMappingName) {
+    if (preMappingName.startsWith("@")) {
+      // The given name is actually a canonical, post-mapping repo name already.
+      return RepositoryName.createUnvalidated(preMappingName);
+    }
+    RepositoryName canonicalRepoName = repositoryMapping().get(preMappingName);
     if (canonicalRepoName != null) {
       return canonicalRepoName;
     }
     // If the owner repo is not present, that means we should fall back to the requested repo name.
     if (ownerRepo() == null) {
-      return RepositoryName.createUnvalidated(apparentRepoName);
+      return RepositoryName.createUnvalidated(preMappingName);
     } else {
-      return RepositoryName.createUnvalidated(apparentRepoName).toNonVisible(ownerRepo());
+      return RepositoryName.createUnvalidated(preMappingName).toNonVisible(ownerRepo());
     }
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/cmdline/RepositoryName.java b/src/main/java/com/google/devtools/build/lib/cmdline/RepositoryName.java
index ac1814e..6035c90 100644
--- a/src/main/java/com/google/devtools/build/lib/cmdline/RepositoryName.java
+++ b/src/main/java/com/google/devtools/build/lib/cmdline/RepositoryName.java
@@ -37,7 +37,7 @@
 
   @SerializationConstant public static final RepositoryName MAIN = new RepositoryName("");
 
-  private static final Pattern VALID_REPO_NAME = Pattern.compile("[\\w\\-.]*");
+  private static final Pattern VALID_REPO_NAME = Pattern.compile("@?[\\w\\-.#]*");
 
   private static final LoadingCache<String, RepositoryName> repositoryNameCache =
       Caffeine.newBuilder()
@@ -49,8 +49,7 @@
               });
 
   /**
-   * Makes sure that name is a valid repository name and creates a new RepositoryName using it. The
-   * given string must not begin with a '@'.
+   * Makes sure that name is a valid repository name and creates a new RepositoryName using it.
    *
    * @throws LabelSyntaxException if the name is invalid
    */
@@ -66,11 +65,8 @@
     }
   }
 
-  /**
-   * Creates a RepositoryName from a known-valid string. The given string must not begin with a '@'.
-   */
+  /** Creates a RepositoryName from a known-valid string. */
   public static RepositoryName createUnvalidated(String name) {
-    Preconditions.checkArgument(!name.startsWith("@"), "Do not prefix @ to repo names!");
     if (name.isEmpty()) {
       // NOTE(wyv): Without this `if` clause, a lot of Google-internal integration tests would start
       //   failing. This suggests to me that something is comparing RepositoryName objects using
@@ -147,8 +143,8 @@
 
     if (!VALID_REPO_NAME.matcher(name).matches()) {
       throw LabelParser.syntaxErrorf(
-          "invalid repository name '@%s': repo names may contain only A-Z, a-z, 0-9, '-', '_' and"
-              + " '.'",
+          "invalid repository name '@%s': repo names may contain only A-Z, a-z, 0-9, '-', '_', '.'"
+              + " and '#'",
           StringUtilities.sanitizeControlChars(name));
     }
   }
diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunctionTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunctionTest.java
index 169e641..e3a8daa 100644
--- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BazelModuleResolutionFunctionTest.java
@@ -93,13 +93,13 @@
         .containsExactly(
             RepositoryName.MAIN,
             ModuleKey.ROOT,
-            RepositoryName.create("dep.1.0"),
+            RepositoryName.create("@dep.1.0"),
             createModuleKey("dep", "1.0"),
-            RepositoryName.create("dep.2.0"),
+            RepositoryName.create("@dep.2.0"),
             createModuleKey("dep", "2.0"),
-            RepositoryName.create("rules_cc.1.0"),
+            RepositoryName.create("@rules_cc.1.0"),
             createModuleKey("rules_cc", "1.0"),
-            RepositoryName.create("rules_java.override"),
+            RepositoryName.create("@rules_java.override"),
             createModuleKey("rules_java", ""));
     assertThat(value.getModuleNameLookup())
         .containsExactly(
@@ -156,15 +156,14 @@
 
     ModuleExtensionId maven =
         ModuleExtensionId.create(
-            Label.parseAbsoluteUnchecked("@rules_jvm_external.1.0//:defs.bzl"), "maven");
+            Label.parseCanonical("@@rules_jvm_external.1.0//:defs.bzl"), "maven");
     ModuleExtensionId pip =
-        ModuleExtensionId.create(
-            Label.parseAbsoluteUnchecked("@rules_python.2.0//:defs.bzl"), "pip");
+        ModuleExtensionId.create(Label.parseCanonical("@@rules_python.2.0//:defs.bzl"), "pip");
     ModuleExtensionId myext =
-        ModuleExtensionId.create(Label.parseAbsoluteUnchecked("@dep.2.0//:defs.bzl"), "myext");
+        ModuleExtensionId.create(Label.parseCanonical("@@dep.2.0//:defs.bzl"), "myext");
     ModuleExtensionId myext2 =
         ModuleExtensionId.create(
-            Label.parseAbsoluteUnchecked("@dep.2.0//incredible:conflict.bzl"), "myext");
+            Label.parseCanonical("@@dep.2.0//incredible:conflict.bzl"), "myext");
 
     BazelModuleResolutionValue value =
         BazelModuleResolutionFunction.createValue(depGraph, depGraph, ImmutableMap.of());
@@ -182,10 +181,10 @@
 
     assertThat(value.getExtensionUniqueNames())
         .containsExactly(
-            maven, "rules_jvm_external.1.0.maven",
-            pip, "rules_python.2.0.pip",
-            myext, "dep.2.0.myext",
-            myext2, "dep.2.0.myext2");
+            maven, "@rules_jvm_external.1.0.maven",
+            pip, "@rules_python.2.0.pip",
+            myext, "@dep.2.0.myext",
+            myext2, "@dep.2.0.myext2");
 
     assertThat(value.getFullRepoMapping(ModuleKey.ROOT))
         .isEqualTo(
@@ -196,26 +195,26 @@
                 "root",
                 "",
                 "rje",
-                "rules_jvm_external.1.0",
+                "@rules_jvm_external.1.0",
                 "rpy",
-                "rules_python.2.0",
+                "@rules_python.2.0",
                 "av",
-                "rules_jvm_external.1.0.maven.autovalue",
+                "@rules_jvm_external.1.0.maven.autovalue",
                 "numpy",
-                "rules_python.2.0.pip.numpy"));
+                "@rules_python.2.0.pip.numpy"));
     assertThat(value.getFullRepoMapping(depKey))
         .isEqualTo(
             createRepositoryMapping(
                 depKey,
                 "dep",
-                "dep.2.0",
+                "@dep.2.0",
                 "rules_python",
-                "rules_python.2.0",
+                "@rules_python.2.0",
                 "np",
-                "rules_python.2.0.pip.numpy",
+                "@rules_python.2.0.pip.numpy",
                 "oneext",
-                "dep.2.0.myext.myext",
+                "@dep.2.0.myext.myext",
                 "twoext",
-                "dep.2.0.myext2.myext"));
+                "@dep.2.0.myext2.myext"));
   }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelperTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelperTest.java
index 6cf8a7d..e93836b 100644
--- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelperTest.java
+++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/BzlmodRepoRuleHelperTest.java
@@ -147,17 +147,18 @@
     ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl()));
 
     EvaluationResult<GetRepoSpecByNameValue> result =
-        evaluator.evaluate(ImmutableList.of(getRepoSpecByNameKey("C.2.0")), evaluationContext);
+        evaluator.evaluate(ImmutableList.of(getRepoSpecByNameKey("@C.2.0")), evaluationContext);
     if (result.hasError()) {
       fail(result.getError().toString());
     }
 
-    Optional<RepoSpec> repoSpec = result.get(getRepoSpecByNameKey("C.2.0")).rule();
+    Optional<RepoSpec> repoSpec = result.get(getRepoSpecByNameKey("@C.2.0")).rule();
     assertThat(repoSpec)
         .hasValue(
             RepoSpec.builder()
                 .setRuleClassName("local_repository")
-                .setAttributes(ImmutableMap.of("name", "C.2.0", "path", "/usr/local/modules/C.2.0"))
+                .setAttributes(
+                    ImmutableMap.of("name", "@C.2.0", "path", "/usr/local/modules/@C.2.0"))
                 .build());
   }
 
@@ -178,19 +179,20 @@
     ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl()));
 
     EvaluationResult<GetRepoSpecByNameValue> result =
-        evaluator.evaluate(ImmutableList.of(getRepoSpecByNameKey("C.override")), evaluationContext);
+        evaluator.evaluate(
+            ImmutableList.of(getRepoSpecByNameKey("@C.override")), evaluationContext);
     if (result.hasError()) {
       fail(result.getError().toString());
     }
 
-    Optional<RepoSpec> repoSpec = result.get(getRepoSpecByNameKey("C.override")).rule();
+    Optional<RepoSpec> repoSpec = result.get(getRepoSpecByNameKey("@C.override")).rule();
     assertThat(repoSpec)
         .hasValue(
             RepoSpec.builder()
                 .setRuleClassName("local_repository")
                 .setAttributes(
                     ImmutableMap.of(
-                        "name", "C.override",
+                        "name", "@C.override",
                         "path", "/foo/bar/C"))
                 .build());
   }
@@ -214,12 +216,12 @@
     ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl()));
 
     EvaluationResult<GetRepoSpecByNameValue> result =
-        evaluator.evaluate(ImmutableList.of(getRepoSpecByNameKey("C.3.0")), evaluationContext);
+        evaluator.evaluate(ImmutableList.of(getRepoSpecByNameKey("@C.3.0")), evaluationContext);
     if (result.hasError()) {
       fail(result.getError().toString());
     }
 
-    Optional<RepoSpec> repoSpec = result.get(getRepoSpecByNameKey("C.3.0")).rule();
+    Optional<RepoSpec> repoSpec = result.get(getRepoSpecByNameKey("@C.3.0")).rule();
     assertThat(repoSpec)
         .hasValue(
             RepoSpec.builder()
@@ -230,9 +232,9 @@
                 .setAttributes(
                     ImmutableMap.of(
                         "name",
-                        "C.3.0",
+                        "@C.3.0",
                         "path",
-                        "/usr/local/modules/C.3.0",
+                        "/usr/local/modules/@C.3.0",
                         "patches",
                         ImmutableList.of("//:foo.patch"),
                         "patch_args",
@@ -262,17 +264,18 @@
     ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl()));
 
     EvaluationResult<GetRepoSpecByNameValue> result =
-        evaluator.evaluate(ImmutableList.of(getRepoSpecByNameKey("D.2.0")), evaluationContext);
+        evaluator.evaluate(ImmutableList.of(getRepoSpecByNameKey("@D.2.0")), evaluationContext);
     if (result.hasError()) {
       fail(result.getError().toString());
     }
 
-    Optional<RepoSpec> repoSpec = result.get(getRepoSpecByNameKey("D.2.0")).rule();
+    Optional<RepoSpec> repoSpec = result.get(getRepoSpecByNameKey("@D.2.0")).rule();
     assertThat(repoSpec)
         .hasValue(
             RepoSpec.builder()
                 .setRuleClassName("local_repository")
-                .setAttributes(ImmutableMap.of("name", "D.2.0", "path", "/usr/local/modules/D.2.0"))
+                .setAttributes(
+                    ImmutableMap.of("name", "@D.2.0", "path", "/usr/local/modules/@D.2.0"))
                 .build());
   }
 
diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleExtensionResolutionTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleExtensionResolutionTest.java
index 45b4d49..9aa7bd2 100644
--- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleExtensionResolutionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleExtensionResolutionTest.java
@@ -264,10 +264,10 @@
     // Set up a simple repo rule.
     registry.addModule(
         createModuleKey("data_repo", "1.0"), "module(name='data_repo',version='1.0')");
-    scratch.file(modulesRoot.getRelative("data_repo.1.0/WORKSPACE").getPathString());
-    scratch.file(modulesRoot.getRelative("data_repo.1.0/BUILD").getPathString());
+    scratch.file(modulesRoot.getRelative("@data_repo.1.0/WORKSPACE").getPathString());
+    scratch.file(modulesRoot.getRelative("@data_repo.1.0/BUILD").getPathString());
     scratch.file(
-        modulesRoot.getRelative("data_repo.1.0/defs.bzl").getPathString(),
+        modulesRoot.getRelative("@data_repo.1.0/defs.bzl").getPathString(),
         "def _data_repo_impl(ctx):",
         "  ctx.file('WORKSPACE')",
         "  ctx.file('BUILD')",
@@ -302,7 +302,7 @@
         "load('@bar//:data.bzl', bar_data='data')",
         "data = 'foo:'+foo_data+' bar:'+bar_data");
 
-    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseAbsoluteUnchecked("//:data.bzl"));
+    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseCanonical("//:data.bzl"));
     EvaluationResult<BzlLoadValue> result =
         evaluator.evaluate(ImmutableList.of(skyKey), evaluationContext);
     if (result.hasError()) {
@@ -358,10 +358,10 @@
         createModuleKey("ext", "1.0"),
         "module(name='ext',version='1.0')",
         "bazel_dep(name='data_repo',version='1.0')");
-    scratch.file(modulesRoot.getRelative("ext.1.0/WORKSPACE").getPathString());
-    scratch.file(modulesRoot.getRelative("ext.1.0/BUILD").getPathString());
+    scratch.file(modulesRoot.getRelative("@ext.1.0/WORKSPACE").getPathString());
+    scratch.file(modulesRoot.getRelative("@ext.1.0/BUILD").getPathString());
     scratch.file(
-        modulesRoot.getRelative("ext.1.0/defs.bzl").getPathString(),
+        modulesRoot.getRelative("@ext.1.0/defs.bzl").getPathString(),
         "load('@data_repo//:defs.bzl','data_repo')",
         "def _ext_impl(ctx):",
         "  data_str = 'modules:'",
@@ -372,7 +372,7 @@
         "tag=tag_class(attrs={'data':attr.string()})",
         "ext=module_extension(implementation=_ext_impl,tag_classes={'tag':tag})");
 
-    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseAbsoluteUnchecked("//:data.bzl"));
+    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseCanonical("//:data.bzl"));
     EvaluationResult<BzlLoadValue> result =
         evaluator.evaluate(ImmutableList.of(skyKey), evaluationContext);
     if (result.hasError()) {
@@ -415,10 +415,10 @@
         createModuleKey("ext", "1.0"),
         "module(name='ext',version='1.0')",
         "bazel_dep(name='data_repo',version='1.0')");
-    scratch.file(modulesRoot.getRelative("ext.1.0/WORKSPACE").getPathString());
-    scratch.file(modulesRoot.getRelative("ext.1.0/BUILD").getPathString());
+    scratch.file(modulesRoot.getRelative("@ext.1.0/WORKSPACE").getPathString());
+    scratch.file(modulesRoot.getRelative("@ext.1.0/BUILD").getPathString());
     scratch.file(
-        modulesRoot.getRelative("ext.1.0/defs.bzl").getPathString(),
+        modulesRoot.getRelative("@ext.1.0/defs.bzl").getPathString(),
         "load('@data_repo//:defs.bzl','data_repo')",
         "def _ext_impl(ctx):",
         "  data_str = 'modules:'",
@@ -429,7 +429,7 @@
         "tag=tag_class(attrs={'data':attr.string()})",
         "ext=module_extension(implementation=_ext_impl,tag_classes={'tag':tag})");
 
-    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseAbsoluteUnchecked("//:data.bzl"));
+    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseCanonical("//:data.bzl"));
     EvaluationResult<BzlLoadValue> result =
         evaluator.evaluate(ImmutableList.of(skyKey), evaluationContext);
     if (result.hasError()) {
@@ -466,10 +466,10 @@
         createModuleKey("ext", "1.0"),
         "module(name='ext',version='1.0')",
         "bazel_dep(name='data_repo',version='1.0')");
-    scratch.file(modulesRoot.getRelative("ext.1.0/WORKSPACE").getPathString());
-    scratch.file(modulesRoot.getRelative("ext.1.0/BUILD").getPathString());
+    scratch.file(modulesRoot.getRelative("@ext.1.0/WORKSPACE").getPathString());
+    scratch.file(modulesRoot.getRelative("@ext.1.0/BUILD").getPathString());
     scratch.file(
-        modulesRoot.getRelative("ext.1.0/defs.bzl").getPathString(),
+        modulesRoot.getRelative("@ext.1.0/defs.bzl").getPathString(),
         "load('@data_repo//:defs.bzl','data_repo')",
         "def _ext_impl(ctx):",
         "  data_str = 'modules:'",
@@ -483,7 +483,7 @@
     ModuleFileFunction.IGNORE_DEV_DEPS.set(differencer, true);
 
     SkyKey skyKey =
-        BzlLoadValue.keyForBuild(Label.parseAbsoluteUnchecked("@ext.1.0.ext.ext_repo//:data.bzl"));
+        BzlLoadValue.keyForBuild(Label.parseCanonical("@@ext.1.0.ext.ext_repo//:data.bzl"));
     EvaluationResult<BzlLoadValue> result =
         evaluator.evaluate(ImmutableList.of(skyKey), evaluationContext);
     if (result.hasError()) {
@@ -516,19 +516,19 @@
         "ext = use_extension('@ext//:defs.bzl','ext')",
         "ext.tag(file='@bar//:requirements.txt')");
     registry.addModule(createModuleKey("bar", "2.0"), "module(name='bar',version='2.0')");
-    scratch.file(modulesRoot.getRelative("bar.2.0/WORKSPACE").getPathString());
-    scratch.file(modulesRoot.getRelative("bar.2.0/BUILD").getPathString());
+    scratch.file(modulesRoot.getRelative("@bar.2.0/WORKSPACE").getPathString());
+    scratch.file(modulesRoot.getRelative("@bar.2.0/BUILD").getPathString());
     scratch.file(
-        modulesRoot.getRelative("bar.2.0/requirements.txt").getPathString(), "go to bed at 11pm.");
+        modulesRoot.getRelative("@bar.2.0/requirements.txt").getPathString(), "go to bed at 11pm.");
 
     registry.addModule(
         createModuleKey("ext", "1.0"),
         "module(name='ext',version='1.0')",
         "bazel_dep(name='data_repo',version='1.0')");
-    scratch.file(modulesRoot.getRelative("ext.1.0/WORKSPACE").getPathString());
-    scratch.file(modulesRoot.getRelative("ext.1.0/BUILD").getPathString());
+    scratch.file(modulesRoot.getRelative("@ext.1.0/WORKSPACE").getPathString());
+    scratch.file(modulesRoot.getRelative("@ext.1.0/BUILD").getPathString());
     scratch.file(
-        modulesRoot.getRelative("ext.1.0/defs.bzl").getPathString(),
+        modulesRoot.getRelative("@ext.1.0/defs.bzl").getPathString(),
         "load('@data_repo//:defs.bzl','data_repo')",
         "def _ext_impl(ctx):",
         "  data_str = 'requirements:'",
@@ -539,7 +539,7 @@
         "tag=tag_class(attrs={'file':attr.label()})",
         "ext=module_extension(implementation=_ext_impl,tag_classes={'tag':tag})");
 
-    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseAbsoluteUnchecked("//:data.bzl"));
+    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseCanonical("//:data.bzl"));
     EvaluationResult<BzlLoadValue> result =
         evaluator.evaluate(ImmutableList.of(skyKey), evaluationContext);
     if (result.hasError()) {
@@ -573,16 +573,16 @@
         "ext = use_extension('@ext//:defs.bzl','ext')",
         "ext.tag(file='@bar//:requirements.txt')");
     registry.addModule(createModuleKey("bar", "2.0"), "module(name='bar',version='2.0')");
-    scratch.file(modulesRoot.getRelative("bar.2.0/WORKSPACE").getPathString());
-    scratch.file(modulesRoot.getRelative("bar.2.0/BUILD").getPathString());
+    scratch.file(modulesRoot.getRelative("@bar.2.0/WORKSPACE").getPathString());
+    scratch.file(modulesRoot.getRelative("@bar.2.0/BUILD").getPathString());
     scratch.file(
-        modulesRoot.getRelative("bar.2.0/requirements.txt").getPathString(), "go to bed at 11pm.");
+        modulesRoot.getRelative("@bar.2.0/requirements.txt").getPathString(), "go to bed at 11pm.");
 
     registry.addModule(createModuleKey("ext", "1.0"), "module(name='ext',version='1.0')");
-    scratch.file(modulesRoot.getRelative("ext.1.0/WORKSPACE").getPathString());
-    scratch.file(modulesRoot.getRelative("ext.1.0/BUILD").getPathString());
+    scratch.file(modulesRoot.getRelative("@ext.1.0/WORKSPACE").getPathString());
+    scratch.file(modulesRoot.getRelative("@ext.1.0/BUILD").getPathString());
     scratch.file(
-        modulesRoot.getRelative("ext.1.0/defs.bzl").getPathString(),
+        modulesRoot.getRelative("@ext.1.0/defs.bzl").getPathString(),
         "def _data_repo_impl(ctx):",
         "  ctx.file('WORKSPACE')",
         "  ctx.file('BUILD')",
@@ -600,7 +600,7 @@
         "tag=tag_class(attrs={'file':attr.label()})",
         "ext=module_extension(implementation=_ext_impl,tag_classes={'tag':tag})");
 
-    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseAbsoluteUnchecked("//:data.bzl"));
+    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseCanonical("//:data.bzl"));
     EvaluationResult<BzlLoadValue> result =
         evaluator.evaluate(ImmutableList.of(skyKey), evaluationContext);
     if (result.hasError()) {
@@ -639,10 +639,10 @@
     scratch.file(workspaceRoot.getRelative("requirements.txt").getPathString(), "get up at 6am.");
 
     registry.addModule(createModuleKey("ext", "1.0"), "module(name='ext',version='1.0')");
-    scratch.file(modulesRoot.getRelative("ext.1.0/WORKSPACE").getPathString());
-    scratch.file(modulesRoot.getRelative("ext.1.0/BUILD").getPathString());
+    scratch.file(modulesRoot.getRelative("@ext.1.0/WORKSPACE").getPathString());
+    scratch.file(modulesRoot.getRelative("@ext.1.0/BUILD").getPathString());
     scratch.file(
-        modulesRoot.getRelative("ext.1.0/defs.bzl").getPathString(),
+        modulesRoot.getRelative("@ext.1.0/defs.bzl").getPathString(),
         "def _data_repo_impl(ctx):",
         "  ctx.file('WORKSPACE')",
         "  ctx.file('BUILD')",
@@ -660,7 +660,7 @@
         "tag=tag_class(attrs={'file':attr.label()})",
         "ext=module_extension(implementation=_ext_impl,tag_classes={'tag':tag})");
 
-    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseAbsoluteUnchecked("//:data.bzl"));
+    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseCanonical("//:data.bzl"));
     EvaluationResult<BzlLoadValue> result =
         evaluator.evaluate(ImmutableList.of(skyKey), evaluationContext);
     if (result.hasError()) {
@@ -684,15 +684,15 @@
         "data=ext_data");
 
     registry.addModule(createModuleKey("foo", "1.0"), "module(name='foo',version='1.0')");
-    scratch.file(modulesRoot.getRelative("foo.1.0/WORKSPACE").getPathString());
-    scratch.file(modulesRoot.getRelative("foo.1.0/BUILD").getPathString());
+    scratch.file(modulesRoot.getRelative("@foo.1.0/WORKSPACE").getPathString());
+    scratch.file(modulesRoot.getRelative("@foo.1.0/BUILD").getPathString());
     scratch.file(
-        modulesRoot.getRelative("foo.1.0/requirements.txt").getPathString(), "get up at 6am.");
+        modulesRoot.getRelative("@foo.1.0/requirements.txt").getPathString(), "get up at 6am.");
     registry.addModule(createModuleKey("bar", "2.0"), "module(name='bar',version='2.0')");
-    scratch.file(modulesRoot.getRelative("bar.2.0/WORKSPACE").getPathString());
-    scratch.file(modulesRoot.getRelative("bar.2.0/BUILD").getPathString());
+    scratch.file(modulesRoot.getRelative("@bar.2.0/WORKSPACE").getPathString());
+    scratch.file(modulesRoot.getRelative("@bar.2.0/BUILD").getPathString());
     scratch.file(
-        modulesRoot.getRelative("bar.2.0/requirements.txt").getPathString(), "go to bed at 11pm.");
+        modulesRoot.getRelative("@bar.2.0/requirements.txt").getPathString(), "go to bed at 11pm.");
 
     registry.addModule(
         createModuleKey("ext", "1.0"),
@@ -700,10 +700,10 @@
         "bazel_dep(name='foo',version='1.0')",
         "bazel_dep(name='bar',version='2.0')",
         "bazel_dep(name='data_repo',version='1.0')");
-    scratch.file(modulesRoot.getRelative("ext.1.0/WORKSPACE").getPathString());
-    scratch.file(modulesRoot.getRelative("ext.1.0/BUILD").getPathString());
+    scratch.file(modulesRoot.getRelative("@ext.1.0/WORKSPACE").getPathString());
+    scratch.file(modulesRoot.getRelative("@ext.1.0/BUILD").getPathString());
     scratch.file(
-        modulesRoot.getRelative("ext.1.0/defs.bzl").getPathString(),
+        modulesRoot.getRelative("@ext.1.0/defs.bzl").getPathString(),
         "load('@data_repo//:defs.bzl','data_repo')",
         "def _ext_impl(ctx):",
         // The Label() call on the following line should work, using ext.1.0's repo mapping.
@@ -716,7 +716,7 @@
         "tag=tag_class(attrs={'file':attr.label(default='@bar//:requirements.txt')})",
         "ext=module_extension(implementation=_ext_impl,tag_classes={'tag':tag})");
 
-    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseAbsoluteUnchecked("//:data.bzl"));
+    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseCanonical("//:data.bzl"));
     EvaluationResult<BzlLoadValue> result =
         evaluator.evaluate(ImmutableList.of(skyKey), evaluationContext);
     if (result.hasError()) {
@@ -752,7 +752,7 @@
         "load('@bar//:data.bzl', bar_data='data')",
         "data = 'foo:'+foo_data+' bar:'+bar_data");
 
-    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseAbsoluteUnchecked("//:data.bzl"));
+    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseCanonical("//:data.bzl"));
     EvaluationResult<BzlLoadValue> result =
         evaluator.evaluate(ImmutableList.of(skyKey), evaluationContext);
     if (result.hasError()) {
@@ -794,7 +794,7 @@
         "load('@bar//:data.bzl', bar_data='data')",
         "data = 'foo:'+foo_data+' bar:'+bar_data");
 
-    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseAbsoluteUnchecked("//:data.bzl"));
+    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseCanonical("//:data.bzl"));
     EvaluationResult<BzlLoadValue> result =
         evaluator.evaluate(ImmutableList.of(skyKey), evaluationContext);
     if (result.hasError()) {
@@ -840,11 +840,12 @@
         "ext=module_extension(implementation=_ext_impl,tag_classes={'tag':tag})");
 
     registry.addModule(createModuleKey("foo", "1.0"), "module(name='foo',version='1.0')");
-    scratch.file(modulesRoot.getRelative("foo.1.0/WORKSPACE").getPathString());
-    scratch.file(modulesRoot.getRelative("foo.1.0/BUILD").getPathString());
-    scratch.file(modulesRoot.getRelative("foo.1.0/data.bzl").getPathString(), "data = 'foo-stuff'");
+    scratch.file(modulesRoot.getRelative("@foo.1.0/WORKSPACE").getPathString());
+    scratch.file(modulesRoot.getRelative("@foo.1.0/BUILD").getPathString());
+    scratch.file(
+        modulesRoot.getRelative("@foo.1.0/data.bzl").getPathString(), "data = 'foo-stuff'");
 
-    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseAbsoluteUnchecked("//:data.bzl"));
+    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseCanonical("//:data.bzl"));
     EvaluationResult<BzlLoadValue> result =
         evaluator.evaluate(ImmutableList.of(skyKey), evaluationContext);
     if (result.hasError()) {
@@ -889,11 +890,12 @@
         "ext=module_extension(implementation=_ext_impl,tag_classes={'tag':tag})");
 
     registry.addModule(createModuleKey("foo", "1.0"), "module(name='foo',version='1.0')");
-    scratch.file(modulesRoot.getRelative("foo.1.0/WORKSPACE").getPathString());
-    scratch.file(modulesRoot.getRelative("foo.1.0/BUILD").getPathString());
-    scratch.file(modulesRoot.getRelative("foo.1.0/data.bzl").getPathString(), "data = 'outer-foo'");
+    scratch.file(modulesRoot.getRelative("@foo.1.0/WORKSPACE").getPathString());
+    scratch.file(modulesRoot.getRelative("@foo.1.0/BUILD").getPathString());
+    scratch.file(
+        modulesRoot.getRelative("@foo.1.0/data.bzl").getPathString(), "data = 'outer-foo'");
 
-    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseAbsoluteUnchecked("//:data.bzl"));
+    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseCanonical("//:data.bzl"));
     EvaluationResult<BzlLoadValue> result =
         evaluator.evaluate(ImmutableList.of(skyKey), evaluationContext);
     if (result.hasError()) {
@@ -927,13 +929,13 @@
         "tag=tag_class(attrs={'file':attr.label()})",
         "ext=module_extension(implementation=_ext_impl,tag_classes={'tag':tag})");
 
-    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseAbsoluteUnchecked("//:data.bzl"));
+    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseCanonical("//:data.bzl"));
     EvaluationResult<BzlLoadValue> result =
         evaluator.evaluate(ImmutableList.of(skyKey), evaluationContext);
     assertThat(result.hasError()).isTrue();
     assertThat(result.getError().getException())
         .hasMessageThat()
-        .contains("Repository '@foo' is not visible from repository '@.ext.ext'");
+        .contains("Repository '@foo' is not visible from repository '@@.ext.ext'");
   }
 
   @Test
@@ -948,7 +950,7 @@
         "load('@ext//:data.bzl', ext_data='data')",
         "data=ext_data");
 
-    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseAbsoluteUnchecked("//:data.bzl"));
+    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseCanonical("//:data.bzl"));
     EvaluationResult<BzlLoadValue> result =
         evaluator.evaluate(ImmutableList.of(skyKey), evaluationContext);
     assertThat(result.hasError()).isTrue();
@@ -978,7 +980,7 @@
         "load('@ext//:data.bzl', ext_data='data')",
         "data = ext_data");
 
-    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseAbsoluteUnchecked("//:data.bzl"));
+    SkyKey skyKey = BzlLoadValue.keyForBuild(Label.parseCanonical("//:data.bzl"));
     EvaluationResult<BzlLoadValue> result =
         evaluator.evaluate(ImmutableList.of(skyKey), evaluationContext);
     if (result.hasError()) {
diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileFunctionTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileFunctionTest.java
index 46b1157..a730b86 100644
--- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleFileFunctionTest.java
@@ -230,7 +230,7 @@
                     0));
     assertThat(rootModuleFileValue.getNonRegistryOverrideCanonicalRepoNameLookup())
         .containsExactly(
-            RepositoryName.create("E.override"), "E", RepositoryName.create("G.override"), "G");
+            RepositoryName.create("@E.override"), "E", RepositoryName.create("@G.override"), "G");
   }
 
   @Test
diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleTest.java
index 4e6d7c3..3aecdb9 100644
--- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleTest.java
+++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/ModuleTest.java
@@ -61,11 +61,11 @@
             createRepositoryMapping(
                 key,
                 "test_module",
-                "test_module.1.0",
+                "@test_module.1.0",
                 "my_foo",
-                "foo.1.0",
+                "@foo.1.0",
                 "my_bar",
-                "bar.2.0",
+                "@bar.2.0",
                 "my_root",
                 ""));
   }
@@ -87,8 +87,8 @@
                 "test_module",
                 "",
                 "my_foo",
-                "foo.1.0",
+                "@foo.1.0",
                 "my_bar",
-                "bar.2.0"));
+                "@bar.2.0"));
   }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/StarlarkBazelModuleTest.java b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/StarlarkBazelModuleTest.java
index 531da05..44dcd4d 100644
--- a/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/StarlarkBazelModuleTest.java
+++ b/src/test/java/com/google/devtools/build/lib/bazel/bzlmod/StarlarkBazelModuleTest.java
@@ -116,8 +116,8 @@
     assertThat(pomTags.get(0).getValue("pom_xmls"))
         .isEqualTo(
             StarlarkList.immutableOf(
-                Label.parseAbsoluteUnchecked("@foo.override//:pom.xml"),
-                Label.parseAbsoluteUnchecked("@bar.2.0//:pom.xml")));
+                Label.parseCanonical("@@foo.override//:pom.xml"),
+                Label.parseCanonical("@@bar.2.0//:pom.xml")));
   }
 
   @Test
diff --git a/src/test/java/com/google/devtools/build/lib/blackbox/tests/workspace/WorkspaceBlackBoxTest.java b/src/test/java/com/google/devtools/build/lib/blackbox/tests/workspace/WorkspaceBlackBoxTest.java
index 48fc1f9..cca0d8d 100644
--- a/src/test/java/com/google/devtools/build/lib/blackbox/tests/workspace/WorkspaceBlackBoxTest.java
+++ b/src/test/java/com/google/devtools/build/lib/blackbox/tests/workspace/WorkspaceBlackBoxTest.java
@@ -260,8 +260,6 @@
     context().write("BUILD");
     ProcessResult result = context().bazel().shouldFail().build("//...");
     assertThat(result.errString())
-        .contains(
-            "invalid repository name '@@a': repo names may contain only A-Z, a-z, 0-9, '-', '_' and"
-                + " '.'");
+        .contains("name field must be a legal workspace name; workspace names may contain only");
   }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/cmdline/RepositoryMappingTest.java b/src/test/java/com/google/devtools/build/lib/cmdline/RepositoryMappingTest.java
index 0d9cd3b..185c76d 100644
--- a/src/test/java/com/google/devtools/build/lib/cmdline/RepositoryMappingTest.java
+++ b/src/test/java/com/google/devtools/build/lib/cmdline/RepositoryMappingTest.java
@@ -32,6 +32,7 @@
             ImmutableMap.of("A", RepositoryName.create("com_foo_bar_a")));
     assertThat(mapping.get("A")).isEqualTo(RepositoryName.create("com_foo_bar_a"));
     assertThat(mapping.get("B")).isEqualTo(RepositoryName.create("B"));
+    assertThat(mapping.get("@canon")).isEqualTo(RepositoryName.create("@canon"));
   }
 
   @Test
@@ -44,6 +45,7 @@
     assertThat(mapping.get("B"))
         .isEqualTo(
             RepositoryName.create("B").toNonVisible(RepositoryName.create("fake_owner_repo")));
+    assertThat(mapping.get("@canon")).isEqualTo(RepositoryName.create("@canon"));
   }
 
   @Test
@@ -58,5 +60,6 @@
     assertThat(mapping.get("C"))
         .isEqualTo(
             RepositoryName.create("C").toNonVisible(RepositoryName.create("fake_owner_repo")));
+    assertThat(mapping.get("@canon")).isEqualTo(RepositoryName.create("@canon"));
   }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/cmdline/RepositoryNameTest.java b/src/test/java/com/google/devtools/build/lib/cmdline/RepositoryNameTest.java
index 9a8743f..570b9c5 100644
--- a/src/test/java/com/google/devtools/build/lib/cmdline/RepositoryNameTest.java
+++ b/src/test/java/com/google/devtools/build/lib/cmdline/RepositoryNameTest.java
@@ -22,9 +22,7 @@
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
-/**
- * Tests for @{link RepositoryName}.
- */
+/** Tests for {@link RepositoryName}. */
 @RunWith(JUnit4.class)
 public class RepositoryNameTest {
 
@@ -45,12 +43,14 @@
     assertThat(RepositoryName.create("..foo").getNameWithAt()).isEqualTo("@..foo");
     assertThat(RepositoryName.create("foo..").getNameWithAt()).isEqualTo("@foo..");
     assertThat(RepositoryName.create(".foo").getNameWithAt()).isEqualTo("@.foo");
+    assertThat(RepositoryName.create("@foo").getNameWithAt()).isEqualTo("@@foo");
+    assertThat(RepositoryName.create("@foo#bar").getNameWithAt()).isEqualTo("@@foo#bar");
 
     assertNotValid(".", "repo names are not allowed to be '@.'");
     assertNotValid("..", "repo names are not allowed to be '@..'");
-    assertNotValid("foo/bar", "repo names may contain only A-Z, a-z, 0-9, '-', '_' and '.'");
-    assertNotValid("foo@", "repo names may contain only A-Z, a-z, 0-9, '-', '_' and '.'");
-    assertNotValid("foo\0", "repo names may contain only A-Z, a-z, 0-9, '-', '_' and '.'");
+    assertNotValid("foo/bar", "repo names may contain only A-Z, a-z, 0-9, '-', '_', '.' and '#'");
+    assertNotValid("foo@", "repo names may contain only A-Z, a-z, 0-9, '-', '_', '.' and '#'");
+    assertNotValid("foo\0", "repo names may contain only A-Z, a-z, 0-9, '-', '_', '.' and '#'");
   }
 
   @Test
diff --git a/src/test/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorTest.java b/src/test/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorTest.java
index 4871914..b216252 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/repository/RepositoryDelegatorTest.java
@@ -492,12 +492,15 @@
     scratch.overwriteFile(
         rootPath.getRelative("MODULE.bazel").getPathString(),
         "module(name='A',version='0.1')",
-        "bazel_dep(name='B',version='1.0')");
+        "bazel_dep(name='bazel_tools',version='1.0')");
     FakeRegistry registry =
         registryFactory
             .newFakeRegistry(scratch.dir("modules").getPathString())
-            .addModule(createModuleKey("B", "1.0"), "module(name='B', version='1.0');");
+            .addModule(
+                createModuleKey("bazel_tools", "1.0"),
+                "module(name='bazel_tools', version='1.0');");
     ModuleFileFunction.REGISTRIES.set(differencer, ImmutableList.of(registry.getUrl()));
+    // Note that bazel_tools is a well-known module, so its repo name will always be "bazel_tools".
     scratch.file(rootPath.getRelative("BUILD").getPathString());
     scratch.file(
         rootPath.getRelative("repo_rule.bzl").getPathString(),
@@ -508,15 +511,15 @@
     scratch.file(
         rootPath.getRelative("WORKSPACE.bzlmod").getPathString(),
         "load(':repo_rule.bzl', 'fictive_repo_rule')",
-        "fictive_repo_rule(name = 'B.1.0')",
+        "fictive_repo_rule(name = 'bazel_tools')",
         "fictive_repo_rule(name = 'C')");
     scratch.file(
         rootPath.getRelative("WORKSPACE").getPathString(),
         "load(':repo_rule.bzl', 'fictive_repo_rule')",
-        "fictive_repo_rule(name = 'B.1.0')");
+        "fictive_repo_rule(name = 'bazel_tools')");
 
     StoredEventHandler eventHandler = new StoredEventHandler();
-    SkyKey key = RepositoryDirectoryValue.key(RepositoryName.createUnvalidated("B.1.0"));
+    SkyKey key = RepositoryDirectoryValue.key(RepositoryName.BAZEL_TOOLS);
     EvaluationContext evaluationContext =
         EvaluationContext.newBuilder()
             .setKeepGoing(false)
@@ -526,9 +529,9 @@
     EvaluationResult<SkyValue> result =
         evaluator.evaluate(ImmutableList.of(key), evaluationContext);
 
-    // B.1.0 should be fetched from MODULE.bazel file instead of WORKSPACE file.
-    // Because FakeRegistry will look for the contents of B.1.0 under $scratch/modules/B.1.0 which
-    // doesn't exist, the fetch should fail as expected.
+    // bazel_tools should be fetched from MODULE.bazel file instead of WORKSPACE file.
+    // Because FakeRegistry will look for the contents of bazel_tools under
+    // $scratch/modules/bazel_tools which doesn't exist, the fetch should fail as expected.
     assertThat(result.hasError()).isTrue();
     assertThat(result.getError().getException())
         .hasMessageThat()
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/BzlLoadFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/BzlLoadFunctionTest.java
index 52bad62..2acdaa2 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/BzlLoadFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/BzlLoadFunctionTest.java
@@ -451,19 +451,19 @@
             "module(name='foo',version='1.0')",
             "bazel_dep(name='bar',version='2.0',repo_name='bar_alias')")
         .addModule(createModuleKey("bar", "2.0"), "module(name='bar',version='2.0')");
-    Path fooDir = moduleRoot.getRelative("foo.1.0");
+    Path fooDir = moduleRoot.getRelative("@foo.1.0");
     scratch.file(fooDir.getRelative("WORKSPACE").getPathString());
     scratch.file(fooDir.getRelative("BUILD").getPathString());
     scratch.file(
         fooDir.getRelative("test.bzl").getPathString(),
         "load('@bar_alias//:test.bzl', 'haha')",
         "hoho = haha");
-    Path barDir = moduleRoot.getRelative("bar.2.0");
+    Path barDir = moduleRoot.getRelative("@bar.2.0");
     scratch.file(barDir.getRelative("WORKSPACE").getPathString());
     scratch.file(barDir.getRelative("BUILD").getPathString());
     scratch.file(barDir.getRelative("test.bzl").getPathString(), "haha = 5");
 
-    SkyKey skyKey = BzlLoadValue.keyForBzlmod(Label.parseAbsoluteUnchecked("@foo.1.0//:test.bzl"));
+    SkyKey skyKey = BzlLoadValue.keyForBzlmod(Label.parseCanonical("@@foo.1.0//:test.bzl"));
     EvaluationResult<BzlLoadValue> result =
         SkyframeExecutorTestUtils.evaluate(
             getSkyframeExecutor(), skyKey, /*keepGoing=*/ false, reporter);
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/RegisteredExecutionPlatformsFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/RegisteredExecutionPlatformsFunctionTest.java
index 414b680..1fb646f 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/RegisteredExecutionPlatformsFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/RegisteredExecutionPlatformsFunctionTest.java
@@ -378,7 +378,7 @@
             ")",
             "bazel_dep(name='E',version='1.0')")
         .addModule(createModuleKey("E", "1.0"), "module(name='E', version='1.0')");
-    for (String repo : ImmutableList.of("B.1.0", "C.1.1", "D.1.0", "D.1.1", "E.1.0")) {
+    for (String repo : ImmutableList.of("@B.1.0", "@C.1.1", "@D.1.0", "@D.1.1", "@E.1.0")) {
       scratch.file(moduleRoot.getRelative(repo).getRelative("WORKSPACE").getPathString());
       scratch.file(
           moduleRoot.getRelative(repo).getRelative("BUILD").getPathString(),
@@ -399,12 +399,12 @@
     // WORKSPACE registrations.
     assertExecutionPlatformLabels(result.get(executionPlatformsKey))
         .containsExactly(
-            Label.parseAbsoluteUnchecked("//:plat"),
-            Label.parseAbsoluteUnchecked("@B.1.0//:plat"),
-            Label.parseAbsoluteUnchecked("@C.1.1//:plat"),
-            Label.parseAbsoluteUnchecked("@E.1.0//:plat"),
-            Label.parseAbsoluteUnchecked("@D.1.1//:plat"),
-            Label.parseAbsoluteUnchecked("//:wsplat"))
+            Label.parseCanonical("//:plat"),
+            Label.parseCanonical("@@B.1.0//:plat"),
+            Label.parseCanonical("@@C.1.1//:plat"),
+            Label.parseCanonical("@@E.1.0//:plat"),
+            Label.parseCanonical("@@D.1.1//:plat"),
+            Label.parseCanonical("//:wsplat"))
         .inOrder();
   }
 
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsFunctionTest.java
index 3ca6970..b518909 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/RegisteredToolchainsFunctionTest.java
@@ -355,7 +355,7 @@
             createModuleKey("toolchain_def", "1.0"), "module(name='toolchain_def',version='1.0')");
 
     // Everyone depends on toolchain_def@1.0 for the declare_toolchain macro.
-    Path toolchainDefDir = moduleRoot.getRelative("toolchain_def.1.0");
+    Path toolchainDefDir = moduleRoot.getRelative("@toolchain_def.1.0");
     scratch.file(toolchainDefDir.getRelative("WORKSPACE").getPathString());
     scratch.file(
         toolchainDefDir.getRelative("BUILD").getPathString(),
@@ -376,7 +376,7 @@
         "        data = 'stuff')");
 
     // Now create the toolchains for each module.
-    for (String repo : ImmutableList.of("B.1.0", "C.1.1", "D.1.0", "D.1.1", "E.1.0")) {
+    for (String repo : ImmutableList.of("@B.1.0", "@C.1.1", "@D.1.0", "@D.1.1", "@E.1.0")) {
       scratch.file(moduleRoot.getRelative(repo).getRelative("WORKSPACE").getPathString());
       scratch.file(
           moduleRoot.getRelative(repo).getRelative("BUILD").getPathString(),
@@ -402,12 +402,12 @@
     // registrations.
     assertToolchainLabels(result.get(toolchainsKey))
         .containsAtLeast(
-            Label.parseAbsoluteUnchecked("//:tool_impl"),
-            Label.parseAbsoluteUnchecked("@B.1.0//:tool_impl"),
-            Label.parseAbsoluteUnchecked("@C.1.1//:tool_impl"),
-            Label.parseAbsoluteUnchecked("@E.1.0//:tool_impl"),
-            Label.parseAbsoluteUnchecked("@D.1.1//:tool_impl"),
-            Label.parseAbsoluteUnchecked("//:wstool_impl"))
+            Label.parseCanonical("//:tool_impl"),
+            Label.parseCanonical("@@B.1.0//:tool_impl"),
+            Label.parseCanonical("@@C.1.1//:tool_impl"),
+            Label.parseCanonical("@@E.1.0//:tool_impl"),
+            Label.parseCanonical("@@D.1.1//:tool_impl"),
+            Label.parseCanonical("//:wstool_impl"))
         .inOrder();
   }
 
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/RepositoryMappingFunctionTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/RepositoryMappingFunctionTest.java
index c1ee7c0..381eb64 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/RepositoryMappingFunctionTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/RepositoryMappingFunctionTest.java
@@ -168,7 +168,7 @@
                 ImmutableMap.of(
                     "", RepositoryName.create(""),
                     "A", RepositoryName.create(""),
-                    "com_foo_bar_b", RepositoryName.create("B.1.0")),
+                    "com_foo_bar_b", RepositoryName.create("@B.1.0")),
                 name));
   }
 
@@ -186,7 +186,7 @@
             "module(name='C', version='1.0')",
             "bazel_dep(name='B', version='1.0', repo_name='com_foo_bar_b')");
 
-    RepositoryName name = RepositoryName.create("C.1.0");
+    RepositoryName name = RepositoryName.create("@C.1.0");
     SkyKey skyKey = RepositoryMappingValue.key(name);
     EvaluationResult<RepositoryMappingValue> result = eval(skyKey);
 
@@ -196,8 +196,8 @@
         .isEqualTo(
             withMapping(
                 ImmutableMap.of(
-                    "C", RepositoryName.create("C.1.0"),
-                    "com_foo_bar_b", RepositoryName.create("B.1.0")),
+                    "C", RepositoryName.create("@C.1.0"),
+                    "com_foo_bar_b", RepositoryName.create("@B.1.0")),
                 name));
   }
 
@@ -210,7 +210,7 @@
         "module(name='B', version='1.0')",
         "bazel_dep(name='A',version='3.0')");
 
-    RepositoryName name = RepositoryName.create("B.1.0");
+    RepositoryName name = RepositoryName.create("@B.1.0");
     SkyKey skyKey = RepositoryMappingValue.key(name);
     EvaluationResult<RepositoryMappingValue> result = eval(skyKey);
 
@@ -220,7 +220,7 @@
         .isEqualTo(
             withMapping(
                 ImmutableMap.of(
-                    "B", RepositoryName.create("B.1.0"), "A", RepositoryName.create("")),
+                    "B", RepositoryName.create("@B.1.0"), "A", RepositoryName.create("")),
                 name));
   }
 
@@ -250,8 +250,8 @@
                 ImmutableMap.of(
                     "", RepositoryName.create(""),
                     "A", RepositoryName.create(""),
-                    "B1", RepositoryName.create("B.1.0"),
-                    "B2", RepositoryName.create("B.2.0")),
+                    "B1", RepositoryName.create("@B.1.0"),
+                    "B2", RepositoryName.create("@B.2.0")),
                 name));
   }
 
@@ -273,7 +273,7 @@
         .addModule(createModuleKey("D", "1.0"), "module(name='D', version='1.0')")
         .addModule(createModuleKey("D", "2.0"), "module(name='D', version='2.0')");
 
-    RepositoryName name = RepositoryName.create("B.1.0");
+    RepositoryName name = RepositoryName.create("@B.1.0");
     SkyKey skyKey = RepositoryMappingValue.key(name);
     EvaluationResult<RepositoryMappingValue> result = eval(skyKey);
 
@@ -285,8 +285,8 @@
         .isEqualTo(
             withMapping(
                 ImmutableMap.of(
-                    "B", RepositoryName.create("B.1.0"),
-                    "D", RepositoryName.create("D.1.0")),
+                    "B", RepositoryName.create("@B.1.0"),
+                    "D", RepositoryName.create("@D.1.0")),
                 name));
   }
 
@@ -306,7 +306,7 @@
         .addModule(createModuleKey("B", "2.0"), "module(name='B', version='2.0')")
         .addModule(createModuleKey("C", "1.0"), "module(name='C', version='1.0')");
 
-    RepositoryName name = RepositoryName.create("B.1.0");
+    RepositoryName name = RepositoryName.create("@B.1.0");
     SkyKey skyKey = RepositoryMappingValue.key(name);
     EvaluationResult<RepositoryMappingValue> result = eval(skyKey);
 
@@ -318,8 +318,8 @@
         .isEqualTo(
             withMapping(
                 ImmutableMap.of(
-                    "B", RepositoryName.create("B.1.0"),
-                    "com_foo_bar_c", RepositoryName.create("C.1.0")),
+                    "B", RepositoryName.create("@B.1.0"),
+                    "com_foo_bar_c", RepositoryName.create("@C.1.0")),
                 name));
   }
 
@@ -419,12 +419,12 @@
                 ImmutableMap.<String, RepositoryName>builder()
                     .put("root", RepositoryName.MAIN)
                     // mappings to @B get remapped to @B.1.0 because of module B@1.0
-                    .put("B_alias", RepositoryName.create("B.1.0"))
-                    .put("B_alias2", RepositoryName.create("B.1.0"))
+                    .put("B_alias", RepositoryName.create("@B.1.0"))
+                    .put("B_alias2", RepositoryName.create("@B.1.0"))
                     // mapping from @B to @B.1.0 is also created
-                    .put("B", RepositoryName.create("B.1.0"))
+                    .put("B", RepositoryName.create("@B.1.0"))
                     // mapping from @C to @C.2.0 is created despite not being mentioned
-                    .put("C", RepositoryName.create("C.2.0"))
+                    .put("C", RepositoryName.create("@C.2.0"))
                     // mapping to @D is untouched because D has a multiple-version override
                     .put("D_alias", RepositoryName.create("D"))
                     // mapping to @E is untouched because E is not a module
@@ -456,7 +456,7 @@
                 ImmutableMap.of(
                     "", RepositoryName.MAIN,
                     "A", RepositoryName.MAIN,
-                    "B", RepositoryName.create("B.1.0"),
+                    "B", RepositoryName.create("@B.1.0"),
                     "root", RepositoryName.create("root"),
                     "ws_repo", RepositoryName.create("ws_repo")),
                 RepositoryName.MAIN));
@@ -486,7 +486,7 @@
                 ImmutableMap.of(
                     "", RepositoryName.MAIN,
                     "A", RepositoryName.MAIN,
-                    "B", RepositoryName.create("B.1.0")),
+                    "B", RepositoryName.create("@B.1.0")),
                 RepositoryName.MAIN));
   }
 
@@ -574,7 +574,7 @@
             withMapping(
                 ImmutableMap.of(
                     "bazel_tools", RepositoryName.BAZEL_TOOLS, // bazel_tools is a well-known module
-                    "foo", RepositoryName.create("foo.1.0"),
+                    "foo", RepositoryName.create("@foo.1.0"),
                     "_builtins", RepositoryName.create("_builtins")),
                 name));
   }
diff --git a/src/test/shell/bazel/local_repository_test.sh b/src/test/shell/bazel/local_repository_test.sh
index c889498..48fe770 100755
--- a/src/test/shell/bazel/local_repository_test.sh
+++ b/src/test/shell/bazel/local_repository_test.sh
@@ -1027,7 +1027,7 @@
 EOF
 
   bazel build @r/a//:bin &> $TEST_log && fail "expected build failure, but succeeded"
-  expect_log "repo names may contain only A-Z, a-z, 0-9, '-', '_' and '.'"
+  expect_log "repo names may contain only A-Z, a-z, 0-9, '-', '_', '.' and '#'"
 }
 
 function test_remote_includes() {