Add Today report to morning batch

This commit is contained in:
2026-06-15 14:54:37 +00:00
parent 8ff5c44324
commit 3d5f71e72d
15 changed files with 431 additions and 32 deletions

View File

@@ -1338,6 +1338,93 @@ func TestGenerateReportIncludesRecentChangesFromPriorSnapshot(t *testing.T) {
}
}
func TestGenerateTodayReportUsesTodayIdentityAndRecentChanges(t *testing.T) {
server := dailyBundleServer(t)
cfg := config.Defaults()
cfg.WeatherAPI.BaseURL = server.URL + "/"
cfg.WeatherAPI.Timezone = "America/Chicago"
cfg.Workspace.Root = t.TempDir()
store, err := state.NewFilesystemStore(cfg.Workspace)
if err != nil {
t.Fatalf("NewFilesystemStore() error = %v", err)
}
priorResolved, err := ResolveGenerate(GenerateRequest{
Config: cfg,
Report: ReportKind(report.CommandNameToday),
Date: mustParse("2026-05-29T12:00:00-05:00"),
}, mustParse("2026-05-29T04:00:00-05:00"))
if err != nil {
t.Fatalf("ResolveGenerate(prior) error = %v", err)
}
savePriorRun(t, store, priorResolved, priorDailyModuleSnapshot(t, priorResolved))
currentResolved, err := ResolveGenerate(GenerateRequest{
Config: cfg,
Report: ReportKind(report.CommandNameToday),
Date: mustParse("2026-05-29T12:00:00-05:00"),
}, mustParse("2026-05-29T05:00:00-05:00"))
if err != nil {
t.Fatalf("ResolveGenerate(current) error = %v", err)
}
renderer := &recordingRenderer{
renderResult: &scriptorium.RenderResult{ExitCode: 0},
structuredRunResult: &scriptorium.StructuredRunResult{ExitCode: 0},
structuredRunBody: validTodayGeneratedTextJSON(),
}
result, err := GenerateReport(context.Background(), ReportRequest{
Config: cfg,
Resolved: currentResolved,
Renderer: renderer,
Store: store,
})
if err != nil {
t.Fatalf("GenerateReport() error = %v", err)
}
if renderer.runCalls != 0 || renderer.structuredRunCalls != 1 {
t.Fatalf("renderer calls run=%d structured=%d, want generated-text flow", renderer.runCalls, renderer.structuredRunCalls)
}
if result.Metadata.ReportID != report.Today || result.Metadata.Variant != "today" || result.Metadata.GeneratedTextSchemaID != "today" {
t.Fatalf("metadata = %#v, want Today generated-text metadata", result.Metadata)
}
if !strings.Contains(result.Metadata.RunID, "_today") {
t.Fatalf("RunID = %q, want Today report ID suffix", result.Metadata.RunID)
}
if !strings.Contains(result.DataPackagePath, filepath.Join("data-packages", "today", "2026-05-29")) {
t.Fatalf("DataPackagePath = %q, want Today artifact group", result.DataPackagePath)
}
if !strings.Contains(result.ReportPath, filepath.Join("reports", "today")) {
t.Fatalf("ReportPath = %q, want Today report group", result.ReportPath)
}
if _, ok := result.ModuleSnapshot.LookupStanza("today_planning"); !ok {
t.Fatal("today_planning stanza missing")
}
if _, ok := result.ModuleSnapshot.LookupStanza("tomorrow_planning"); ok {
t.Fatal("tomorrow_planning stanza present, want Today-specific planning")
}
if result.PriorSnapshot == nil || len(result.RecentChanges) == 0 {
t.Fatalf("prior=%#v recentChanges=%#v, want Today daily comparison changes", result.PriorSnapshot, result.RecentChanges)
}
data, err := os.ReadFile(result.DataPackagePath)
if err != nil {
t.Fatalf("read data package: %v", err)
}
for _, want := range []string{"id: today", "prompt_id: weather.today_generated_text", "today_planning:", "recent_changes:"} {
if !strings.Contains(string(data), want) {
t.Fatalf("data package missing %q:\n%s", want, string(data))
}
}
reportData, err := os.ReadFile(result.ReportPath)
if err != nil {
t.Fatalf("read report: %v", err)
}
for _, want := range []string{"# Today's Weather", "Today starts with showers before improving."} {
if !strings.Contains(string(reportData), want) {
t.Fatalf("today report missing %q:\n%s", want, string(reportData))
}
}
}
func TestGenerateTomorrowReportUsesTomorrowBriefingDate(t *testing.T) {
server := dailyBundleServer(t)
cfg := config.Defaults()
@@ -2072,8 +2159,8 @@ func TestRunBatchContinuesAfterReportFailure(t *testing.T) {
if result.Total != 3 || result.Succeeded != 2 || result.Failed != 1 {
t.Fatalf("summary total/succeeded/failed = %d/%d/%d, want 3/2/1", result.Total, result.Succeeded, result.Failed)
}
if renderer.runCalls != 2 {
t.Fatalf("run calls = %d, want successful reports to continue", renderer.runCalls)
if renderer.runCalls != 1 || renderer.structuredRunCalls != 1 {
t.Fatalf("renderer calls run=%d structured=%d, want successful reports to continue", renderer.runCalls, renderer.structuredRunCalls)
}
var failedThreeDay bool
for _, item := range result.Reports {
@@ -2316,6 +2403,10 @@ func validTomorrowGeneratedTextJSON() string {
return `{"summary":"Tomorrow starts with showers before improving.","forecast_discussion":["Morning showers should taper as drier air arrives.","Afternoon conditions trend quieter."],"precipitation_timing":"The best rain chance is during the morning."}`
}
func validTodayGeneratedTextJSON() string {
return `{"summary":"Today starts with showers before improving.","forecast_discussion":["Morning showers should taper as drier air arrives.","Afternoon conditions trend quieter."],"precipitation_timing":"The best rain chance is during the morning."}`
}
func generateDailyReportForTest(t *testing.T, cfg config.Config) *ReportResult {
t.Helper()
cfg.Workspace.Root = t.TempDir()
@@ -2671,6 +2762,9 @@ func (r *selectiveRenderer) Run(_ context.Context, req scriptorium.RunRequest) (
func (r *selectiveRenderer) StructuredRun(_ context.Context, req scriptorium.StructuredRunRequest) (*scriptorium.StructuredRunResult, error) {
r.structuredRunCalls++
body := validHourlyGeneratedTextJSON()
if req.PromptID == "weather.today_generated_text" {
body = validTodayGeneratedTextJSON()
}
if req.PromptID == "weather.tomorrow_generated_text" {
body = validTomorrowGeneratedTextJSON()
}