diff --git a/internal/app/app_test.go b/internal/app/app_test.go index c2f3403..e67075f 100644 --- a/internal/app/app_test.go +++ b/internal/app/app_test.go @@ -169,7 +169,7 @@ func TestGenerateReportWritesReportAndPreflight(t *testing.T) { if !strings.HasSuffix(result.DataPackagePath, ".data_package.yaml") { t.Fatalf("DataPackagePath = %q, want YAML data package path", result.DataPackagePath) } - if !strings.Contains(string(data), "schema_version: weatherreporter.data_package.v2") || + if !strings.Contains(string(data), "schema_version: weatherreporter.data_package.v3") || !strings.Contains(string(data), "recent_changes:") || !strings.Contains(string(data), "applicable_risk_products:") || !strings.Contains(string(data), "derived_summaries:") || diff --git a/internal/cli/root_test.go b/internal/cli/root_test.go index c130ea0..05ce7f8 100644 --- a/internal/cli/root_test.go +++ b/internal/cli/root_test.go @@ -540,7 +540,7 @@ func TestRunGenerateDailyWritesMarkdownReport(t *testing.T) { if err != nil { t.Fatalf("read managed data package: %v", err) } - if !strings.Contains(string(data), "schema_version: weatherreporter.data_package.v2") || !strings.Contains(string(data), "id: daily") { + if !strings.Contains(string(data), "schema_version: weatherreporter.data_package.v3") || !strings.Contains(string(data), "id: daily") { t.Fatalf("data package output missing expected content:\n%s", string(data)) } if !strings.Contains(string(data), "location:") || diff --git a/internal/promptinput/package.go b/internal/promptinput/package.go index 83e08ad..c680bab 100644 --- a/internal/promptinput/package.go +++ b/internal/promptinput/package.go @@ -16,7 +16,7 @@ import ( "gopkg.in/yaml.v3" ) -const SchemaVersion = "weatherreporter.data_package.v2" +const SchemaVersion = "weatherreporter.data_package.v3" const ( metadataStanza = "metadata" @@ -133,7 +133,7 @@ func stanzasFromSnapshot(snapshot module.Snapshot) BriefingStanzas { order := make([]string, 0, len(snapshot.Outputs)) for _, output := range snapshot.Outputs { order = append(order, output.StanzaName) - values[output.StanzaName] = output.Value + values[output.StanzaName] = output.DataPackageValue() } return BriefingStanzas{Order: order, Values: values} } diff --git a/internal/promptinput/package_test.go b/internal/promptinput/package_test.go index b08c15d..7e07554 100644 --- a/internal/promptinput/package_test.go +++ b/internal/promptinput/package_test.go @@ -126,6 +126,44 @@ func TestBuildUsesNamedSnapshotStanzas(t *testing.T) { } } +func TestBuildUsesPromptValuesFromSnapshot(t *testing.T) { + req := validBuildRequest(t) + req.Modules = snapshotWithOutputs(t, + module.Output{ + ID: module.Metadata, + StanzaName: "metadata", + Value: map[string]string{"run_id": "rich"}, + PromptValue: map[string]string{"run_id": "prompt"}, + }, + module.Output{ + ID: module.CurrentConditions, + StanzaName: "current_conditions", + Value: map[string]string{"condition_text": "Rich conditions"}, + PromptValue: map[string]string{"condition_text": "Prompt conditions"}, + }, + module.Output{ + ID: module.AlertDigest, + StanzaName: "alert_digest", + Value: map[string]bool{"checked": true}, + }, + ) + + pkg, err := Build(req) + if err != nil { + t.Fatalf("Build() error = %v", err) + } + + if got := pkg.Briefing.Values["metadata"].(map[string]string)["run_id"]; got != "prompt" { + t.Fatalf("metadata.run_id = %q, want prompt value", got) + } + if got := pkg.Briefing.Values["current_conditions"].(map[string]string)["condition_text"]; got != "Prompt conditions" { + t.Fatalf("current_conditions.condition_text = %q, want prompt value", got) + } + if got := pkg.Briefing.Values["alert_digest"].(map[string]bool)["checked"]; !got { + t.Fatalf("alert_digest.checked = %v, want rich value fallback", got) + } +} + func TestMarshalYAMLIsDeterministicAndGroupsNamedStanzas(t *testing.T) { pkg, err := Build(validBuildRequest(t)) if err != nil { @@ -143,7 +181,7 @@ func TestMarshalYAMLIsDeterministicAndGroupsNamedStanzas(t *testing.T) { if string(first) != string(second) { t.Fatalf("YAML output changed between marshals:\n%s\n---\n%s", string(first), string(second)) } - if !strings.Contains(string(first), "schema_version: weatherreporter.data_package.v2") || + if !strings.Contains(string(first), "schema_version: weatherreporter.data_package.v3") || !strings.Contains(string(first), "briefing:\n") || !strings.Contains(string(first), " applicable_risk_products:\n") || !strings.Contains(string(first), " derived_summaries:\n") || @@ -251,7 +289,7 @@ func TestMarshalYAMLRejectsUncategorizedStanza(t *testing.T) { func TestLoadYAMLRejectsMisplacedStanza(t *testing.T) { data := []byte(` -schema_version: weatherreporter.data_package.v2 +schema_version: weatherreporter.data_package.v3 run_id: 20260529T100000Z_daily report: id: daily @@ -278,6 +316,23 @@ recent_changes: } } +func TestLoadYAMLRejectsOldSchemaVersion(t *testing.T) { + pkg, err := Build(validBuildRequest(t)) + if err != nil { + t.Fatalf("Build() error = %v", err) + } + data, err := MarshalYAML(pkg) + if err != nil { + t.Fatalf("MarshalYAML() error = %v", err) + } + data = []byte(strings.Replace(string(data), "weatherreporter.data_package.v3", "weatherreporter.data_package.v2", 1)) + + _, err = LoadYAML(data) + if err == nil || !strings.Contains(err.Error(), "schemaVersion must be weatherreporter.data_package.v3") { + t.Fatalf("LoadYAML() error = %v, want current schema version error", err) + } +} + func validBuildRequest(t *testing.T) BuildRequest { t.Helper() generatedAt := time.Date(2026, 5, 29, 10, 0, 0, 0, time.UTC) diff --git a/internal/state/filesystem_test.go b/internal/state/filesystem_test.go index 0c200b6..1c9062f 100644 --- a/internal/state/filesystem_test.go +++ b/internal/state/filesystem_test.go @@ -242,6 +242,10 @@ func TestSaveArtifactsAndMetadataRoundTrip(t *testing.T) { if loadedDataPackage.SchemaVersion != promptinput.SchemaVersion || loadedDataPackage.Briefing.Order[0] != "metadata" { t.Fatalf("loaded data package = %#v, want YAML package with metadata stanza", loadedDataPackage) } + metadataStanza, ok := loadedDataPackage.Briefing.Values["metadata"].(map[string]any) + if !ok || metadataStanza["prompt_run_id"] != resolved.Metadata().RunID { + t.Fatalf("loaded data package metadata = %#v, want runtime prompt value", loadedDataPackage.Briefing.Values["metadata"]) + } var decoded Metadata data, err := os.ReadFile(metadataPath) if err != nil {