Compare recent changes from module snapshots

This commit is contained in:
2026-06-09 21:20:53 +00:00
parent 479d144592
commit 816cfb24aa
17 changed files with 508 additions and 346 deletions

View File

@@ -530,7 +530,7 @@ func GenerateReport(ctx context.Context, req ReportRequest) (*ReportResult, erro
return nil, err
}
recentChanges, err := recentChanges(ctx, store, priorSnapshot, briefingPackage, req.Config.RecentChange)
recentChanges, err := recentChanges(ctx, store, priorSnapshot, req.Resolved.Definition.ID, moduleSnapshot, req.Config.RecentChange)
if err != nil {
return nil, err
}
@@ -988,11 +988,11 @@ func defaultStore(cfg config.Config) (*state.FilesystemStore, error) {
return state.NewFilesystemStore(cfg.Workspace)
}
func recentChanges(ctx context.Context, store state.Store, priorSnapshot *state.PriorSnapshot, current briefing.Package, cfg config.RecentChangeConfig) ([]changes.Change, error) {
func recentChanges(ctx context.Context, store state.Store, priorSnapshot *state.PriorSnapshot, reportID report.ID, current module.Snapshot, cfg config.RecentChangeConfig) ([]changes.Change, error) {
if priorSnapshot == nil {
return nil, nil
}
previous, err := store.LoadBriefing(ctx, priorSnapshot.BriefingPath)
previous, err := store.LoadModuleSnapshot(ctx, priorSnapshot.ModuleSnapshotPath)
if err != nil {
return nil, err
}
@@ -1002,7 +1002,7 @@ func recentChanges(ctx context.Context, store state.Store, priorSnapshot *state.
WindGustMilesPerHour: cfg.WindGustMilesPerHour,
PrecipTimingShiftMinutes: cfg.PrecipTimingShiftMinutes,
}
switch current.Metadata.ReportID {
switch reportID {
case report.DailyToday, report.DailyTomorrow:
return changes.CompareDaily(previous, current, thresholds)
case report.ThreeDay:

View File

@@ -20,6 +20,7 @@ import (
"gitea.maximumdirect.net/eric/weatherreporter/internal/promptinput"
"gitea.maximumdirect.net/eric/weatherreporter/internal/report"
"gitea.maximumdirect.net/eric/weatherreporter/internal/state"
"gitea.maximumdirect.net/eric/weatherreporter/internal/timeutil"
)
func TestFetchAndSaveBundle(t *testing.T) {
@@ -655,25 +656,7 @@ func TestGenerateReportIncludesRecentChangesFromPriorSnapshot(t *testing.T) {
t.Fatalf("ResolveGenerate(prior) error = %v", err)
}
priorBriefing := priorDailyBriefing(priorResolved)
priorBriefingPath, err := store.SaveBriefing(context.Background(), priorResolved, priorBriefing)
if err != nil {
t.Fatalf("SaveBriefing() error = %v", err)
}
priorPaths, err := store.Paths(priorResolved)
if err != nil {
t.Fatalf("Paths() error = %v", err)
}
_, err = store.SaveMetadata(context.Background(), state.BuildMetadata(priorResolved, priorBriefing, state.ArtifactPaths{
Briefing: priorBriefingPath,
ModuleSnapshot: priorPaths.ModuleSnapshot,
Metadata: priorPaths.Metadata,
DataPackage: priorPaths.DataPackage,
Preflight: priorPaths.Preflight,
RenderedReport: priorPaths.RenderedReport,
}))
if err != nil {
t.Fatalf("SaveMetadata() error = %v", err)
}
savePriorRun(t, store, priorResolved, priorBriefing, priorDailyModuleSnapshot(t, priorResolved))
currentResolved, err := ResolveGenerate(GenerateRequest{
Config: cfg,
@@ -771,25 +754,7 @@ func TestTomorrowReportCanCompareAgainstPriorDailySnapshot(t *testing.T) {
t.Fatalf("ResolveGenerate(prior) error = %v", err)
}
priorBriefing := priorDailyBriefing(priorResolved)
priorBriefingPath, err := store.SaveBriefing(context.Background(), priorResolved, priorBriefing)
if err != nil {
t.Fatalf("SaveBriefing() error = %v", err)
}
priorPaths, err := store.Paths(priorResolved)
if err != nil {
t.Fatalf("Paths() error = %v", err)
}
_, err = store.SaveMetadata(context.Background(), state.BuildMetadata(priorResolved, priorBriefing, state.ArtifactPaths{
Briefing: priorBriefingPath,
ModuleSnapshot: priorPaths.ModuleSnapshot,
Metadata: priorPaths.Metadata,
DataPackage: priorPaths.DataPackage,
Preflight: priorPaths.Preflight,
RenderedReport: priorPaths.RenderedReport,
}))
if err != nil {
t.Fatalf("SaveMetadata() error = %v", err)
}
savePriorRun(t, store, priorResolved, priorBriefing, priorDailyModuleSnapshot(t, priorResolved))
currentResolved, err := ResolveGenerate(GenerateRequest{
Config: cfg,
@@ -839,25 +804,7 @@ func TestGenerateThreeDayReportWritesReportAndRecentChanges(t *testing.T) {
t.Fatalf("ResolveGenerate(prior) error = %v", err)
}
priorBriefing := priorThreeDayBriefing(priorResolved)
priorBriefingPath, err := store.SaveBriefing(context.Background(), priorResolved, priorBriefing)
if err != nil {
t.Fatalf("SaveBriefing() error = %v", err)
}
priorPaths, err := store.Paths(priorResolved)
if err != nil {
t.Fatalf("Paths() error = %v", err)
}
_, err = store.SaveMetadata(context.Background(), state.BuildMetadata(priorResolved, priorBriefing, state.ArtifactPaths{
Briefing: priorBriefingPath,
ModuleSnapshot: priorPaths.ModuleSnapshot,
Metadata: priorPaths.Metadata,
DataPackage: priorPaths.DataPackage,
Preflight: priorPaths.Preflight,
RenderedReport: priorPaths.RenderedReport,
}))
if err != nil {
t.Fatalf("SaveMetadata() error = %v", err)
}
savePriorRun(t, store, priorResolved, priorBriefing, priorOutlookModuleSnapshot(t, "2026-05-30"))
currentResolved, err := ResolveGenerate(GenerateRequest{
Config: cfg,
Report: ReportThreeDay,
@@ -916,25 +863,7 @@ func TestGenerateWeekendReportWritesReportAndRecentChanges(t *testing.T) {
t.Fatalf("ResolveGenerate(prior) error = %v", err)
}
priorBriefing := priorWeekendBriefing(priorResolved)
priorBriefingPath, err := store.SaveBriefing(context.Background(), priorResolved, priorBriefing)
if err != nil {
t.Fatalf("SaveBriefing() error = %v", err)
}
priorPaths, err := store.Paths(priorResolved)
if err != nil {
t.Fatalf("Paths() error = %v", err)
}
_, err = store.SaveMetadata(context.Background(), state.BuildMetadata(priorResolved, priorBriefing, state.ArtifactPaths{
Briefing: priorBriefingPath,
ModuleSnapshot: priorPaths.ModuleSnapshot,
Metadata: priorPaths.Metadata,
DataPackage: priorPaths.DataPackage,
Preflight: priorPaths.Preflight,
RenderedReport: priorPaths.RenderedReport,
}))
if err != nil {
t.Fatalf("SaveMetadata() error = %v", err)
}
savePriorRun(t, store, priorResolved, priorBriefing, priorOutlookModuleSnapshot(t, "2026-05-30"))
currentResolved, err := ResolveGenerate(GenerateRequest{
Config: cfg,
Report: ReportWeekend,
@@ -1475,6 +1404,82 @@ func priorDailyBriefing(resolved report.Resolved) briefing.Package {
}
}
func savePriorRun(t *testing.T, store state.Store, resolved report.Resolved, briefingPackage briefing.Package, snapshot module.Snapshot) {
t.Helper()
briefingPath, err := store.SaveBriefing(context.Background(), resolved, briefingPackage)
if err != nil {
t.Fatalf("SaveBriefing() error = %v", err)
}
moduleSnapshotPath, err := store.SaveModuleSnapshot(context.Background(), resolved, snapshot)
if err != nil {
t.Fatalf("SaveModuleSnapshot() error = %v", err)
}
paths, err := store.Paths(resolved)
if err != nil {
t.Fatalf("Paths() error = %v", err)
}
_, err = store.SaveMetadata(context.Background(), state.BuildMetadata(resolved, briefingPackage, state.ArtifactPaths{
Briefing: briefingPath,
ModuleSnapshot: moduleSnapshotPath,
Metadata: paths.Metadata,
DataPackage: paths.DataPackage,
Preflight: paths.Preflight,
RenderedReport: paths.RenderedReport,
}))
if err != nil {
t.Fatalf("SaveMetadata() error = %v", err)
}
}
func priorDailyModuleSnapshot(t *testing.T, resolved report.Resolved) module.Snapshot {
t.Helper()
low := 50
high := 58
precip := 10
snapshot, err := module.NewSnapshot([]module.Output{
{ID: module.DerivedDailySummary, StanzaName: "derived_daily_summary", Value: map[string]any{
"date": resolved.ValidPeriod.Start.Format(timeutil.DateLayout),
"low_temp_f": low,
"high_temp_f": high,
"max_pop_percent": precip,
}},
{ID: module.DerivedDaypartSummaries, StanzaName: "derived_daypart_summaries", Value: map[string]any{
"morning": map[string]any{
"period": timeutil.Period{Start: resolved.ValidPeriod.Start.Add(6 * time.Hour), End: resolved.ValidPeriod.Start.Add(10 * time.Hour)},
"temp_range_f": "50-58",
},
}},
{ID: module.PrecipTiming, StanzaName: "precip_timing", Value: map[string]any{
"max_pop_percent": precip,
"max_pop_time": "6 AM",
}},
{ID: module.AlertDigest, StanzaName: "alert_digest", Value: map[string]any{}},
})
if err != nil {
t.Fatalf("NewSnapshot() error = %v", err)
}
return snapshot
}
func priorOutlookModuleSnapshot(t *testing.T, date string) module.Snapshot {
t.Helper()
precip := 10
snapshot, err := module.NewSnapshot([]module.Output{
{ID: module.DerivedDaypartSummaries, StanzaName: "derived_daypart_summaries", Value: map[string]any{
date + "_morning": map[string]any{
"period": timeutil.Period{Start: mustParse(date + "T06:00:00Z"), End: mustParse(date + "T10:00:00Z")},
"temp_range_f": "50-58",
"max_pop_percent": precip,
"max_pop_time": "6 AM",
},
}},
})
if err != nil {
t.Fatalf("NewSnapshot() error = %v", err)
}
return snapshot
}
func priorThreeDayBriefing(resolved report.Resolved) briefing.Package {
high := 58.0
precip := 10.0