Enable rule transition to inspect configurable attributes' value

Fixes https://github.com/bazelbuild/bazel/issues/15157

PiperOrigin-RevId: 558262406
Change-Id: I514c95c0470a2d171a5b276f25b65a4adddf17e9
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationValue.java b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationValue.java
index 4055f14..c18e416 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationValue.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildConfigurationValue.java
@@ -906,7 +906,7 @@
     return starlarkVisibleFragments.keySet();
   }
 
-  private BuildEventId getEventId() {
+  public BuildEventId getEventId() {
     return BuildEventIdUtil.configurationId(checksum());
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigMatchingProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigMatchingProvider.java
index 8a6a0a6..b8878b4 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigMatchingProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/ConfigMatchingProvider.java
@@ -58,11 +58,11 @@
   /** The target's label. */
   public abstract Label label();
 
-  abstract ImmutableMultimap<String, String> settingsMap();
+  public abstract ImmutableMultimap<String, String> settingsMap();
 
-  abstract ImmutableMap<Label, String> flagSettingsMap();
+  public abstract ImmutableMap<Label, String> flagSettingsMap();
 
-  abstract ImmutableSet<Label> constraintValuesSetting();
+  public abstract ImmutableSet<Label> constraintValuesSetting();
 
   /**
    * Whether or not the configuration criteria defined by this target match its actual
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/RequiredFragmentsUtil.java b/src/main/java/com/google/devtools/build/lib/analysis/config/RequiredFragmentsUtil.java
index 630a9d6..1210c8a 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/RequiredFragmentsUtil.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/RequiredFragmentsUtil.java
@@ -106,7 +106,12 @@
           .addRuleImplSpecificRequiredConfigFragments(requiredFragments, attributes, configuration);
     }
     addRequiredFragmentsFromRuleTransitions(
-        requiredFragments, target, attributes, configuration.getBuildOptionDetails());
+        configConditions,
+        configuration.checksum(),
+        requiredFragments,
+        target,
+        attributes,
+        configuration.getBuildOptionDetails());
 
     // We consider build settings (which are both targets and configuration) to require themselves.
     if (target.isBuildSetting()) {
@@ -216,6 +221,8 @@
    * because the child's properties determine that dependency.
    */
   private static void addRequiredFragmentsFromRuleTransitions(
+      ConfigConditions configConditions,
+      String configHash,
       RequiredConfigFragmentsProvider.Builder requiredFragments,
       Rule target,
       ConfiguredAttributeMapper attributeMap,
@@ -224,7 +231,7 @@
       target
           .getRuleClassObject()
           .getTransitionFactory()
-          .create(RuleTransitionData.create(target))
+          .create(RuleTransitionData.create(target, configConditions.asProviders(), configHash))
           .addRequiredFragments(requiredFragments, optionDetails);
     }
     // We don't set the execution platform in this data because a) that doesn't affect which
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/StarlarkDefinedConfigTransition.java b/src/main/java/com/google/devtools/build/lib/analysis/config/StarlarkDefinedConfigTransition.java
index efbd190..8e2daae 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/config/StarlarkDefinedConfigTransition.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/config/StarlarkDefinedConfigTransition.java
@@ -39,6 +39,7 @@
 import com.google.devtools.build.lib.packages.BazelStarlarkContext;
 import com.google.devtools.build.lib.packages.BazelStarlarkContext.Phase;
 import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.packages.RuleTransitionData;
 import com.google.devtools.build.lib.packages.StructImpl;
 import com.google.devtools.build.lib.packages.SymbolGenerator;
 import com.google.devtools.build.lib.starlarkbuildapi.config.ConfigurationTransitionApi;
@@ -95,7 +96,7 @@
 
   // The values in this cache should always be instances of StarlarkTransition, but referencing that
   // here results in a circular dependency.
-  private final transient Cache<Rule, PatchTransition> ruleTransitionCache =
+  private final transient Cache<RuleTransitionData, PatchTransition> ruleTransitionCache =
       Caffeine.newBuilder().weakKeys().build();
 
   private StarlarkDefinedConfigTransition(
@@ -216,7 +217,8 @@
   /**
    * Returns a cache that can be used to ensure that this {@link StarlarkDefinedConfigTransition}
    * results in at most one {@link
-   * com.google.devtools.build.lib.analysis.starlark.StarlarkTransition} instance per {@link Rule}.
+   * com.google.devtools.build.lib.analysis.starlark.StarlarkTransition} instance per {@link
+   * RuleTransitionData}.
    *
    * <p>The cache uses {@link Caffeine#weakKeys} to permit collection of transition objects when the
    * corresponding {@link Rule} is collectable. As a consequence, it uses identity comparison for
@@ -231,7 +233,7 @@
    * practice to have few or even one transition invoke multiple times over multiple configured
    * targets.
    */
-  public final Cache<Rule, PatchTransition> getRuleTransitionCache() {
+  public final Cache<RuleTransitionData, PatchTransition> getRuleTransitionCache() {
     return ruleTransitionCache;
   }
 
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/BUILD b/src/main/java/com/google/devtools/build/lib/analysis/producers/BUILD
index ce934bf..98cb507 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/producers/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/BUILD
@@ -15,6 +15,7 @@
     name = "producers",
     srcs = glob(["*.java"]),
     deps = [
+        "//third_party:guava",
         "//src/main/java/com/google/devtools/build/lib/actions:action_lookup_key",
         "//src/main/java/com/google/devtools/build/lib/analysis:analysis_cluster",
         "//src/main/java/com/google/devtools/build/lib/analysis:aspect_collection",
@@ -23,10 +24,13 @@
         "//src/main/java/com/google/devtools/build/lib/analysis:config/config_conditions",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/config_matching_provider",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/configuration_transition_event",
+        "//src/main/java/com/google/devtools/build/lib/analysis:config/core_options",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/invalid_configuration_exception",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/starlark_transition_cache",
+        "//src/main/java/com/google/devtools/build/lib/analysis:config/toolchain_type_requirement",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/composing_transition",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/configuration_transition",
+        "//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/patch_transition",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/transition_collector",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/transitions/transition_factory",
         "//src/main/java/com/google/devtools/build/lib/analysis:configured_target",
@@ -52,10 +56,12 @@
         "//src/main/java/com/google/devtools/build/lib/buildeventstream/proto:build_event_stream_java_proto",
         "//src/main/java/com/google/devtools/build/lib/causes",
         "//src/main/java/com/google/devtools/build/lib/cmdline",
+        "//src/main/java/com/google/devtools/build/lib/collect/nestedset",
         "//src/main/java/com/google/devtools/build/lib/events",
         "//src/main/java/com/google/devtools/build/lib/packages",
         "//src/main/java/com/google/devtools/build/lib/packages:configured_attribute_mapper",
         "//src/main/java/com/google/devtools/build/lib/packages:exec_group",
+        #"//src/main/java/com/google/devtools/build/lib/rules/config",
         "//src/main/java/com/google/devtools/build/lib/skyframe:aspect_creation_exception",
         "//src/main/java/com/google/devtools/build/lib/skyframe:aspect_key_creator",
         "//src/main/java/com/google/devtools/build/lib/skyframe:build_configuration",
@@ -78,7 +84,6 @@
         "//src/main/java/net/starlark/java/syntax",
         "//src/main/protobuf:failure_details_java_proto",
         "//third_party:auto_value",
-        "//third_party:guava",
         "//third_party:jsr305",
     ],
 )
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/ConfigConditionsProducer.java b/src/main/java/com/google/devtools/build/lib/analysis/producers/ConfigConditionsProducer.java
index 59f4833..66f556d 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/producers/ConfigConditionsProducer.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/ConfigConditionsProducer.java
@@ -16,7 +16,6 @@
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.devtools.build.lib.analysis.InconsistentNullConfigException;
-import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
 import com.google.devtools.build.lib.analysis.TransitiveDependencyState;
 import com.google.devtools.build.lib.analysis.config.ConfigConditions;
 import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
@@ -28,6 +27,7 @@
 import com.google.devtools.build.lib.packages.Rule;
 import com.google.devtools.build.lib.packages.RuleClass;
 import com.google.devtools.build.lib.packages.Target;
+import com.google.devtools.build.lib.skyframe.BuildConfigurationKey;
 import com.google.devtools.build.lib.skyframe.ConfiguredTargetAndData;
 import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey;
 import com.google.devtools.build.lib.skyframe.ConfiguredValueCreationException;
@@ -47,7 +47,9 @@
   }
 
   // -------------------- Input --------------------
-  private final TargetAndConfiguration targetAndConfiguration;
+  private final Label targetLabel;
+  private final Target target;
+  private final BuildConfigurationKey buildConfigurationKey;
   @Nullable private final PlatformInfo targetPlatformInfo;
   private final TransitiveDependencyState transitiveState;
 
@@ -66,18 +68,22 @@
   private DetailedExitCode mostImportantExitCode;
 
   ConfigConditionsProducer(
-      TargetAndConfiguration targetAndConfiguration,
+      Target target,
+      Label targetLabel,
+      BuildConfigurationKey buildConfigurationKey,
       @Nullable PlatformInfo targetPlatformInfo,
       TransitiveDependencyState transitiveState,
       ResultSink sink,
       StateMachine runAfter) {
-    this.targetAndConfiguration = targetAndConfiguration;
+    this.targetLabel = targetLabel;
+    this.target = target;
+    this.buildConfigurationKey = buildConfigurationKey;
     this.targetPlatformInfo = targetPlatformInfo;
     this.transitiveState = transitiveState;
     this.sink = sink;
     this.runAfter = runAfter;
 
-    this.configLabels = computeConfigLabels(targetAndConfiguration.getTarget());
+    this.configLabels = computeConfigLabels(target);
     this.prerequisites =
         configLabels == null ? null : new ConfiguredTargetAndData[configLabels.size()];
   }
@@ -98,7 +104,7 @@
           new ConfiguredTargetAndDataProducer(
               ConfiguredTargetKey.builder()
                   .setLabel(configLabels.get(i))
-                  .setConfiguration(targetAndConfiguration.getConfiguration())
+                  .setConfigurationKey(buildConfigurationKey)
                   .build(),
               /* transitionKeys= */ ImmutableList.of(),
               transitiveState,
@@ -147,7 +153,6 @@
         asConfigConditions.put(
             label, ConfigConditions.fromConfiguredTarget(prerequisite, targetPlatformInfo));
       } catch (ConfigConditions.InvalidConditionException e) {
-        var targetLabel = targetAndConfiguration.getLabel();
         String message =
             String.format(
                     "%s is not a valid select() condition for %s.\n",
@@ -155,8 +160,7 @@
                 + String.format(
                     "To inspect the select(), run: bazel query --output=build %s.\n", targetLabel)
                 + "For more help, see https://bazel.build/reference/be/functions#select.\n\n";
-        sink.acceptConfigConditionsError(
-            new ConfiguredValueCreationException(targetAndConfiguration, message));
+        sink.acceptConfigConditionsError(new ConfiguredValueCreationException(target, message));
         return runAfter;
       }
     }
@@ -200,9 +204,7 @@
           // The precise error is reported by the dependency that failed to load.
           // TODO(gregce): beautify this error: https://github.com/bazelbuild/bazel/issues/11984.
           new ConfiguredValueCreationException(
-              targetAndConfiguration,
-              "errors encountered resolving select() keys for "
-                  + targetAndConfiguration.getLabel()));
+              target, "errors encountered resolving select() keys for " + targetLabel));
     }
   }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyContextProducer.java b/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyContextProducer.java
