start method

Future<void> start(
  1. HintTour tour
)

Start a tour: typo validation → machine → seeding of already-mounted targets. The wait-for-target timer is armed by a machine effect.

Async deliberately: (1) the typo AssertionError goes into the Future (loud failure in debug from expectLater) instead of being thrown in the middle of someone's build; (2) later start will await fetching a server-driven tour — the signature is already ready and won't need a breaking change.

Implementation

Future<void> start(HintTour tour) async {
  assert(
    _machine.state.isIdle,
    "hintful: start('${tour.id}') while ${_machine.state} is active"
    ' — one tour at a time',
  );
  assert(
    tour.duplicateTargetIds.isEmpty,
    "hintful: tour '${tour.id}' has duplicate step targetIds:"
    ' ${tour.duplicateTargetIds.join(', ')}',
  );

  final classification = classifyStepTargets(
    tour,
    Set<String>.of(_registry.ids),
  );
  if (classification.typos.isNotEmpty) {
    final message = _describeTypos(tour, classification.typos);
    assert(false, message); // debug: loud failure with candidates
    tour = _withoutTypoSteps(tour, classification.typos); // release: skip
    if (tour.steps.isEmpty) return; // nothing to show
  }

  _dispatch(HintStart(tour: tour));

  // Already-mounted targets will not fire onChange (the registry did not
  // change) — seed them synchronously, otherwise waiting(0) would spin
  // forever.
  for (final id in _registry.ids) {
    _dispatch(TargetAppeared(targetId: id));
  }
  _lastKnownIds = _registry.ids;
}