ambientAssetFactsOrFlare function

({SubstationFactsSnapshot snapshot, SubstationKey substation})? ambientAssetFactsOrFlare(
  1. TreeContext context, {
  2. required String consumer,
  3. SubstationKey? aspect,
})

The ambient pair a consumer needs to run resolveGridAssets — or null, having raised kAssetFactsUnavailableFlare EXACTLY once, when the station has not mounted SubstationFactsAssets (and, at an effect, a SubstationScope) yet.

ONE helper, two verbs (ADR-0008 D3). A BUILD passes its own constructor- stable aspect and WATCHES it with TreeContext.dependOnInheritedSeedOfExactType: the substation it resolves for is what it was authored as, so it needs no ambient scope and one seat's changed facts leave every other seat alone. A process EFFECT — a spawn, a route — omits aspect, READS both the snapshot and the ambient SubstationScope with the non-binding TreeContext.getInheritedSeedOfExactType, and takes the latest facts WITHOUT subscribing.

Absent facts are a MIGRATION state, not a violated invariant: a station composed before the projection existed still has repository-provided assets in its worktrees and a stack that must keep building, so this reports and degrades rather than refusing. Each caller owns what "degrade" means — the pre-resolution asset stack, the untouched worktree, the pre-resolution pathspec — and none of them fabricates a second selector answer. Once the ambient values ARE mounted the resolution is strict again: a snapshot missing the substation's own key still throws from resolveGridAssets.

Implementation

({SubstationFactsSnapshot snapshot, SubstationKey substation})?
ambientAssetFactsOrFlare(
  TreeContext context, {
  required String consumer,
  SubstationKey? aspect,
}) {
  final snapshot = aspect == null
      ? context.getInheritedSeedOfExactType<SubstationFactsSnapshot>()
      : context.dependOnInheritedSeedOfExactType<SubstationFactsSnapshot>(
          aspect: aspect,
        );
  // Only an EFFECT asks the tree which substation it is running under; a build
  // already knows, and subscribing to a scope it did not need would widen what
  // rebuilds it.
  final scope = aspect == null
      ? context.getInheritedSeedOfExactType<SubstationScope>()
      : null;
  final substation =
      aspect ?? (scope == null ? null : SubstationKey(scope.name));
  if (snapshot != null && substation != null) {
    return (snapshot: snapshot, substation: substation);
  }
  context.getInheritedSeedOfExactType<ServiceBundle>()?.transport?.flare(
    kAssetFactsUnavailableFlare,
    <String, String>{
      'consumer': consumer,
      'missing': <String>[
        if (snapshot == null) 'snapshot',
        if (aspect == null && scope == null) 'scope',
      ].join(','),
    },
  );
  return null;
}