index e68b145..37fbb9e 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyContextProducer.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyContextProducer.java
@@ -18,6 +18,7 @@
 import com.google.devtools.build.lib.analysis.TransitiveDependencyState;
 import com.google.devtools.build.lib.analysis.config.ConfigConditions;
 import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
+import com.google.devtools.build.lib.skyframe.BuildConfigurationKey;
 import com.google.devtools.build.lib.skyframe.ConfiguredValueCreationException;
 import com.google.devtools.build.lib.skyframe.toolchains.ToolchainException;
 import com.google.devtools.build.lib.skyframe.toolchains.UnloadedToolchainContext;
@@ -56,6 +57,7 @@
   // -------------------- Input --------------------
   private final UnloadedToolchainContextsInputs unloadedToolchainContextsInputs;
   private final TargetAndConfiguration targetAndConfiguration;
+  private final BuildConfigurationKey buildConfigurationKey;
   private final TransitiveDependencyState transitiveState;
 
   // -------------------- Output --------------------
@@ -70,9 +72,12 @@
   public DependencyContextProducer(
       UnloadedToolchainContextsInputs unloadedToolchainContextsInputs,
       TargetAndConfiguration targetAndConfiguration,
+      BuildConfigurationKey buildConfigurationKey,
       TransitiveDependencyState transitiveState,
       ResultSink sink) {
     this.unloadedToolchainContextsInputs = unloadedToolchainContextsInputs;
+    this.buildConfigurationKey = buildConfigurationKey;
+    this.unloadedToolchainContexts = null;
     this.targetAndConfiguration = targetAndConfiguration;
     this.transitiveState = transitiveState;
     this.sink = sink;
@@ -104,7 +109,9 @@
     }
 
     return new ConfigConditionsProducer(
-        targetAndConfiguration,
+        targetAndConfiguration.getTarget(),
+        targetAndConfiguration.getTarget().getLabel(),
+        buildConfigurationKey,
         unloadedToolchainContexts == null ? null : unloadedToolchainContexts.getTargetPlatform(),
         transitiveState,
         (ConfigConditionsProducer.ResultSink) this,
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyContextProducerWithCompatibilityCheck.java b/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyContextProducerWithCompatibilityCheck.java
index 3f31bd9..581e617 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyContextProducerWithCompatibilityCheck.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyContextProducerWithCompatibilityCheck.java
@@ -81,7 +81,9 @@
       // If `defaultToolchainContextKey` is null, there's no platform info, incompatibility check
       // or toolchain resolution. Short-circuits and computes only the ConfigConditions.
       return new ConfigConditionsProducer(
-          targetAndConfiguration,
+          targetAndConfiguration.getTarget(),
+          targetAndConfiguration.getTarget().getLabel(),
+          configuredTargetKey.getConfigurationKey(),
           /* targetPlatformInfo= */ null,
           transitiveState,
           (ConfigConditionsProducer.ResultSink) this,
@@ -119,7 +121,9 @@
     }
 
     return new ConfigConditionsProducer(
-        targetAndConfiguration,
+        targetAndConfiguration.getTarget(),
+        targetAndConfiguration.getTarget().getLabel(),
+        configuredTargetKey.getConfigurationKey(),
         targetPlatformInfo,
         transitiveState,
         (ConfigConditionsProducer.ResultSink) this,
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyProducer.java b/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyProducer.java
index 1e4e06f..b2e65d8 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyProducer.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/DependencyProducer.java
@@ -376,9 +376,10 @@
           DependencyError.of(
               new DependencyEvaluationException(
                   new ConfiguredValueCreationException(
+                      parameters.target(),
                       parameters.location(),
                       message,
-                      toLabel,
+                      parameters.label(),
                       parameters.eventId(),
                       /* rootCauses= */ null,
                       /* detailedExitCode= */ null),
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/PrerequisitesProducer.java b/src/main/java/com/google/devtools/build/lib/analysis/producers/PrerequisitesProducer.java
index ff76717..ff75d1c 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/producers/PrerequisitesProducer.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/PrerequisitesProducer.java
@@ -242,6 +242,7 @@
     sink.acceptPrerequisitesAspectError(
         new DependencyEvaluationException(
             new ConfiguredValueCreationException(
+                parameters.target(),
                 parameters.location(),
                 error.getMessage(),
                 parameters.label(),
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/producers/TargetAndConfigurationProducer.java b/src/main/java/com/google/devtools/build/lib/analysis/producers/TargetAndConfigurationProducer.java
index c9395c2..fbd2579 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/producers/TargetAndConfigurationProducer.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/producers/TargetAndConfigurationProducer.java
@@ -19,35 +19,61 @@
 
 import com.google.auto.value.AutoOneOf;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
 import com.google.devtools.build.lib.actions.ActionLookupKey;
 import com.google.devtools.build.lib.analysis.ConfiguredTargetValue;
+import com.google.devtools.build.lib.analysis.ExecGroupCollection;
 import com.google.devtools.build.lib.analysis.InconsistentNullConfigException;
+import com.google.devtools.build.lib.analysis.PlatformConfiguration;
+import com.google.devtools.build.lib.analysis.PlatformOptions;
 import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
 import com.google.devtools.build.lib.analysis.TransitiveDependencyState;
 import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
+import com.google.devtools.build.lib.analysis.config.BuildOptions;
+import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
+import com.google.devtools.build.lib.analysis.config.ConfigConditions;
 import com.google.devtools.build.lib.analysis.config.ConfigurationTransitionEvent;
+import com.google.devtools.build.lib.analysis.config.CoreOptions;
 import com.google.devtools.build.lib.analysis.config.InvalidConfigurationException;
 import com.google.devtools.build.lib.analysis.config.StarlarkTransitionCache;
+import com.google.devtools.build.lib.analysis.config.ToolchainTypeRequirement;
 import com.google.devtools.build.lib.analysis.config.transitions.ComposingTransition;
 import com.google.devtools.build.lib.analysis.config.transitions.ConfigurationTransition;
+import com.google.devtools.build.lib.analysis.config.transitions.PatchTransition;
 import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
+import com.google.devtools.build.lib.analysis.platform.PlatformInfo;
 import com.google.devtools.build.lib.analysis.starlark.StarlarkTransition.TransitionException;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId.ConfigurationId;
+import com.google.devtools.build.lib.causes.AnalysisFailedCause;
+import com.google.devtools.build.lib.causes.Cause;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.Order;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.ExtendedEventHandler;
+import com.google.devtools.build.lib.packages.BuildType;
 import com.google.devtools.build.lib.packages.NoSuchPackageException;
 import com.google.devtools.build.lib.packages.NoSuchTargetException;
 import com.google.devtools.build.lib.packages.NoSuchThingException;
+import com.google.devtools.build.lib.packages.NonconfigurableAttributeMapper;
 import com.google.devtools.build.lib.packages.Rule;
+import com.google.devtools.build.lib.packages.RuleClass;
 import com.google.devtools.build.lib.packages.RuleTransitionData;
 import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.packages.TargetUtils;
+import com.google.devtools.build.lib.packages.Type;
+import com.google.devtools.build.lib.server.FailureDetails.Analysis;
+import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
 import com.google.devtools.build.lib.skyframe.BuildConfigurationKey;
 import com.google.devtools.build.lib.skyframe.ConfiguredTargetKey;
 import com.google.devtools.build.lib.skyframe.ConfiguredValueCreationException;
+import com.google.devtools.build.lib.skyframe.toolchains.PlatformLookupUtil.InvalidPlatformException;
+import com.google.devtools.build.lib.skyframe.toolchains.ToolchainContextKey;
 import com.google.devtools.build.lib.util.DetailedExitCode;
 import com.google.devtools.build.skyframe.SkyValue;
 import com.google.devtools.build.skyframe.state.StateMachine;
 import com.google.devtools.common.options.OptionsParsingException;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
 import java.util.function.Consumer;
 import javax.annotation.Nullable;
 import net.starlark.java.syntax.Location;
@@ -109,6 +135,7 @@
   // -------------------- Input --------------------
   private final ConfiguredTargetKey preRuleTransitionKey;
   @Nullable private final TransitionFactory<RuleTransitionData> trimmingTransitionFactory;
+  private final PatchTransition toolchainTaggedTrimmingTransition;
   private final StarlarkTransitionCache transitionCache;
 
   private final TransitiveDependencyState transitiveState;
@@ -123,12 +150,14 @@
   public TargetAndConfigurationProducer(
       ConfiguredTargetKey preRuleTransitionKey,
       @Nullable TransitionFactory<RuleTransitionData> trimmingTransitionFactory,
+      PatchTransition toolchainTaggedTrimmingTransition,
       StarlarkTransitionCache transitionCache,
       TransitiveDependencyState transitiveState,
       ResultSink sink,
       ExtendedEventHandler eventHandler) {
     this.preRuleTransitionKey = preRuleTransitionKey;
     this.trimmingTransitionFactory = trimmingTransitionFactory;
+    this.toolchainTaggedTrimmingTransition = toolchainTaggedTrimmingTransition;
     this.transitionCache = transitionCache;
     this.transitiveState = transitiveState;
     this.sink = sink;
@@ -239,15 +268,12 @@
         error.getMessage(), TargetUtils.getLocationMaybe(target), error.getDetailedExitCode());
   }
 
-  /**
-   * Applies the requested rule transition.
-   *
-   * <p>When the rule transition results in a new configuration, performs an idempotency check and
-   * constructs a delegate {@link ConfiguredTargetKey} with the appropriate {@link
-   * ConfiguredTargetKey#shouldApplyRuleTransition} value. Otherwise, just looks up the
-   * configuration.
-   */
-  private class RuleTransitionApplier implements StateMachine, TransitionApplier.ResultSink {
+  /** Applies any requested rule transition before producing the final configuration. */
+  private class RuleTransitionApplier
+      implements StateMachine,
+          TransitionApplier.ResultSink,
+          ConfigConditionsProducer.ResultSink,
+          PlatformInfoProducer.ResultSink {
     // -------------------- Input --------------------
     private final ConfigurationTransition transition;
     // -------------------- Internal State --------------------
@@ -257,8 +283,211 @@
       this.transition = transition;
     }
 
+    private ConfigConditions configConditions;
+
+    @Nullable private PlatformInfo platformInfo;
+
     @Override
-    public StateMachine step(Tasks tasks) {
+    public StateMachine step(Tasks tasks) throws InterruptedException {
+
+      UnloadedToolchainContextsInputs unloadedToolchainContextsInputs =
+          getUnloadedToolchainContextsInputs(
+              target, preRuleTransitionKey.getExecutionPlatformLabel());
+
+      if (unloadedToolchainContextsInputs.targetToolchainContextKey() != null) {
+        PlatformConfiguration platformConfiguration =
+            new PlatformConfiguration(preRuleTransitionKey.getConfigurationKey().getOptions());
+        tasks.enqueue(
+            new PlatformInfoProducer(
+                ConfiguredTargetKey.builder()
+                    .setLabel(platformConfiguration.getTargetPlatform())
+                    .setConfigurationKey(
+                        unloadedToolchainContextsInputs
+                            .targetToolchainContextKey()
+                            .configurationKey())
+                    .build(),
+                (PlatformInfoProducer.ResultSink) this,
+                this::computeConfigConditions));
+      } else {
+        this.platformInfo = null;
+        computeConfigConditions(tasks);
+      }
+
+      return DONE;
+    }
+
+    public UnloadedToolchainContextsInputs getUnloadedToolchainContextsInputs(
+        Target target, @Nullable Label parentExecutionPlatformLabel) throws InterruptedException {
+      if (!(target instanceof Rule)) {
+        return UnloadedToolchainContextsInputs.empty();
+      }
+
+      Rule rule = (Rule) target;
+
+      if (!preRuleTransitionKey
+          .getConfigurationKey()
+          .getOptions()
+          .contains(PlatformOptions.class)) {
+        return UnloadedToolchainContextsInputs.empty();
+      }
+      PlatformConfiguration platformConfiguration =
+          new PlatformConfiguration(preRuleTransitionKey.getConfigurationKey().getOptions());
+      var defaultExecConstraintLabels =
+          getExecutionPlatformConstraints(rule, platformConfiguration);
+      var ruleClass = rule.getRuleClassObject();
+      boolean useAutoExecGroups =
+          rule.isAttrDefined("$use_auto_exec_groups", Type.BOOLEAN)
+              ? (boolean) rule.getAttr("$use_auto_exec_groups")
+              : preRuleTransitionKey
+                  .getConfigurationKey()
+                  .getOptions()
+                  .get(CoreOptions.class)
+                  .useAutoExecGroups;
+
+      var processedExecGroups =
+          ExecGroupCollection.process(
+              ruleClass.getExecGroups(),
+              defaultExecConstraintLabels,
+              ruleClass.getToolchainTypes(),
+              useAutoExecGroups);
+
+      if (!rule.useToolchainResolution()) {
+        return UnloadedToolchainContextsInputs.create(processedExecGroups, null);
+      }
+
+      return UnloadedToolchainContextsInputs.create(
+          processedExecGroups,
+          createDefaultToolchainContextKey(
+              computeToolchainConfigurationKey(
+                  preRuleTransitionKey.getConfigurationKey().getOptions(),
+                  toolchainTaggedTrimmingTransition),
+              defaultExecConstraintLabels,
+              /* debugTarget= */ platformConfiguration.debugToolchainResolution(rule.getLabel()),
+              /* useAutoExecGroups= */ useAutoExecGroups,
+              ruleClass.getToolchainTypes(),
+              parentExecutionPlatformLabel));
+    }
+
+    public ToolchainContextKey createDefaultToolchainContextKey(
+        BuildConfigurationKey configurationKey,
+        ImmutableSet<Label> defaultExecConstraintLabels,
+        boolean debugTarget,
+        boolean useAutoExecGroups,
+        ImmutableSet<ToolchainTypeRequirement> toolchainTypes,
+        @Nullable Label parentExecutionPlatformLabel) {
+      ToolchainContextKey.Builder toolchainContextKeyBuilder =
+          ToolchainContextKey.key()
+              .configurationKey(configurationKey)
+              .execConstraintLabels(defaultExecConstraintLabels)
+              .debugTarget(debugTarget);
+
+      // Add toolchain types only if automatic exec groups are not created for this target.
+      if (!useAutoExecGroups) {
+        toolchainContextKeyBuilder.toolchainTypes(toolchainTypes);
+      }
+
+      if (parentExecutionPlatformLabel != null) {
+        // Find out what execution platform the parent used, and force that.
+        // This should only be set for direct toolchain dependencies.
+        toolchainContextKeyBuilder.forceExecutionPlatform(parentExecutionPlatformLabel);
+      }
+      return toolchainContextKeyBuilder.build();
+    }
+
+    private BuildConfigurationKey computeToolchainConfigurationKey(
+        BuildOptions buildOptions, PatchTransition toolchainTaggedTrimmingTransition)
+        throws InterruptedException {
+      // The toolchain context's options are the parent rule's options with manual trimming
+      // auto-applied. This means toolchains don't inherit feature flags. This helps build
+      // performance: if the toolchain context had the exact same configuration of its parent and
+      // that
+      // included feature flags, all the toolchain's dependencies would apply this transition
+      // individually. That creates a lot more potentially expensive applications of that transition
+      // (especially since manual trimming applies to every configured target in the build).
+      //
+      // In other words: without this modification:
+      // parent rule -> toolchain context -> toolchain
+      //     -> toolchain dep 1 # applies manual trimming to remove feature flags
+      //     -> toolchain dep 2 # applies manual trimming to remove feature flags
+      //     ...
+      //
+      // With this modification:
+      // parent rule -> toolchain context # applies manual trimming to remove feature flags
+      //     -> toolchain
+      //         -> toolchain dep 1
+      //         -> toolchain dep 2
+      //         ...
+      //
+      // None of this has any effect on rules that don't utilize manual trimming.
+      BuildOptions toolchainOptions =
+          toolchainTaggedTrimmingTransition.patch(
+              new BuildOptionsView(
+                  buildOptions, toolchainTaggedTrimmingTransition.requiresOptionFragments()),
+              eventHandler);
+      return BuildConfigurationKey.withoutPlatformMapping(toolchainOptions);
+    }
+
+    private ImmutableSet<Label> getExecutionPlatformConstraints(
+        Rule rule, @Nullable PlatformConfiguration platformConfiguration) {
+      if (platformConfiguration == null) {
+        return ImmutableSet.of(); // See NoConfigTransition.
+      }
+      NonconfigurableAttributeMapper mapper = NonconfigurableAttributeMapper.of(rule);
+      ImmutableSet.Builder<Label> execConstraintLabels = new ImmutableSet.Builder<>();
+
+      execConstraintLabels.addAll(rule.getRuleClassObject().getExecutionPlatformConstraints());
+      if (rule.getRuleClassObject()
+          .hasAttr(RuleClass.EXEC_COMPATIBLE_WITH_ATTR, BuildType.LABEL_LIST)) {
+        execConstraintLabels.addAll(
+            mapper.get(RuleClass.EXEC_COMPATIBLE_WITH_ATTR, BuildType.LABEL_LIST));
+      }
+
+      execConstraintLabels.addAll(
+          platformConfiguration.getAdditionalExecutionConstraintsFor(rule.getLabel()));
+
+      return execConstraintLabels.build();
+    }
+
+    @CanIgnoreReturnValue
+    public StateMachine computeConfigConditions(Tasks tasks) {
+      tasks.enqueue(
+          new ConfigConditionsProducer(
+              target,
+              preRuleTransitionKey.getLabel(),
+              preRuleTransitionKey.getConfigurationKey(),
+              platformInfo,
+              transitiveState,
+              (ConfigConditionsProducer.ResultSink) this,
+              this::computeTransition));
+      return DONE;
+    }
+
+    public StateMachine computeTransition(Tasks tasks) {
+      // logic to compute transition with ConfigConditions
+      var transitionData =
+          RuleTransitionData.create(
+              target.getAssociatedRule(),
+              configConditions != null ? configConditions.asProviders() : null,
+              preRuleTransitionKey.getConfigurationKey().getOptionsChecksum());
+
+      ConfigurationTransition transition = null;
+
+      TransitionFactory<RuleTransitionData> transitionFactory =
+          target.getAssociatedRule().getRuleClassObject().getTransitionFactory();
+      if (transitionFactory != null) {
+        transition = transitionFactory.create(transitionData);
+      }
+
+      boolean isAlias = target.getAssociatedRule().getName().equals("alias");
+
+      if (trimmingTransitionFactory != null && !isAlias) {
+        var trimmingTransition = trimmingTransitionFactory.create(transitionData);
+        if (transition != null) {
+          transition = ComposingTransition.of(transition, trimmingTransition);
+        } else {
+          transition = trimmingTransition;
+        }
+      }
       return new TransitionApplier(
           preRuleTransitionKey.getConfigurationKey(),
           transition,
@@ -289,6 +518,26 @@
       emitTransitionErrorMessage(e.getMessage());
     }
 
+    @Override
+    public void acceptConfigConditionsError(ConfiguredValueCreationException e) {
+      emitTransitionErrorMessage(e.getMessage());
+    }
+
+    @Override
+    public void acceptConfigConditions(ConfigConditions configConditions) {
+      this.configConditions = configConditions;
+    }
+
+    @Override
+    public void acceptPlatformInfo(PlatformInfo info) {
+      this.platformInfo = info;
+    }
+
+    @Override
+    public void acceptPlatformInfoError(InvalidPlatformException error) {
+      emitTransitionErrorMessage(error.getMessage());
+    }
+
     private StateMachine processTransitionedKey(Tasks tasks) {
       if (configurationKey == null) {
         return DONE; // There was an error.
@@ -400,22 +649,44 @@
 
   private void emitError(
       String message, @Nullable Location location, @Nullable DetailedExitCode exitCode) {
+    Cause cause =
+        new AnalysisFailedCause(
+            preRuleTransitionKey.getLabel(),
+            configurationIdMessage(preRuleTransitionKey.getConfigurationKey().getOptionsChecksum()),
+            exitCode != null ? exitCode : createDetailedExitCode(message));
     sink.acceptTargetAndConfigurationError(
         TargetAndConfigurationError.of(
             new ConfiguredValueCreationException(
+                target,
                 location,
                 message,
-                preRuleTransitionKey.getLabel(),
+                target.getLabel(),
                 configurationId(preRuleTransitionKey.getConfigurationKey()),
-                /* rootCauses= */ null,
-                exitCode)));
+                NestedSetBuilder.create(Order.STABLE_ORDER, cause),
+                exitCode != null ? exitCode : createDetailedExitCode(message))));
+  }
+
+  public static ConfigurationId configurationIdMessage(@Nullable String optionsCheckSum) {
+    if (optionsCheckSum == null) {
+      return ConfigurationId.newBuilder().setId("none").build();
+    }
+    return ConfigurationId.newBuilder().setId(optionsCheckSum).build();
+  }
+
+  public static DetailedExitCode createDetailedExitCode(String message) {
+    return DetailedExitCode.of(
+        FailureDetail.newBuilder()
+            .setMessage(message)
+            .setAnalysis(
+                Analysis.newBuilder().setCode(Analysis.Code.CONFIGURED_VALUE_CREATION_FAILED))
+            .build());
   }
 
   // Public for Cquery.
   @Nullable
   public static ConfigurationTransition computeTransition(
       Rule rule, @Nullable TransitionFactory<RuleTransitionData> trimmingTransitionFactory) {
-    var transitionData = RuleTransitionData.create(rule);
+    var transitionData = RuleTransitionData.create(rule, /* configConditions= */ null, "");
 
     ConfigurationTransition transition = null;
 
@@ -424,8 +695,8 @@
     if (transitionFactory != null) {
       transition = transitionFactory.create(transitionData);
     }
-
-    if (trimmingTransitionFactory != null) {
+    boolean isAlias = rule.getAssociatedRule().getName().equals("alias");
+    if (trimmingTransitionFactory != null && !isAlias) {
       var trimmingTransition = trimmingTransitionFactory.create(transitionData);
       if (transition != null) {
         transition = ComposingTransition.of(transition, trimmingTransition);
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleTransitionProvider.java b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleTransitionProvider.java
index a41e513..95f7780 100644
--- a/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleTransitionProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleTransitionProvider.java
@@ -17,24 +17,32 @@
 import static com.google.devtools.build.lib.analysis.starlark.FunctionTransitionUtil.applyAndValidate;
 
 import com.google.common.annotations.VisibleForTesting;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 import com.google.devtools.build.lib.analysis.config.BuildOptions;
 import com.google.devtools.build.lib.analysis.config.BuildOptionsView;
+import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
 import com.google.devtools.build.lib.analysis.config.StarlarkDefinedConfigTransition;
 import com.google.devtools.build.lib.analysis.config.transitions.PatchTransition;
 import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
+import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.EventHandler;
 import com.google.devtools.build.lib.packages.Attribute;
 import com.google.devtools.build.lib.packages.BuildType;
+import com.google.devtools.build.lib.packages.BuildType.SelectorList;
+import com.google.devtools.build.lib.packages.ConfiguredAttributeMapper;
 import com.google.devtools.build.lib.packages.RawAttributeMapper;
 import com.google.devtools.build.lib.packages.Rule;
 import com.google.devtools.build.lib.packages.RuleTransitionData;
 import com.google.devtools.build.lib.packages.StructImpl;
 import com.google.devtools.build.lib.packages.StructProvider;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Set;
 
 /**
  * Implements {@link TransitionFactory} to provide a starlark-defined transition that rules can
@@ -73,7 +81,11 @@
     // we wouldn't need {@code rule} in the cache key.
     return starlarkDefinedConfigTransition
         .getRuleTransitionCache()
-        .get(ruleData.rule(), this::createTransition);
+        .get(
+            ruleData,
+            x ->
+                createTransition(
+                    ruleData.rule(), ruleData.configConditions(), ruleData.configHash()));
   }
 
   @Override
@@ -81,15 +93,33 @@
     return TransitionType.RULE;
   }
 
-  private FunctionPatchTransition createTransition(Rule rule) {
+  private FunctionPatchTransition createTransition(
+      Rule rule, ImmutableMap<Label, ConfigMatchingProvider> configConditions, String configHash) {
     LinkedHashMap<String, Object> attributes = new LinkedHashMap<>();
     RawAttributeMapper attributeMapper = RawAttributeMapper.of(rule);
+    ConfiguredAttributeMapper configuredAttributeMapper =
+        ConfiguredAttributeMapper.of(rule, configConditions, configHash, false);
+    ImmutableList<String> transitionOutputs = this.starlarkDefinedConfigTransition.getOutputs();
     for (Attribute attribute : rule.getAttributes()) {
       Object val = attributeMapper.getRawAttributeValue(rule, attribute);
-      if (val instanceof BuildType.SelectorList) {
-        // For now, don't allow access to attributes that read selects.
-        // TODO(b/121134880): make this restriction more fine grained.
-        continue;
+      boolean shouldResolveSelect = true;
+      if (val instanceof BuildType.SelectorList && configConditions != null) {
+        for (Object label : ((SelectorList) val).getKeyLabels()) {
+          ConfigMatchingProvider configMatchingProvider = configConditions.get(label);
+          if (checkIfAttributeSelectOnAFlagTransitionChanges(
+              configMatchingProvider, transitionOutputs)) {
+            shouldResolveSelect = false;
+            break;
+          }
+        }
+        if (shouldResolveSelect) {
+          val =
+              configuredAttributeMapper.get(
+                  attribute.getName(),
+                  configuredAttributeMapper.getAttributeType(attribute.getName()));
+        } else {
+          continue;
+        }
       }
       attributes.put(
           Attribute.getStarlarkName(attribute.getPublicName()), Attribute.valueToStarlark(val));
@@ -97,12 +127,35 @@
     StructImpl attrObject =
         StructProvider.STRUCT.create(
             attributes,
-            "No attribute '%s'. Either this attribute does "
-                + "not exist for this rule or is set by a select. Starlark rule transitions "
-                + "currently cannot read attributes behind selects.");
+            "No attribute '%s'. Either this attribute does not exist for this rule or the attribute"
+                + " was not resolved because it is set by a select that reads flags the transition"
+                + " may set.");
     return new FunctionPatchTransition(attrObject);
   }
 
+  private boolean checkIfAttributeSelectOnAFlagTransitionChanges(
+      ConfigMatchingProvider configMatchingProvider, ImmutableList<String> transitionOutputs) {
+    // check settingMap
+    Set<String> nativeFlagLabels = new HashSet<>();
+    for (String key : configMatchingProvider.settingsMap().keySet()) {
+      String modified = "//command_line_option:" + key;
+      nativeFlagLabels.add(modified);
+    }
+    // check flags values
+    ImmutableMap<Label, String> flagSettingsMap = configMatchingProvider.flagSettingsMap();
+    Set<String> flagLabels = new HashSet<>();
+    for (Label flag : flagSettingsMap.keySet()) {
+      flagLabels.add(flag.getCanonicalForm());
+    }
+
+    for (String output : transitionOutputs) {
+      if (nativeFlagLabels.contains(output) || flagLabels.contains(output)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   /** The actual transition used by the rule. */
   private final class FunctionPatchTransition extends StarlarkTransition
       implements PatchTransition {
diff --git a/src/main/java/com/google/devtools/build/lib/packages/BUILD b/src/main/java/com/google/devtools/build/lib/packages/BUILD
index da7b1ed..dbe0b48 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/packages/BUILD
@@ -59,6 +59,7 @@
         "//src/main/java/com/google/devtools/build/docgen/annot",
         "//src/main/java/com/google/devtools/build/lib/actions:execution_requirements",
         "//src/main/java/com/google/devtools/build/lib/actions:thread_state_receiver",
+        "//src/main/java/com/google/devtools/build/lib/analysis:config/config_matching_provider",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/feature_set",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/fragment",
         "//src/main/java/com/google/devtools/build/lib/analysis:config/fragment_class_set",
diff --git a/src/main/java/com/google/devtools/build/lib/packages/RuleTransitionData.java b/src/main/java/com/google/devtools/build/lib/packages/RuleTransitionData.java
index 81d49ec..8fb037d 100644
--- a/src/main/java/com/google/devtools/build/lib/packages/RuleTransitionData.java
+++ b/src/main/java/com/google/devtools/build/lib/packages/RuleTransitionData.java
@@ -14,7 +14,11 @@
 package com.google.devtools.build.lib.packages;
 
 import com.google.auto.value.AutoValue;
+import com.google.common.collect.ImmutableMap;
+import com.google.devtools.build.lib.analysis.config.ConfigMatchingProvider;
 import com.google.devtools.build.lib.analysis.config.transitions.TransitionFactory;
+import com.google.devtools.build.lib.cmdline.Label;
+import javax.annotation.Nullable;
 
 /**
  * Helper class which contains data used by a {@link TransitionFactory} to create a transition for
@@ -23,9 +27,15 @@
 @AutoValue
 public abstract class RuleTransitionData implements TransitionFactory.Data {
 
-  public static RuleTransitionData create(Rule rule) {
-    return new AutoValue_RuleTransitionData(rule);
+  public static RuleTransitionData create(
+      Rule rule, ImmutableMap<Label, ConfigMatchingProvider> configConditions, String configHash) {
+    return new AutoValue_RuleTransitionData(rule, configConditions, configHash);
   }
 
   public abstract Rule rule();
+
+  @Nullable
+  public abstract ImmutableMap<Label, ConfigMatchingProvider> configConditions();
+
+  public abstract String configHash();
 }
diff --git a/src/main/java/com/google/devtools/build/lib/query2/cquery/TransitionsOutputFormatterCallback.java b/src/main/java/com/google/devtools/build/lib/query2/cquery/TransitionsOutputFormatterCallback.java
index d6a88b9..c5e965f 100644
--- a/src/main/java/com/google/devtools/build/lib/query2/cquery/TransitionsOutputFormatterCallback.java
+++ b/src/main/java/com/google/devtools/build/lib/query2/cquery/TransitionsOutputFormatterCallback.java
@@ -138,7 +138,11 @@
       if (factory != null) {
         output =
             factory
-                .create(RuleTransitionData.create(target.getAssociatedRule()))
+                .create(
+                    RuleTransitionData.create(
+                        target.getAssociatedRule(),
+                        null,
+                        ct.getConfigurationKey().getOptionsChecksum()))
                 .getName()
                 .concat(" -> ");
       }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
index f1fa6db..07c73b3 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
@@ -407,6 +407,7 @@
               new DependencyContextProducer(
                   unloadedToolchainContextsInputs,
                   targetAndConfiguration,
+                  key.getConfigurationKey(),
                   state.transitiveState,
                   (DependencyContextProducer.ResultSink) state));
     }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
index ba9caf5..0d7dd87 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/BUILD
@@ -1160,12 +1160,11 @@
     srcs = ["ConfiguredValueCreationException.java"],
     deps = [
         ":sane_analysis_exception",
-        "//src/main/java/com/google/devtools/build/lib/analysis:config/build_configuration",
-        "//src/main/java/com/google/devtools/build/lib/analysis:target_and_configuration",
         "//src/main/java/com/google/devtools/build/lib/buildeventstream/proto:build_event_stream_java_proto",
         "//src/main/java/com/google/devtools/build/lib/causes",
         "//src/main/java/com/google/devtools/build/lib/cmdline",
         "//src/main/java/com/google/devtools/build/lib/collect/nestedset",
+        "//src/main/java/com/google/devtools/build/lib/packages",
         "//src/main/java/com/google/devtools/build/lib/util:detailed_exit_code",
         "//src/main/java/net/starlark/java/syntax",
         "//src/main/protobuf:failure_details_java_proto",
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetEvaluationExceptions.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetEvaluationExceptions.java
index 7426866..bd71075 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetEvaluationExceptions.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetEvaluationExceptions.java
@@ -33,6 +33,7 @@
     private static ConfiguredValueCreationException withoutMessage(
         ConfiguredValueCreationException orig) {
       return new ConfiguredValueCreationException(
+          /* target= */ null,
           orig.getLocation(),
           "",
           /* label= */ null,
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
index d3139ad..6224ff7 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredTargetFunction.java
@@ -398,12 +398,16 @@
       return null;
     } catch (ActionConflictException e) {
       e.reportTo(env.getListener());
-      throw new ConfiguredValueCreationException(ctgValue, e.getMessage());
+      throw new ConfiguredValueCreationException(ctgValue.getTarget(), e.getMessage());
     } catch (InvalidExecGroupException e) {
-      throw new ConfiguredValueCreationException(ctgValue, e.getMessage());
+      throw new ConfiguredValueCreationException(ctgValue.getTarget(), e.getMessage());
     } catch (AnalysisFailurePropagationException e) {
       throw new ConfiguredValueCreationException(
-          ctgValue, e.getMessage(), /* rootCauses= */ null, e.getDetailedExitCode());
+          ctgValue.getTarget(),
+          /* buildEventId */ null,
+          e.getMessage(),
+          /* rootCauses= */ null,
+          e.getDetailedExitCode());
     }
 
     events.replayOn(env.getListener());
@@ -422,7 +426,11 @@
                               createDetailedExitCode(event.getMessage())))
                   .collect(Collectors.toList()));
       throw new ConfiguredValueCreationException(
-          ctgValue, "Analysis of target '" + target.getLabel() + "' failed", rootCauses, null);
+          ctgValue.getTarget(),
+          null,
+          "Analysis of target '" + target.getLabel() + "' failed",
+          rootCauses,
+          null);
     }
     Preconditions.checkState(
         !analysisEnvironment.hasErrors(), "Analysis environment hasError() but no errors reported");
@@ -462,6 +470,8 @@
                     configuredTargetKey,
                     ((ConfiguredRuleClassProvider) ruleClassProvider)
                         .getTrimmingTransitionFactory(),
+                    ((ConfiguredRuleClassProvider) ruleClassProvider)
+                        .getToolchainTaggedTrimmingTransition(),
                     buildViewProvider.getSkyframeBuildView().getStarlarkTransitionCache(),
                     state.computeDependenciesState.transitiveState,
                     (TargetAndConfigurationProducer.ResultSink) state,
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredValueCreationException.java b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredValueCreationException.java
index 4677573..837f637 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredValueCreationException.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/ConfiguredValueCreationException.java
@@ -13,15 +13,16 @@
 // limitations under the License.
 package com.google.devtools.build.lib.skyframe;
 
-import static com.google.devtools.build.lib.analysis.config.BuildConfigurationValue.configurationId;
 
-import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
 import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId.ConfigurationId;
 import com.google.devtools.build.lib.causes.AnalysisFailedCause;
 import com.google.devtools.build.lib.causes.Cause;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.Order;
+import com.google.devtools.build.lib.packages.Target;
 import com.google.devtools.build.lib.server.FailureDetails.Analysis;
 import com.google.devtools.build.lib.server.FailureDetails.Analysis.Code;
 import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
@@ -36,6 +37,8 @@
 public final class ConfiguredValueCreationException extends Exception
     implements SaneAnalysisException {
 
+  private final Target target;
+  private final Label label;
   @Nullable private final Location location;
   private final BuildEventId configuration;
   private final NestedSet<Cause> rootCauses;
@@ -44,6 +47,7 @@
   private final DetailedExitCode detailedExitCode;
 
   public ConfiguredValueCreationException(
+      @Nullable Target target,
       @Nullable Location location,
       String message,
       Label label,
@@ -51,36 +55,52 @@
       @Nullable NestedSet<Cause> rootCauses,
       @Nullable DetailedExitCode detailedExitCode) {
     super(message);
+    this.target = target;
+    this.label = label;
     this.location = location;
     this.configuration = configuration;
-    this.detailedExitCode =
+    DetailedExitCode exitCode =
         detailedExitCode != null ? detailedExitCode : createDetailedExitCode(message);
+    this.detailedExitCode = exitCode;
     this.rootCauses =
         rootCauses != null
             ? rootCauses
-            : NestedSetBuilder.<Cause>stableOrder()
-                .add(
-                    new AnalysisFailedCause(
-                        label, configuration.getConfiguration(), this.detailedExitCode))
-                .build();
+            : NestedSetBuilder.create(
+                Order.STABLE_ORDER, createRootCause(label, configuration, exitCode));
   }
 
   public ConfiguredValueCreationException(
-      TargetAndConfiguration ctgValue,
+      Target target,
+      @Nullable BuildEventId configuration,
       String message,
       @Nullable NestedSet<Cause> rootCauses,
       @Nullable DetailedExitCode detailedExitCode) {
     this(
-        ctgValue.getTarget().getLocation(),
+        target,
+        target.getLocation(),
         message,
-        ctgValue.getLabel(),
-        configurationId(ctgValue.getConfiguration()),
+        target.getLabel(),
+        configuration,
         rootCauses,
         detailedExitCode);
   }
 
-  public ConfiguredValueCreationException(TargetAndConfiguration ctgValue, String message) {
-    this(ctgValue, message, /*rootCauses=*/ null, /*detailedExitCode=*/ null);
+  public ConfiguredValueCreationException(@Nullable Target target, String message) {
+    this(
+        target,
+        /* configuration= */ null,
+        message,
+        /* rootCauses= */ null,
+        /* detailedExitCode= */ null);
+  }
+
+  @Nullable
+  public Target getTarget() {
+    return target;
+  }
+
+  public Label getLabel() {
+    return label;
   }
 
   @Nullable
@@ -109,4 +129,14 @@
             .setAnalysis(Analysis.newBuilder().setCode(Code.CONFIGURED_VALUE_CREATION_FAILED))
             .build());
   }
+
+  private static AnalysisFailedCause createRootCause(
+      Label label, BuildEventId configuration, DetailedExitCode detailedExitCode) {
+    return new AnalysisFailedCause(
+        label,
+        configuration == null
+            ? ConfigurationId.newBuilder().setId("none").build()
+            : configuration.getConfiguration(),
+        detailedExitCode);
+  }
 }
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/DependencyResolver.java b/src/main/java/com/google/devtools/build/lib/skyframe/DependencyResolver.java
index 0ff0d47..5c287c2 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/DependencyResolver.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/DependencyResolver.java
@@ -15,7 +15,9 @@
 
 import static com.google.common.collect.ImmutableSet.toImmutableSet;
 import static com.google.devtools.build.lib.analysis.config.BuildConfigurationValue.configurationId;
+import static com.google.devtools.build.lib.analysis.config.BuildConfigurationValue.configurationIdMessage;
 import static com.google.devtools.build.lib.analysis.config.transitions.TransitionCollector.NULL_TRANSITION_COLLECTOR;
+import static com.google.devtools.build.lib.analysis.producers.TargetAndConfigurationProducer.createDetailedExitCode;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
@@ -61,11 +63,13 @@
 import com.google.devtools.build.lib.analysis.producers.UnloadedToolchainContextsInputs;
 import com.google.devtools.build.lib.analysis.starlark.StarlarkAttributeTransitionProvider;
 import com.google.devtools.build.lib.analysis.starlark.StarlarkTransition.TransitionException;
+import com.google.devtools.build.lib.causes.AnalysisFailedCause;
 import com.google.devtools.build.lib.causes.Cause;
 import com.google.devtools.build.lib.cmdline.Label;
 import com.google.devtools.build.lib.cmdline.LabelSyntaxException;
 import com.google.devtools.build.lib.collect.nestedset.NestedSet;
 import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.Order;
 import com.google.devtools.build.lib.events.Event;
 import com.google.devtools.build.lib.events.ExtendedEventHandler;
 import com.google.devtools.build.lib.events.StoredEventHandler;
@@ -369,7 +373,8 @@
                 "Cannot compute config conditions"));
         throw new ReportedException(
             new ConfiguredValueCreationException(
-                targetAndConfiguration,
+                targetAndConfiguration.getTarget(),
+                configurationId(targetAndConfiguration.getConfiguration()),
                 "Cannot compute config conditions",
                 causes,
                 getPrioritizedDetailedExitCode(causes)));
@@ -397,7 +402,8 @@
         // BuildTool to handle. Calling code needs to be untangled for that to work and pass tests.
         throw new UnreportedException(
             new ConfiguredValueCreationException(
-                targetAndConfiguration,
+                targetAndConfiguration.getTarget(),
+                configurationId(targetAndConfiguration.getConfiguration()),
                 "Analysis failed",
                 causes,
                 getPrioritizedDetailedExitCode(causes)));
@@ -444,14 +450,15 @@
     if (splitval.size() < 2) {
       throw new UnreportedException(
           new ConfiguredValueCreationException(
-              targetAndConfiguration, "bad Starlark exec transition reference: " + bzlReference));
+              targetAndConfiguration.getTarget(),
+              "bad Starlark exec transition reference: " + bzlReference));
     }
     Label bzlFile;
     try {
       bzlFile = Label.parseCanonical(splitval.get(0));
     } catch (LabelSyntaxException e) {
       throw new UnreportedException(
-          new ConfiguredValueCreationException(targetAndConfiguration, e.getMessage()));
+          new ConfiguredValueCreationException(targetAndConfiguration.getTarget(), e.getMessage()));
     }
     BzlLoadValue bzlValue = (BzlLoadValue) env.getValue(BzlLoadValue.keyForBuild(bzlFile));
     if (bzlValue == null) {
@@ -461,7 +468,7 @@
     if (!(transition instanceof StarlarkDefinedConfigTransition)) {
       throw new UnreportedException(
           new ConfiguredValueCreationException(
-              targetAndConfiguration,
+              targetAndConfiguration.getTarget(),
               String.valueOf(transition) + " is not a Starlark transition"));
     }
     return Optional.of(
@@ -572,7 +579,11 @@
           cvce != null
               ? cvce
               : new ConfiguredValueCreationException(
-                  targetAndConfiguration, errorMessage, null, e.getDetailedExitCode()));
+                  targetAndConfiguration.getTarget(),
+                  configurationId(targetAndConfiguration.getConfiguration()),
+                  errorMessage,
+                  null,
+                  e.getDetailedExitCode()));
     } else if (untyped instanceof ConfiguredValueCreationException) {
       ConfiguredValueCreationException e = (ConfiguredValueCreationException) untyped;
       if (!e.getMessage().isEmpty()) {
@@ -588,7 +599,11 @@
       }
       throw new ReportedException(
           new ConfiguredValueCreationException(
-              targetAndConfiguration, e.getMessage(), e.getCauses(), e.getDetailedExitCode()));
+              targetAndConfiguration.getTarget(),
+              configurationId(targetAndConfiguration.getConfiguration()),
+              e.getMessage(),
+              e.getCauses(),
+              e.getDetailedExitCode()));
     } else if (untyped instanceof ToolchainException) {
       ToolchainException e = (ToolchainException) untyped;
       ConfiguredValueCreationException cvce =
@@ -717,12 +732,12 @@
           case DEPENDENCY_TRANSITION:
             {
               TransitionException e = error.dependencyTransition();
-              throw new ConfiguredValueCreationException(ctgValue, e.getMessage());
+              throw new ConfiguredValueCreationException(ctgValue.getTarget(), e.getMessage());
             }
           case DEPENDENCY_OPTIONS_PARSING:
             {
               OptionsParsingException e = error.dependencyOptionsParsing();
-              throw new ConfiguredValueCreationException(ctgValue, e.getMessage());
+              throw new ConfiguredValueCreationException(ctgValue.getTarget(), e.getMessage());
             }
           case INVALID_VISIBILITY:
             {
@@ -867,14 +882,20 @@
     BuildConfigurationValue configuration = targetAndConfiguration.getConfiguration();
     Label label = targetAndConfiguration.getLabel();
     listener.post(AnalysisRootCauseEvent.withConfigurationValue(configuration, label, message));
+    Cause cause =
+        new AnalysisFailedCause(
+            targetAndConfiguration.getLabel(),
+            configurationIdMessage(targetAndConfiguration.getConfiguration()),
+            createDetailedExitCode(message));
     return new DependencyEvaluationException(
         new ConfiguredValueCreationException(
+            targetAndConfiguration.getTarget(),
             location,
             message,
             label,
             configurationId(configuration),
-            /* rootCauses= */ null,
-            /* detailedExitCode= */ null),
+            NestedSetBuilder.create(Order.STABLE_ORDER, cause),
+            cause.getDetailedExitCode()),
         // These errors occur in dependency resolution, which is attached to the current target.
         // i.e. no dependent ConfiguredTargetFunction call happens to report its own error.
         /* depReportedOwnError= */ false);
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/BUILD b/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/BUILD
index c62a9dc..dc1bd67 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/BUILD
@@ -254,12 +254,17 @@
     name = "toolchain_exception",
     srcs = ["ToolchainException.java"],
     deps = [
+        "//src/main/java/com/google/devtools/build/lib/analysis:config/build_configuration",
         "//src/main/java/com/google/devtools/build/lib/analysis:target_and_configuration",
+        "//src/main/java/com/google/devtools/build/lib/buildeventstream/proto:build_event_stream_java_proto",
+        "//src/main/java/com/google/devtools/build/lib/causes",
+        "//src/main/java/com/google/devtools/build/lib/collect/nestedset",
         "//src/main/java/com/google/devtools/build/lib/skyframe:configured_value_creation_exception",
         "//src/main/java/com/google/devtools/build/lib/skyframe:detailed_exceptions",
         "//src/main/java/com/google/devtools/build/lib/util:detailed_exit_code",
         "//src/main/protobuf:failure_details_java_proto",
         "//third_party:guava",
+        "//third_party:jsr305",
     ],
 )
 
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/ToolchainException.java b/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/ToolchainException.java
index f121231..ccae8a6 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/ToolchainException.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/toolchains/ToolchainException.java
@@ -15,12 +15,20 @@
 
 import com.google.common.base.Strings;
 import com.google.devtools.build.lib.analysis.TargetAndConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildConfigurationValue;
