Add functional simulation question review

This commit is contained in:
hz
2026-07-14 17:49:23 -05:00
parent 3e39a4ffce
commit 705f079997
13 changed files with 551 additions and 32 deletions
@@ -33,6 +33,8 @@ public class ExamSimulationStore
_metrics = metrics;
_simulations.Indexes.CreateOne(new CreateIndexModel<ExamSimulation>(
Builders<ExamSimulation>.IndexKeys.Ascending(item => item.UserId).Ascending(item => item.State)));
_simulations.Indexes.CreateOne(new CreateIndexModel<ExamSimulation>(
Builders<ExamSimulation>.IndexKeys.Ascending(item => item.UserId).Ascending(item => item.State).Descending(item => item.CompletedUtc)));
_simulations.Indexes.CreateOne(new CreateIndexModel<ExamSimulation>(
Builders<ExamSimulation>.IndexKeys.Ascending(item => item.UpdatedUtc)));
_outcomes.Indexes.CreateOne(new CreateIndexModel<Step3Outcome>(
@@ -136,8 +138,8 @@ public class ExamSimulationStore
Score = ExamSimulationScoring.Calculate(items, responseMap, questionMap),
BlueprintTargets = targets,
BlueprintActual = items.GroupBy(item => item.BlueprintCategory).ToDictionary(group => group.Key, group => group.Count()),
ReviewQuestions = items.Select(item => QuestionResponse.FromModel(
questionMap[item.QuestionExternalId], questionElo: item.QuestionElo, includeChoicePool: true)).ToList()
ReviewQuestions = items.Select(item => QuestionResponse.FromModelWithChoices(
questionMap[item.QuestionExternalId], item.PresentedChoiceIds, item.QuestionElo)).ToList()
};
}
@@ -154,6 +156,33 @@ public class ExamSimulationStore
return simulation;
}
public async Task<CompletedExamSimulationPage> GetCompletedAsync(string userId, int limit, DateTime? before)
{
limit = Math.Clamp(limit, 1, 50);
var filter = Builders<ExamSimulation>.Filter.Eq(item => item.UserId, userId) &
Builders<ExamSimulation>.Filter.Eq(item => item.State, ExamSimulationStates.Completed);
if (before is not null)
filter &= Builders<ExamSimulation>.Filter.Lt(item => item.CompletedUtc, before.Value);
var simulations = await _simulations.Find(filter).SortByDescending(item => item.CompletedUtc).Limit(limit + 1).ToListAsync();
var hasMore = simulations.Count > limit;
if (hasMore) simulations.RemoveAt(simulations.Count - 1);
return new CompletedExamSimulationPage
{
Items = simulations.Select(item => new CompletedExamSimulationSummary
{
Id = item.Id ?? "",
CompletedUtc = item.CompletedUtc ?? item.UpdatedUtc,
PredictedScore = item.Score?.PredictedScore ?? 0,
RangeLow = item.Score?.RangeLow ?? 0,
RangeHigh = item.Score?.RangeHigh ?? 0,
Correct = item.Score?.Correct ?? 0,
Total = item.Score?.Total ?? item.Items.Count,
SeenCount = item.Score?.SeenCount ?? 0
}).ToList(),
NextBefore = hasMore && simulations.Count > 0 ? simulations[^1].CompletedUtc : null
};
}
public async Task<ExamSimulation> StartNextBlockAsync(ExamSimulation simulation)
{
if (simulation.State != ExamSimulationStates.BetweenBlocks)
@@ -244,7 +273,7 @@ public class ExamSimulationStore
{
response.ReviewQuestions = simulation.Items.OrderBy(item => item.BlockIndex).ThenBy(item => item.Position)
.Where(item => questionMap.ContainsKey(item.QuestionExternalId))
.Select(item => QuestionResponse.FromModel(questionMap[item.QuestionExternalId], questionElo: item.QuestionElo, includeChoicePool: true)).ToList();
.Select(item => QuestionResponse.FromModelWithChoices(questionMap[item.QuestionExternalId], item.PresentedChoiceIds, item.QuestionElo)).ToList();
}
return response;
}