decideReadiness function

ReadinessVerdict decideReadiness({
  1. required String? grade,
  2. required String rationale,
})

The readiness MATRIX (pure — zero I/O; the whole decision, unit-testable).

  1. a MISSING/blank grade ⇒ ReadinessAbsent — the lane published NOTHING this round, so there is nothing to route over. Absence is a join state, not a verdict: the caller waits for the lane to publish and re-reads, and only a lane that FINISHED silent is a failure. The fail direction stays SAFE by construction (ADR-0000 A13(7)): absence never ADVANCES — what it stopped doing is minting a governor gate that names no finding.
  2. A/B/C ⇒ ReadinessDrive — the bead is specifiable.
  3. anything else (D/E/F, or an off-ladder letter) ⇒ ReadinessHold (not-ready) carrying the lens's rationale VERBATIM as the ask. A PRESENT failing grade is the ONLY hold this ladder mints.

There is no auto-fix arm (unlike the spec route's RESPEC, respec.dart): a respec re-runs an AGENT that can rewrite the spec, but nothing in this circuit rewrites the BEAD — refining it is the governor's lever, so the only honest not-ready outcome is a hold.

Implementation

ReadinessVerdict decideReadiness({
  required String? grade,
  required String rationale,
}) {
  final raw = grade?.trim() ?? '';
  if (raw.isEmpty) return const ReadinessAbsent();
  final letter = raw.toUpperCase();
  if (letter == 'A' || letter == 'B' || letter == 'C') {
    return ReadinessDrive(letter);
  }
  return ReadinessHold(
    rule: 'not-ready',
    reason: renderRefinementAsk(grade: letter, rationale: rationale.trim()),
  );
}