+import com.google.devtools.build.lib.buildeventstream.BuildEventStreamProtos.BuildEventId.ConfigurationId;
+import com.google.devtools.build.lib.causes.AnalysisFailedCause;
+import com.google.devtools.build.lib.causes.Cause;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.Order;
 import com.google.devtools.build.lib.server.FailureDetails;
+import com.google.devtools.build.lib.server.FailureDetails.Analysis;
 import com.google.devtools.build.lib.server.FailureDetails.FailureDetail;
 import com.google.devtools.build.lib.server.FailureDetails.Toolchain.Code;
 import com.google.devtools.build.lib.skyframe.ConfiguredValueCreationException;
 import com.google.devtools.build.lib.skyframe.DetailedException;
 import com.google.devtools.build.lib.util.DetailedExitCode;
+import javax.annotation.Nullable;
 
 /** Base class for exceptions that happen during toolchain resolution. */
 public abstract class ToolchainException extends Exception implements DetailedException {
@@ -67,12 +75,38 @@
         return (ConfiguredValueCreationException) cause;
       }
     }
+    Cause cause =
+        new AnalysisFailedCause(
+            targetAndConfiguration.getLabel(),
+            configurationIdMessage(targetAndConfiguration.getConfiguration()),
+            createDetailedExitCode(
+                String.format(
+                    "While resolving toolchains for target %s: %s",
+                    targetAndConfiguration.getLabel(), getMessage())));
     return new ConfiguredValueCreationException(
-        targetAndConfiguration,
+        targetAndConfiguration.getTarget(),
+        targetAndConfiguration.getConfiguration().getEventId(),
         String.format(
             "While resolving toolchains for target %s: %s",
             targetAndConfiguration.getLabel(), getMessage()),
-        null,
+        NestedSetBuilder.create(Order.STABLE_ORDER, cause),
         getDetailedExitCode());
   }
