/// Viability status of a seed lot, derived purely from its age versus the /// species' typical seed longevity (bundled reference data). Turns passive /// storage into active stewardship: it surfaces which lots to sow or regenerate /// before they lapse, instead of just accumulating them. enum SeedViability { /// Comfortably within the species' typical viability window. fresh, /// In the final year of the window — sow or reproduce this season. expiringSoon, /// Past the typical viability window — germination is likely dropping fast. expired, /// Not enough data to judge (no harvest year, or no reference figure). unknown, } /// Computes the viability status of a seed lot harvested in [harvestYear] for a /// species whose typical longevity is [viabilityYears], as of [currentYear]. /// /// A conservative, age-based signal: the bundled figure is a single number, not /// a decay curve, so this only distinguishes "fine / use soon / past it". /// [expiringSoon] flags the last year of the window so the grower can prioritise /// what to reproduce before it lapses. Any actual [GerminationTest] a grower /// records remains the ground truth and is shown alongside this estimate. SeedViability seedViability({ required int? harvestYear, required int? viabilityYears, required int currentYear, }) { if (harvestYear == null || viabilityYears == null || viabilityYears <= 0) { return SeedViability.unknown; } final age = currentYear - harvestYear; // A harvest stamped in the future is treated as fresh, not expired. if (age < 0) return SeedViability.fresh; if (age >= viabilityYears) return SeedViability.expired; if (age >= viabilityYears - 1) return SeedViability.expiringSoon; return SeedViability.fresh; }