Split Tomorrow report identity

This commit is contained in:
2026-06-14 23:22:31 +00:00
parent afe6803a63
commit 386263784c
20 changed files with 75 additions and 73 deletions

View File

@@ -394,7 +394,7 @@ func reportIDForCommand(kind ReportKind) (report.ID, error) {
case ReportDaily:
return report.DailyToday, nil
case ReportTomorrow:
return report.DailyTomorrow, nil
return report.Tomorrow, nil
case ReportHourly:
return report.Hourly, nil
case ReportThreeDay:
@@ -1085,7 +1085,7 @@ func recentChanges(ctx context.Context, store state.Store, priorSnapshot *state.
PrecipTimingShiftMinutes: cfg.PrecipTimingShiftMinutes,
}
switch reportID {
case report.DailyToday, report.DailyTomorrow:
case report.DailyToday, report.Tomorrow:
return changes.CompareDaily(previous, current, thresholds)
case report.ThreeDay:
return changes.CompareThreeDay(previous, current, thresholds)

View File

@@ -1240,7 +1240,7 @@ func TestGenerateTomorrowReportUsesTomorrowBriefingDate(t *testing.T) {
t.Fatalf("GenerateReport() error = %v", err)
}
if result.Metadata.ReportID != report.DailyTomorrow || result.Metadata.Variant != "tomorrow" {
if result.Metadata.ReportID != report.Tomorrow || result.Metadata.Variant != "tomorrow" {
t.Fatalf("metadata report/variant = %q/%q, want tomorrow", result.Metadata.ReportID, result.Metadata.Variant)
}
dailySummary, ok, err := module.StanzaValue[map[string]any](result.ModuleSnapshot, "derived_daily_summary")
@@ -1253,12 +1253,12 @@ func TestGenerateTomorrowReportUsesTomorrowBriefingDate(t *testing.T) {
if _, ok := result.ModuleSnapshot.LookupStanza("tomorrow_planning"); !ok {
t.Fatal("tomorrow_planning stanza missing")
}
if !strings.Contains(filepath.Base(result.ReportPath), "daily_tomorrow") {
if !strings.Contains(filepath.Base(result.ReportPath), "tomorrow") {
t.Fatalf("ReportPath = %q, want managed tomorrow report path", result.ReportPath)
}
}
func TestTomorrowReportCanCompareAgainstPriorDailySnapshot(t *testing.T) {
func TestTomorrowReportCanCompareAgainstPriorTomorrowSnapshot(t *testing.T) {
server := dailyBundleServer(t)
cfg := config.Defaults()
cfg.WeatherAPI.BaseURL = server.URL + "/"
@@ -1270,8 +1270,7 @@ func TestTomorrowReportCanCompareAgainstPriorDailySnapshot(t *testing.T) {
}
priorResolved, err := ResolveGenerate(GenerateRequest{
Config: cfg,
Report: ReportDaily,
Date: mustParse("2026-05-30T12:00:00-05:00"),
Report: ReportTomorrow,
}, mustParse("2026-05-29T17:00:00-05:00"))
if err != nil {
t.Fatalf("ResolveGenerate(prior) error = %v", err)
@@ -1301,10 +1300,10 @@ func TestTomorrowReportCanCompareAgainstPriorDailySnapshot(t *testing.T) {
t.Fatalf("GenerateReport() error = %v", err)
}
if result.PriorSnapshot == nil {
t.Fatal("PriorSnapshot = nil, want compatible prior daily snapshot")
t.Fatal("PriorSnapshot = nil, want compatible prior tomorrow snapshot")
}
if len(result.RecentChanges) == 0 {
t.Fatal("RecentChanges length = 0, want changes from compatible prior daily snapshot")
t.Fatal("RecentChanges length = 0, want changes from compatible prior tomorrow snapshot")
}
}
@@ -1622,7 +1621,7 @@ func TestResolveGenerateMapsCommandToReportDefinition(t *testing.T) {
{
name: "tomorrow",
kind: ReportTomorrow,
wantID: report.DailyTomorrow,
wantID: report.Tomorrow,
wantPrompt: "weather.daily_report",
wantStart: "2026-05-30T00:00:00-05:00",
wantEnd: "2026-05-31T00:00:00-05:00",

View File

@@ -197,7 +197,7 @@ func TestDerivedDaypartSummariesExposeConfiguredKeysAndHazards(t *testing.T) {
func TestOutdoorWindowsAndTomorrowPlanningModulesPreserveDailyContent(t *testing.T) {
registry := MustDefaultModuleRegistry()
ctx := derivedModuleContext(report.DailyTomorrow)
ctx := derivedModuleContext(report.Tomorrow)
outdoorOutput, err := registry.BuildModule(ctx, module.ConfigItem{ID: module.OutdoorWindows})
if err != nil {

View File

@@ -249,8 +249,8 @@ func (d ModuleDefinition) ValidateOptions(options any) error {
}
func defaultModuleDefinitions() []ModuleDefinition {
allReports := []report.ID{report.DailyToday, report.DailyTomorrow, report.Hourly, report.ThreeDay, report.Weekend, report.Storm}
daypartReports := []report.ID{report.DailyToday, report.DailyTomorrow, report.ThreeDay, report.Weekend}
allReports := []report.ID{report.DailyToday, report.Tomorrow, report.Hourly, report.ThreeDay, report.Weekend, report.Storm}
daypartReports := []report.ID{report.DailyToday, report.Tomorrow, report.ThreeDay, report.Weekend}
return []ModuleDefinition{
{
ID: module.Metadata,
@@ -276,7 +276,7 @@ func defaultModuleDefinitions() []ModuleDefinition {
DefaultOptions: module.NarrativeForecastOptions{},
RequiredCollected: []module.FactRequirement{module.CollectedNarrativeForecast},
RequiredDerived: []module.FactRequirement{module.RequiresDerivedNarrativePeriods},
SupportedReports: []report.ID{report.DailyToday, report.DailyTomorrow},
SupportedReports: []report.ID{report.DailyToday, report.Tomorrow},
MissingData: module.MissingDataOmit,
Builder: buildNarrativeForecastModule,
},
@@ -286,7 +286,7 @@ func defaultModuleDefinitions() []ModuleDefinition {
DefaultOptions: module.HourlyForecastOptions{},
RequiredCollected: []module.FactRequirement{module.CollectedHourlyForecast},
RequiredDerived: []module.FactRequirement{module.RequiresDerivedHourlyPeriods},
SupportedReports: []report.ID{report.DailyToday, report.DailyTomorrow, report.Hourly},
SupportedReports: []report.ID{report.DailyToday, report.Tomorrow, report.Hourly},
MissingData: module.MissingDataOmit,
Builder: buildHourlyForecastModule,
},
@@ -295,7 +295,7 @@ func defaultModuleDefinitions() []ModuleDefinition {
StanzaName: "derived_daily_summary",
DefaultOptions: module.DerivedDailySummaryOptions{},
RequiredDerived: []module.FactRequirement{module.RequiresDerivedDailySummaries, module.RequiresDerivedPrecipTiming},
SupportedReports: []report.ID{report.DailyToday, report.DailyTomorrow},
SupportedReports: []report.ID{report.DailyToday, report.Tomorrow},
MissingData: module.MissingDataError,
Builder: buildDerivedDailySummaryModule,
},
@@ -379,7 +379,7 @@ func defaultModuleDefinitions() []ModuleDefinition {
StanzaName: "tomorrow_planning",
DefaultOptions: module.TomorrowPlanningOptions{},
RequiredDerived: []module.FactRequirement{module.RequiresDerivedDailySummaries},
SupportedReports: []report.ID{report.DailyTomorrow},
SupportedReports: []report.ID{report.Tomorrow},
MissingData: module.MissingDataEmpty,
Builder: buildTomorrowPlanningModule,
},

View File

@@ -187,7 +187,7 @@ func variantForReport(id report.ID) string {
switch id {
case report.DailyToday:
return "today"
case report.DailyTomorrow:
case report.Tomorrow:
return "tomorrow"
default:
return ""

View File

@@ -133,19 +133,19 @@ func TestRunGenerateTomorrowWritesMarkdownReport(t *testing.T) {
if !strings.Contains(string(report), "# Daily Report") {
t.Fatalf("report output missing markdown:\n%s", string(report))
}
dataPackagePath := oneArtifact(t, workspaceRoot, "data-packages", "daily", "2026-05-30", "*.data_package.yaml")
dataPackagePath := oneArtifact(t, workspaceRoot, "data-packages", "tomorrow", "2026-05-30", "*.data_package.yaml")
data, err := os.ReadFile(dataPackagePath)
if err != nil {
t.Fatalf("read managed data package: %v", err)
}
if !strings.Contains(string(data), "id: daily_tomorrow") || !strings.Contains(string(data), "tomorrow_planning:") {
if !strings.Contains(string(data), "id: tomorrow") || !strings.Contains(string(data), "tomorrow_planning:") {
t.Fatalf("data package output missing tomorrow content:\n%s", string(data))
}
reportMatches, err := filepath.Glob(filepath.Join(workspaceRoot, "reports", "daily", "*.md"))
reportMatches, err := filepath.Glob(filepath.Join(workspaceRoot, "reports", "tomorrow", "*.md"))
if err != nil {
t.Fatalf("glob managed report: %v", err)
}
if len(reportMatches) != 1 || !strings.Contains(filepath.Base(reportMatches[0]), "daily_tomorrow") {
if len(reportMatches) != 1 || !strings.Contains(filepath.Base(reportMatches[0]), "tomorrow") {
t.Fatalf("managed reports = %#v, want tomorrow report", reportMatches)
}
}
@@ -171,18 +171,18 @@ func TestRunEveningGeneratesTomorrowReport(t *testing.T) {
if err != nil {
t.Fatalf("Run() error = %v", err)
}
dataPackageMatches, err := filepath.Glob(filepath.Join(workspaceRoot, "data-packages", "daily", "2026-05-30", "*.data_package.yaml"))
dataPackageMatches, err := filepath.Glob(filepath.Join(workspaceRoot, "data-packages", "tomorrow", "2026-05-30", "*.data_package.yaml"))
if err != nil {
t.Fatalf("glob data package: %v", err)
}
if len(dataPackageMatches) != 1 {
t.Fatalf("data package files = %#v, want one", dataPackageMatches)
}
reportMatches, err := filepath.Glob(filepath.Join(workspaceRoot, "reports", "daily", "*.md"))
reportMatches, err := filepath.Glob(filepath.Join(workspaceRoot, "reports", "tomorrow", "*.md"))
if err != nil {
t.Fatalf("glob managed report: %v", err)
}
if len(reportMatches) != 1 || !strings.Contains(filepath.Base(reportMatches[0]), "daily_tomorrow") {
if len(reportMatches) != 1 || !strings.Contains(filepath.Base(reportMatches[0]), "tomorrow") {
t.Fatalf("managed reports = %#v, want only tomorrow report", reportMatches)
}
}
@@ -482,10 +482,10 @@ func TestRunEveningReportsNotificationSuccess(t *testing.T) {
distributorServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/runs/distributor-run-1" {
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"run_id":"distributor-run-1","pipeline_id":"weatherreporter.daily","status":"succeeded","report":{"actions":[{"action":"replace_older"}]}}`))
_, _ = w.Write([]byte(`{"run_id":"distributor-run-1","pipeline_id":"weatherreporter.tomorrow","status":"succeeded","report":{"actions":[{"action":"replace_older"}]}}`))
return
}
if r.URL.Path != "/v1/pipelines/weatherreporter.daily/upload" {
if r.URL.Path != "/v1/pipelines/weatherreporter.tomorrow/upload" {
http.NotFound(w, r)
return
}
@@ -521,7 +521,7 @@ func TestRunEveningReportsNotificationSuccess(t *testing.T) {
if len(summary.Reports) != 1 {
t.Fatalf("reports = %#v, want one report", summary.Reports)
}
if summary.Reports[0].NotificationStatus != "succeeded" || summary.Reports[0].NotificationRunID != "distributor-run-1" || summary.Reports[0].NotificationPipelineID != "weatherreporter.daily" {
if summary.Reports[0].NotificationStatus != "succeeded" || summary.Reports[0].NotificationRunID != "distributor-run-1" || summary.Reports[0].NotificationPipelineID != "weatherreporter.tomorrow" {
t.Fatalf("notification fields = %#v", summary.Reports[0])
}
if !strings.Contains(stderr.String(), `notificationStatus="succeeded"`) || !strings.Contains(stderr.String(), `notificationRunId="distributor-run-1"`) {

View File

@@ -111,8 +111,8 @@ func reportIDForConfigKey(key string) (report.ID, error) {
switch normalized {
case "daily", "daily_today":
return report.DailyToday, nil
case "tomorrow", "daily_tomorrow":
return report.DailyTomorrow, nil
case "tomorrow":
return report.Tomorrow, nil
case "hourly":
return report.Hourly, nil
case "three_day", "three_day_outlook":

View File

@@ -115,7 +115,7 @@ func BuildDerived(req BuildDerivedRequest) (DerivedFacts, error) {
switch req.Resolved.Definition.ID {
case report.Hourly:
case report.DailyToday, report.DailyTomorrow:
case report.DailyToday, report.Tomorrow:
summary, err := forecast.BuildDailySummary(bundle, period.Start, location, req.Dayparts)
if err != nil {
return DerivedFacts{}, err

View File

@@ -135,7 +135,7 @@ func TestBuildDerivedOutlookBuildsPartialDaySummariesWithMissingOptionalSources(
func TestBuildDerivedWeekendAndTomorrow(t *testing.T) {
location := testLocation()
for _, id := range []report.ID{report.DailyTomorrow, report.Weekend} {
for _, id := range []report.ID{report.Tomorrow, report.Weekend} {
resolved := resolveForTest(t, id, mustParse("2026-05-29T08:00:00-05:00"), location)
derived, err := BuildDerived(BuildDerivedRequest{
Resolved: resolved,
@@ -259,7 +259,7 @@ func TestBuildDerivedSelectsSPCConvectiveOutlooksByValidPeriod(t *testing.T) {
},
{
name: "daily tomorrow",
resolved: resolveForTest(t, report.DailyTomorrow, now, location),
resolved: resolveForTest(t, report.Tomorrow, now, location),
wantOutlookIDs: []string{"sat-enhanced"},
wantDiscussion: []string{"day2"},
},

View File

@@ -15,27 +15,27 @@ func dailyTodayDefinition() Definition {
ArtifactGroup: "daily",
BatchOutputName: "daily.md",
Generated: true,
CompatiblePriorIDs: []ID{DailyToday, DailyTomorrow},
CompatiblePriorIDs: []ID{DailyToday},
Modules: dailyTodayModules(),
Morning: true,
resolve: resolveDailyToday,
}
}
func dailyTomorrowDefinition() Definition {
func tomorrowDefinition() Definition {
return Definition{
ID: DailyTomorrow,
Name: "Tomorrow Planning Brief",
ID: Tomorrow,
Name: "Tomorrow Report",
PromptID: "weather.daily_report",
GenerationMode: GenerationModeScriptoriumMarkdown,
ComparisonStrategy: CompareSameValidDate,
ArtifactGroup: "daily",
ArtifactGroup: "tomorrow",
BatchOutputName: "tomorrow.md",
Generated: true,
CompatiblePriorIDs: []ID{DailyToday, DailyTomorrow},
Modules: dailyTomorrowModules(),
CompatiblePriorIDs: []ID{Tomorrow},
Modules: tomorrowModules(),
Evening: true,
resolve: resolveDailyTomorrow,
resolve: resolveTomorrow,
}
}
@@ -57,7 +57,7 @@ func dailyTodayModules() []module.ConfigItem {
)
}
func dailyTomorrowModules() []module.ConfigItem {
func tomorrowModules() []module.ConfigItem {
return moduleItems(
module.Metadata,
module.CurrentConditions,
@@ -83,6 +83,6 @@ func resolveDailyToday(req ResolveRequest) (timeutil.Period, error) {
return timeutil.CivilDay(req.Now, req.Location), nil
}
func resolveDailyTomorrow(req ResolveRequest) (timeutil.Period, error) {
func resolveTomorrow(req ResolveRequest) (timeutil.Period, error) {
return timeutil.CivilDay(req.Now.In(req.Location).AddDate(0, 0, 1), req.Location), nil
}

View File

@@ -12,12 +12,12 @@ import (
type ID string
const (
DailyToday ID = "daily_today"
DailyTomorrow ID = "daily_tomorrow"
Hourly ID = "hourly"
ThreeDay ID = "three_day"
Weekend ID = "weekend"
Storm ID = "storm"
DailyToday ID = "daily_today"
Tomorrow ID = "tomorrow"
Hourly ID = "hourly"
ThreeDay ID = "three_day"
Weekend ID = "weekend"
Storm ID = "storm"
)
type ComparisonStrategy string

View File

@@ -32,7 +32,7 @@ func (r Registry) BatchReports(batch Batch, req ResolveRequest) ([]Resolved, err
}
return r.resolveIDs(ids, req)
case Evening:
return r.resolveIDs([]ID{DailyTomorrow}, req)
return r.resolveIDs([]ID{Tomorrow}, req)
default:
return nil, fmt.Errorf("unknown batch %q", batch)
}

View File

@@ -37,7 +37,7 @@ func TestTomorrowValidPeriodFromEveningGeneration(t *testing.T) {
location := mustLoadLocation(t)
now := mustParse("2026-05-29T20:00:00-05:00")
resolved, err := Resolve(DailyTomorrow, ResolveRequest{Now: now, Location: location})
resolved, err := Resolve(Tomorrow, ResolveRequest{Now: now, Location: location})
if err != nil {
t.Fatalf("Resolve() error = %v", err)
}
@@ -207,8 +207,8 @@ func TestEveningBatchIncludesTomorrow(t *testing.T) {
t.Fatalf("BatchReports() error = %v", err)
}
ids := resolvedIDs(resolved)
if strings.Join(ids, ",") != "daily_tomorrow" {
t.Fatalf("ids = %v, want daily_tomorrow", ids)
if strings.Join(ids, ",") != "tomorrow" {
t.Fatalf("ids = %v, want tomorrow", ids)
}
}
@@ -243,7 +243,7 @@ func TestRegistryLookupErrorIsActionable(t *testing.T) {
func TestRegistryAllIncludesHourlyInStableOrder(t *testing.T) {
ids := resolvedDefinitionIDs(DefaultRegistry().All())
want := []string{"daily_today", "daily_tomorrow", "hourly", "three_day", "weekend", "storm"}
want := []string{"daily_today", "tomorrow", "hourly", "three_day", "weekend", "storm"}
if strings.Join(ids, ",") != strings.Join(want, ",") {
t.Fatalf("All() ids = %#v, want %#v", ids, want)
}
@@ -306,15 +306,15 @@ func TestRegistryDefinitionsDeclarePathAndCompatibilityPolicy(t *testing.T) {
artifactGroup: "daily",
batchOutputName: "daily.md",
generated: true,
compatiblePriorIDs: []ID{DailyToday, DailyTomorrow},
compatiblePriorIDs: []ID{DailyToday},
comparisonStrategy: CompareSameValidDate,
},
{
id: DailyTomorrow,
artifactGroup: "daily",
id: Tomorrow,
artifactGroup: "tomorrow",
batchOutputName: "tomorrow.md",
generated: true,
compatiblePriorIDs: []ID{DailyToday, DailyTomorrow},
compatiblePriorIDs: []ID{Tomorrow},
comparisonStrategy: CompareSameValidDate,
},
{
@@ -406,7 +406,7 @@ func TestRegistryDefinitionsDeclareDefaultModules(t *testing.T) {
},
},
{
id: DailyTomorrow,
id: Tomorrow,
want: []module.ID{
module.Metadata,
module.CurrentConditions,

View File

@@ -13,7 +13,7 @@ type Registry struct {
func DefaultRegistry() Registry {
definitions := []Definition{
dailyTodayDefinition(),
dailyTomorrowDefinition(),
tomorrowDefinition(),
hourlyDefinition(),
threeDayDefinition(),
weekendDefinition(),
@@ -74,7 +74,7 @@ func (r Registry) MustLookup(id ID) Definition {
}
func (r Registry) All() []Definition {
ids := []ID{DailyToday, DailyTomorrow, Hourly, ThreeDay, Weekend, Storm}
ids := []ID{DailyToday, Tomorrow, Hourly, ThreeDay, Weekend, Storm}
out := make([]Definition, 0, len(ids))
for _, id := range ids {
if definition, ok := r.definitions[id]; ok {