+
+  public static ConfigurationId configurationIdMessage(
+      @Nullable BuildConfigurationValue configuration) {
+    if (configuration == null) {
+      return ConfigurationId.newBuilder().setId("none").build();
+    }
+    return ConfigurationId.newBuilder().setId(configuration.checksum()).build();
+  }
+
+  private static DetailedExitCode createDetailedExitCode(String message) {
+    return DetailedExitCode.of(
+        FailureDetail.newBuilder()
+            .setMessage(message)
+            .setAnalysis(
+                Analysis.newBuilder().setCode(Analysis.Code.CONFIGURED_VALUE_CREATION_FAILED))
+            .build());
+  }
 }
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/StarlarkRuleTransitionProviderTest.java b/src/test/java/com/google/devtools/build/lib/analysis/StarlarkRuleTransitionProviderTest.java
index 3267329..ba0bc22 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/StarlarkRuleTransitionProviderTest.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/StarlarkRuleTransitionProviderTest.java
@@ -292,7 +292,6 @@
     assertContainsEvent(
         "Rule transition only allowed to return a single transitioned configuration.");
   }
-
   @Test
   public void testCanDoBadStuffWithParameterizedTransitionsAndSelects() throws Exception {
     writeAllowlistFile();
@@ -339,8 +338,9 @@
     getConfiguredTarget("//test");
     assertContainsEvent(
         "No attribute 'my_configurable_attr'. "
-            + "Either this attribute does not exist for this rule or is set by a select. "
-            + "Starlark rule transitions currently cannot read attributes behind selects.");
+            + "Either this attribute does not exist for this rule or the attribute "
+            + "was not resolved because it is set by a select that reads flags the transition "
+            + "may set.");
   }
 
   @Test
