Restore distractor-specific follow-up questions

This commit is contained in:
hz
2026-08-01 18:06:52 -05:00
parent 8c5aa17d89
commit c7f5006cb6
14 changed files with 76770 additions and 100 deletions
@@ -49,6 +49,21 @@ public static class QuestionValidator
if (!entry.Value.Choices.Any(choice => choice.Id == entry.Value.CorrectChoiceId))
return "wrongAnswerFollowups correctChoiceId must match a follow-up choice id";
}
if (req.IsPublished)
{
if (req.WrongAnswerFollowups.Any(entry => entry.Value.Choices.Count != 3))
return "published wrongAnswerFollowups require exactly three choices per distractor";
if (!AllDistinct(req.WrongAnswerFollowups.Values.Select(value => value.Prompt)))
return "published wrongAnswerFollowups require a different prompt for every distractor";
if (!AllDistinct(req.WrongAnswerFollowups.Values.Select(value => value.TeachingPoint)))
return "published wrongAnswerFollowups require a different teachingPoint for every distractor";
if (!AllDistinct(req.WrongAnswerFollowups.Values.Select(value =>
value.Choices.Single(choice => choice.Id == value.CorrectChoiceId).Text)))
return "published wrongAnswerFollowups require a different correct follow-up answer for every distractor";
if (!AllDistinct(req.WrongAnswerFollowups.Values.Select(value => string.Join("|",
value.Choices.Select(choice => Normalize(choice.Text)).OrderBy(text => text, StringComparer.Ordinal)))))
return "published wrongAnswerFollowups require a different choice set for every distractor";
}
if (req.ReviewFollowups is null) return "reviewFollowups must be an array";
if (req.ReviewFollowups.Count > 10) return "questions support at most ten review follow-ups";
@@ -75,6 +90,16 @@ public static class QuestionValidator
return null;
}
private static bool AllDistinct(IEnumerable<string> values)
{
var normalized = values.Select(Normalize).ToList();
return normalized.All(value => value.Length > 0)
&& normalized.Distinct(StringComparer.Ordinal).Count() == normalized.Count;
}
private static string Normalize(string value) => string.Join(' ', value.Trim().ToLowerInvariant()
.Split((char[]?)null, StringSplitOptions.RemoveEmptyEntries));
public static string? ValidateLabs(IReadOnlyCollection<QuestionLab>? labs, bool requireComplete)
{
if (labs is null)