Merge branch 'phase/73-lesson-marks'

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Leonid Pershin
2026-08-21 12:00:53 +03:00
co-authored by Cursor
17 changed files with 703 additions and 22 deletions
+59
View File
@@ -0,0 +1,59 @@
using HSchool.Content;
namespace HSchool.People;
/// <summary>One lesson mark (25). Sparse list on the person — not a year-long gradebook.</summary>
public sealed class LessonMarkRecord
{
public required string Subject { get; init; }
public required int Value { get; init; }
public required DateTime Time { get; init; }
public required int Period { get; init; }
}
/// <summary>Appends recent lesson marks and drops the oldest when over the BehaviorDef ceiling.</summary>
public static class LessonMarkMemory
{
public static bool Record(
Person person,
string subject,
int value,
DateTime time,
int period,
BehaviorDef rules)
{
ArgumentNullException.ThrowIfNull(person);
ArgumentNullException.ThrowIfNull(rules);
ArgumentException.ThrowIfNullOrWhiteSpace(subject);
if (rules.LessonMarkMax <= 0 || value is < 2 or > 5)
{
return false;
}
var list = person.LessonMarks;
if (list is null)
{
list = [];
person.LessonMarks = list;
}
list.Add(new LessonMarkRecord
{
Subject = subject,
Value = value,
Time = DateTime.SpecifyKind(time, DateTimeKind.Utc),
Period = period,
});
while (list.Count > rules.LessonMarkMax)
{
list.RemoveAt(0);
}
return true;
}
}
+6
View File
@@ -75,6 +75,12 @@ public sealed record Person
/// </summary>
public List<OffenseRecord>? Offenses { get; set; }
/// <summary>
/// Recent lesson marks (25). Null when empty so people.json stays compact.
/// Ceiling and thresholds live on <c>BehaviorDef</c>.
/// </summary>
public List<LessonMarkRecord>? LessonMarks { get; set; }
public int AgeOn(DateTime asOf) => SchoolYears.AgeYears(BirthDate, asOf);
}