@@ -1557,7 +1557,7 @@
         testTarget
             .getRuleClassObject()
             .getTransitionFactory()
-            .create(RuleTransitionData.create(testTarget));
+            .create(RuleTransitionData.create(testTarget, null, ""));
     RequiredConfigFragmentsProvider.Builder requiredFragments =
         RequiredConfigFragmentsProvider.builder();
     ruleTransition.addRequiredFragments(
diff --git a/src/test/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTransitionFactoryTest.java b/src/test/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTransitionFactoryTest.java
index ceb4711..2634388 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTransitionFactoryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/config/ConfigFeatureFlagTransitionFactoryTest.java
@@ -62,7 +62,7 @@
     Rule rule = scratchRule("a", "empty", "feature_flag_setter(name = 'empty', flag_values = {})");
     PatchTransition transition =
         new ConfigFeatureFlagTransitionFactory("flag_values")
-            .create(RuleTransitionData.create(rule));
+            .create(RuleTransitionData.create(rule, null, ""));
 
     BuildOptions original = getOptionsWithoutFlagFragment();
     BuildOptions converted =
@@ -88,7 +88,7 @@
             "    default_value = 'a')");
     PatchTransition transition =
         new ConfigFeatureFlagTransitionFactory("flag_values")
-            .create(RuleTransitionData.create(rule));
+            .create(RuleTransitionData.create(rule, null, ""));
 
     BuildOptions original = getOptionsWithoutFlagFragment();
     BuildOptions converted =
@@ -104,7 +104,7 @@
     Rule rule = scratchRule("a", "empty", "feature_flag_setter(name = 'empty', flag_values = {})");
     PatchTransition transition =
         new ConfigFeatureFlagTransitionFactory("flag_values")
-            .create(RuleTransitionData.create(rule));
+            .create(RuleTransitionData.create(rule, null, ""));
     Map<Label, String> originalFlagMap = ImmutableMap.of(Label.parseCanonical("//a:flag"), "value");
 
     BuildOptions original = getOptionsWithFlagFragment(originalFlagMap);
@@ -133,7 +133,7 @@
             "    default_value = 'a')");
     PatchTransition transition =
         new ConfigFeatureFlagTransitionFactory("flag_values")
-            .create(RuleTransitionData.create(rule));
+            .create(RuleTransitionData.create(rule, null, ""));
     Map<Label, String> originalFlagMap = ImmutableMap.of(Label.parseCanonical("//a:old"), "value");
     Map<Label, String> expectedFlagMap = ImmutableMap.of(Label.parseCanonical("//a:flag"), "a");
 
@@ -201,34 +201,34 @@
     new EqualsTester()
         .addEqualityGroup(
             // transition for non flags target
-            factory.create(RuleTransitionData.create(nonflag)), NoTransition.INSTANCE)
+            factory.create(RuleTransitionData.create(nonflag, null, "")), NoTransition.INSTANCE)
         .addEqualityGroup(
             // transition with empty map
-            factory.create(RuleTransitionData.create(empty)),
+            factory.create(RuleTransitionData.create(empty, null, "")),
             // transition produced by same factory on same rule
-            factory.create(RuleTransitionData.create(empty)),
+            factory.create(RuleTransitionData.create(empty, null, "")),
             // transition produced by similar factory on same rule
-            factory2.create(RuleTransitionData.create(empty)),
+            factory2.create(RuleTransitionData.create(empty, null, "")),
             // transition produced by same factory on similar rule
-            factory.create(RuleTransitionData.create(empty2)),
+            factory.create(RuleTransitionData.create(empty2, null, "")),
             // transition produced by similar factory on similar rule
-            factory2.create(RuleTransitionData.create(empty2)))
+            factory2.create(RuleTransitionData.create(empty2, null, "")))
         .addEqualityGroup(
             // transition with flag -> a
-            factory.create(RuleTransitionData.create(flagSetterA)),
+            factory.create(RuleTransitionData.create(flagSetterA, null, "")),
             // same map, different rule
-            factory.create(RuleTransitionData.create(flagSetterA2)),
+            factory.create(RuleTransitionData.create(flagSetterA2, null, "")),
             // same map, different factory
-            factory2.create(RuleTransitionData.create(flagSetterA)))
+            factory2.create(RuleTransitionData.create(flagSetterA, null, "")))
         .addEqualityGroup(
             // transition with flag set to different value
-            factory.create(RuleTransitionData.create(flagSetterB)))
+            factory.create(RuleTransitionData.create(flagSetterB, null, "")))
         .addEqualityGroup(
             // transition with different flag set to same value
-            factory.create(RuleTransitionData.create(flag2Setter)))
+            factory.create(RuleTransitionData.create(flag2Setter, null, "")))
         .addEqualityGroup(
             // transition with more flags set
-            factory.create(RuleTransitionData.create(bothSetter)))
+            factory.create(RuleTransitionData.create(bothSetter, null, "")))
         .testEquals();
   }
 
diff --git a/src/test/java/com/google/devtools/build/lib/rules/config/FeatureFlagManualTrimmingTest.java b/src/test/java/com/google/devtools/build/lib/rules/config/FeatureFlagManualTrimmingTest.java
index 4173c5c..5531aa0 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/config/FeatureFlagManualTrimmingTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/config/FeatureFlagManualTrimmingTest.java
@@ -839,7 +839,7 @@
         getConfiguration(getConfiguredTarget("//test:toplevel_target")).getOptions();
     PatchTransition transition =
         new ConfigFeatureFlagTaggedTrimmingTransitionFactory(BaseRuleClasses.TAGGED_TRIMMING_ATTR)
-            .create(RuleTransitionData.create((Rule) getTarget("//test:dep")));
+            .create(RuleTransitionData.create((Rule) getTarget("//test:dep"), null, ""));
     BuildOptions depOptions =
         transition.patch(
             new BuildOptionsView(topLevelOptions, transition.requiresOptionFragments()),
diff --git a/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeErrorProcessorTest.java b/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeErrorProcessorTest.java
index 7ea54c7..aa69a10 100644
--- a/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeErrorProcessorTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skyframe/SkyframeErrorProcessorTest.java
@@ -49,10 +49,11 @@
         ConfiguredTargetKey.builder()
             .setLabel(Label.parseCanonicalUnchecked("//analysis_err"))
             .build();
+    TargetAndConfiguration mockTargetAndConfiguration =
+        new TargetAndConfiguration(mock(Target.class), /* configuration= */ null);
     ConfiguredValueCreationException analysisException =
         new ConfiguredValueCreationException(
-            new TargetAndConfiguration(mock(Target.class), /* configuration= */ null),
-            "analysis exception");
+            mockTargetAndConfiguration.getTarget(), "analysis exception");
     ErrorInfo analysisErrorInfo =
         ErrorInfo.fromException(
             new ReifiedSkyFunctionException(
diff --git a/src/test/shell/integration/rule_transition_test.sh b/src/test/shell/integration/rule_transition_test.sh
new file mode 100755
index 0000000..6025381
--- /dev/null
+++ b/src/test/shell/integration/rule_transition_test.sh
@@ -0,0 +1,278 @@
+#!/bin/bash
+#
+# Copyright 2023 The Bazel Authors. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Test rule transition can inspect configurable attribute.
+
+# --- begin runfiles.bash initialization ---
+# Copy-pasted from Bazel's Bash runfiles library (tools/bash/runfiles/runfiles.bash).
+if [[ ! -d "${RUNFILES_DIR:-/dev/null}" && ! -f "${RUNFILES_MANIFEST_FILE:-/dev/null}" ]]; then
+  if [[ -f "$0.runfiles_manifest" ]]; then
+    export RUNFILES_MANIFEST_FILE="$0.runfiles_manifest"
+  elif [[ -f "$0.runfiles/MANIFEST" ]]; then
+    export RUNFILES_MANIFEST_FILE="$0.runfiles/MANIFEST"
+  elif [[ -f "$0.runfiles/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then
+    export RUNFILES_DIR="$0.runfiles"
+  fi
+fi
+if [[ -f "${RUNFILES_DIR:-/dev/null}/bazel_tools/tools/bash/runfiles/runfiles.bash" ]]; then
+  source "${RUNFILES_DIR}/bazel_tools/tools/bash/runfiles/runfiles.bash"
+elif [[ -f "${RUNFILES_MANIFEST_FILE:-/dev/null}" ]]; then
+  source "$(grep -m1 "^bazel_tools/tools/bash/runfiles/runfiles.bash " \
+            "$RUNFILES_MANIFEST_FILE" | cut -d ' ' -f 2-)"
+else
+  echo >&2 "ERROR: cannot find @bazel_tools//tools/bash/runfiles:runfiles.bash"
+  exit 1
+fi
+# --- end runfiles.bash initialization ---
+
+source "$(rlocation "io_bazel/src/test/shell/integration_test_setup.sh")" \
+  || { echo "integration_test_setup.sh not found!" >&2; exit 1; }
+
+function set_up() {
+  create_new_workspace
+}
+
+function create_transitions() {
+  local pkg="${1}"
+  mkdir -p "${pkg}"
+  cat > "${pkg}/def.bzl" <<EOF
+
+load("//third_party/bazel_skylib/rules:common_settings.bzl", "BuildSettingInfo")
+
+example_package = "${pkg}"
+
+def _transition_impl(settings, attr):
+    if getattr(attr, "apply_transition") and settings["//%s:transition_input_flag" % example_package]:
+        return {"//%s:transition_output_flag" % example_package: True}
+    return {"//%s:transition_output_flag" % example_package: False}
+
+example_transition = transition(
+    implementation = _transition_impl,
+    inputs = ["//%s:transition_input_flag" % example_package],
+    outputs = ["//%s:transition_output_flag" % example_package],
+)
+
+def _rule_impl(ctx):
+    print("Flag value for %s: %s" % (
+        ctx.label.name,
+        ctx.attr._transition_output_flag[BuildSettingInfo].value,
+    ))
+
+transition_attached = rule(
+    implementation = _rule_impl,
+    cfg = example_transition,
+    attrs = {
+        "apply_transition": attr.bool(default = False),
+        "deps": attr.label_list(),
+        "_transition_output_flag": attr.label(default = "//%s:transition_output_flag" % example_package),
+        "_allowlist_function_transition": attr.label(
+            default = "//tools/allowlists/function_transition_allowlist:function_transition_allowlist",
+        ),
+    },
+)
+
+transition_not_attached = rule(
+    implementation = _rule_impl,
+    attrs = {
+        "deps": attr.label_list(),
+        "_transition_output_flag": attr.label(default = "//%s:transition_output_flag" % example_package),
+    },
+)
+EOF
+}
+
+function create_rules_with_incoming_transition_and_selects() {
+  local pkg="${1}"
+  mkdir -p "${pkg}"
+  cat > "${pkg}/BUILD" <<EOF
+load(
+    "//${pkg}:def.bzl",
+    "transition_attached",
+    "transition_not_attached",
+)
+load("//third_party/bazel_skylib/rules:common_settings.bzl", "bool_flag")
+
+bool_flag(
+    name = "transition_input_flag",
+    build_setting_default = True,
+)
+
+bool_flag(
+    name = "transition_output_flag",
+    build_setting_default = False,
+)
+
+config_setting(
+    name = "select_setting",
+    flag_values = {":transition_input_flag": "True"},
+)
+
+# All should print "False" if
+# "--no//${pkg}:transition_input_flag" is
+# specified on the command line
+
+# bazel build :top_level will print the results for all of the targets below
+
+transition_attached(
+    name = "top_level",
+    apply_transition = select({
+        ":select_setting": True,
+        "//conditions:default": False,
+    }),
+    deps = [
+        ":transition_attached_dep",
+        ":transition_not_attached_dep",
+    ],
+)
+
+# Should print "False"
+transition_attached(
+    apply_transition = False,
+    name = "transition_attached_dep",
+    deps = [
+        ":transition_not_attached_dep_of_dep",
+    ],
+)
+
+# Should print "True" when building top_level, "False" otherwise
+transition_not_attached(
+    name = "transition_not_attached_dep",
+)
+
+# Should print "False"
+transition_not_attached(
+    name = "transition_not_attached_dep_of_dep",
+)
+EOF
+}
+
+function test_rule_transition_can_inspect_configure_attributes(){
+  local -r pkg="${FUNCNAME[0]}"
+  create_transitions "${pkg}"
+  create_rules_with_incoming_transition_and_selects "${pkg}"
+
+  bazel build "//${pkg}:top_level" &> $TEST_log || fail "Build failed"
+
+  expect_log 'Flag value for transition_not_attached_dep: True'
+  expect_log 'Flag value for transition_not_attached_dep_of_dep: False'
+  expect_log 'Flag value for transition_attached_dep: False'
+  expect_log 'Flag value for top_level: True'
+}
+
+function test_rule_transition_can_inspect_configure_attributes_with_flag(){
+  local -r pkg="${FUNCNAME[0]}"
+
+  create_transitions "${pkg}"
+  create_rules_with_incoming_transition_and_selects "${pkg}"
+
+  bazel build --no//${pkg}:transition_input_flag "//${pkg}:top_level" &> $TEST_log || fail "Build failed"
+
+  expect_log 'Flag value for transition_not_attached_dep: False'
+  expect_log 'Flag value for transition_not_attached_dep_of_dep: False'
+  expect_log 'Flag value for transition_attached_dep: False'
+  expect_log 'Flag value for top_level: False'
+}
+
+function test_rule_transition_can_not_inspect_configure_attribute() {
+  local -r pkg="${FUNCNAME[0]}"
+
+  # create transition definition
+  mkdir -p "${pkg}"
+  cat > "${pkg}/def.bzl" <<EOF
+
+load("//third_party/bazel_skylib/rules:common_settings.bzl", "BuildSettingInfo")
+
+example_package = "${pkg}"
+
+def _transition_impl(settings, attr):
+    if getattr(attr, "apply_transition") and settings["//%s:transition_input_flag" % example_package]:
+        return {"//%s:transition_output_flag" % example_package: True}
+    return {
+      "//%s:transition_output_flag" % example_package: False,
+      "//%s:transition_input_flag" % example_package: False
+    }
+
+example_transition = transition(
+    implementation = _transition_impl,
+    inputs = ["//%s:transition_input_flag" % example_package],
+    outputs = [
+      "//%s:transition_output_flag" % example_package,
+      "//%s:transition_input_flag" % example_package,
+    ],
+)
+
+def _rule_impl(ctx):
+    print("Flag value for %s: %s" % (
+        ctx.label.name,
+        ctx.attr._transition_output_flag[BuildSettingInfo].value,
+    ))
+
+transition_attached = rule(
+    implementation = _rule_impl,
+    cfg = example_transition,
+    attrs = {
+        "apply_transition": attr.bool(default = False),
+        "deps": attr.label_list(),
+        "_transition_output_flag": attr.label(default = "//%s:transition_output_flag" % example_package),
+        "_allowlist_function_transition": attr.label(
+            default = "//tools/allowlists/function_transition_allowlist:function_transition_allowlist",
+        ),
+    },
+)
+EOF
+
+  # create rules with transition attached
+  cat > "${pkg}/BUILD" <<EOF
+load(
+    "//${pkg}:def.bzl",
+    "transition_attached",
+)
+load("//third_party/bazel_skylib/rules:common_settings.bzl", "bool_flag")
+
+bool_flag(
+    name = "transition_input_flag",
+    build_setting_default = True,
+)
+
+bool_flag(
+    name = "transition_output_flag",
+    build_setting_default = False,
+)
+
+config_setting(
+    name = "select_setting",
+    flag_values = {":transition_input_flag": "True"},
+)
+
+# All should print "False" if
+# "--no//${pkg}:transition_input_flag" is
+# specified on the command line
+
+# bazel build :top_level will print the results for all of the targets below
+
+transition_attached(
+    name = "top_level",
+    apply_transition = select({
+        ":select_setting": True,
+        "//conditions:default": False,
+    }),
+)
+EOF
+  bazel build "//${pkg}:top_level" &> $TEST_log && fail "Build did NOT complete successfully"
+  expect_log "No attribute 'apply_transition'. Either this attribute does not exist for this rule or the attribute was not resolved because it is set by a select that reads flags the transition may set."
+}
+
+run_suite "rule transition tests"
diff --git a/src/test/shell/integration/toolchain_test.sh b/src/test/shell/integration/toolchain_test.sh
index 894d950..1a65538 100755
--- a/src/test/shell/integration/toolchain_test.sh
+++ b/src/test/shell/integration/toolchain_test.sh
@@ -1128,12 +1128,12 @@
   bazel build \
     --platforms="//${pkg}/platform:not_a_platform" \
     "//${pkg}/demo:use" &> $TEST_log && fail "Build failure expected"
-  expect_log "While resolving toolchains for target //${pkg}/demo:use: Target //${pkg}/platform:not_a_platform was referenced as a platform, but does not provide PlatformInfo"
+  expect_log "Target //${pkg}/platform:not_a_platform was referenced as a platform, but does not provide PlatformInfo"
 
   bazel build \
     --host_platform="//${pkg}/platform:not_a_platform" \
     "//${pkg}/demo:use" &> $TEST_log && fail "Build failure expected"
-  expect_log "While resolving toolchains for target //${pkg}/demo:use: Target //${pkg}/platform:not_a_platform was referenced as a platform, but does not provide PlatformInfo"
+  expect_log "Target //${pkg}/platform:not_a_platform was referenced as a platform, but does not provide PlatformInfo"
 }
 
 
@@ -1884,10 +1884,11 @@
 )
 EOF
 
+  echo "START DEBUGGING"
   bazel build \
     --platforms="//${pkg}:hello" \
     "//${pkg}:target" &> $TEST_log && fail "Build succeeded unexpectedly"
-  expect_log "While resolving toolchains for target //${pkg}:target: Target //${pkg}:hello was referenced as a platform, but does not provide PlatformInfo"
+  expect_log "Target //${pkg}:hello was referenced as a platform, but does not provide PlatformInfo"
 }