diff --git a/internal/module/module.go b/internal/module/module.go index e14778a..1ac4f91 100644 --- a/internal/module/module.go +++ b/internal/module/module.go @@ -35,9 +35,10 @@ type ConfigItem struct { } type Output struct { - ID ID `json:"id"` - StanzaName string `json:"stanzaName"` - Value any `json:"value"` + ID ID `json:"id"` + StanzaName string `json:"stanzaName"` + Value any `json:"value"` + PromptValue any `json:"-" yaml:"-"` } type Snapshot struct { @@ -45,6 +46,13 @@ type Snapshot struct { Outputs []Output `json:"outputs"` } +func (o Output) DataPackageValue() any { + if o.PromptValue != nil { + return o.PromptValue + } + return o.Value +} + func NewSnapshot(outputs []Output) (Snapshot, error) { snapshot := Snapshot{ SchemaVersion: SnapshotSchemaVersion, diff --git a/internal/module/module_test.go b/internal/module/module_test.go index de83208..f861903 100644 --- a/internal/module/module_test.go +++ b/internal/module/module_test.go @@ -13,7 +13,12 @@ type testStanza struct { func TestSnapshotPreservesOutputOrderAndJSON(t *testing.T) { snapshot, err := NewSnapshot([]Output{ - {ID: Metadata, StanzaName: "metadata", Value: testStanza{Message: "first", Count: 1}}, + { + ID: Metadata, + StanzaName: "metadata", + Value: testStanza{Message: "first", Count: 1}, + PromptValue: testStanza{Message: "prompt-only", Count: 10}, + }, {ID: AlertDigest, StanzaName: "alert_digest", Value: testStanza{Message: "second", Count: 2}}, }) if err != nil { @@ -35,6 +40,26 @@ func TestSnapshotPreservesOutputOrderAndJSON(t *testing.T) { if got != want { t.Fatalf("json = %s, want %s", got, want) } + if strings.Contains(got, "PromptValue") || strings.Contains(got, "promptValue") || strings.Contains(got, "prompt-only") { + t.Fatalf("json includes runtime-only prompt value: %s", got) + } +} + +func TestOutputDataPackageValue(t *testing.T) { + output := Output{ + ID: Metadata, + StanzaName: "metadata", + Value: testStanza{Message: "rich", Count: 1}, + PromptValue: testStanza{Message: "prompt", Count: 2}, + } + if got := output.DataPackageValue(); got != output.PromptValue { + t.Fatalf("DataPackageValue() = %#v, want prompt value", got) + } + + output.PromptValue = nil + if got := output.DataPackageValue(); got != output.Value { + t.Fatalf("DataPackageValue() = %#v, want rich value fallback", got) + } } func TestSnapshotRejectsDuplicateOutputs(t *testing.T) { @@ -57,7 +82,12 @@ func TestSnapshotRejectsDuplicateOutputs(t *testing.T) { func TestStanzaValueDecodesTypedOutput(t *testing.T) { snapshot, err := NewSnapshot([]Output{ - {ID: Metadata, StanzaName: "metadata", Value: testStanza{Message: "available", Count: 3}}, + { + ID: Metadata, + StanzaName: "metadata", + Value: testStanza{Message: "available", Count: 3}, + PromptValue: testStanza{Message: "prompt-only", Count: 99}, + }, }) if err != nil { t.Fatalf("NewSnapshot() error = %v", err) diff --git a/internal/state/filesystem_test.go b/internal/state/filesystem_test.go index ff54c57..0c200b6 100644 --- a/internal/state/filesystem_test.go +++ b/internal/state/filesystem_test.go @@ -114,7 +114,12 @@ func TestSaveArtifactsAndMetadataRoundTrip(t *testing.T) { store := newTestStore(t) resolved := resolveDailyAt(t, "2026-05-29T05:00:00-05:00") briefingMetadata := stateBriefingMetadata(resolved) - snapshot, err := module.NewSnapshot([]module.Output{{ID: module.Metadata, StanzaName: "metadata", Value: map[string]string{"run_id": resolved.Metadata().RunID}}}) + snapshot, err := module.NewSnapshot([]module.Output{{ + ID: module.Metadata, + StanzaName: "metadata", + Value: map[string]string{"run_id": resolved.Metadata().RunID}, + PromptValue: map[string]string{"prompt_run_id": resolved.Metadata().RunID}, + }}) if err != nil { t.Fatalf("NewSnapshot() error = %v", err) } @@ -220,6 +225,16 @@ func TestSaveArtifactsAndMetadataRoundTrip(t *testing.T) { if loadedSnapshot.SchemaVersion != module.SnapshotSchemaVersion || len(loadedSnapshot.Outputs) != 1 { t.Fatalf("loaded module snapshot = %#v, want one metadata output", loadedSnapshot) } + if loadedSnapshot.Outputs[0].PromptValue != nil { + t.Fatalf("loaded module snapshot PromptValue = %#v, want omitted runtime value", loadedSnapshot.Outputs[0].PromptValue) + } + snapshotData, err := os.ReadFile(moduleSnapshotPath) + if err != nil { + t.Fatalf("read module snapshot: %v", err) + } + if strings.Contains(string(snapshotData), "prompt_run_id") || strings.Contains(string(snapshotData), "promptValue") || strings.Contains(string(snapshotData), "PromptValue") { + t.Fatalf("module snapshot JSON includes runtime-only prompt value:\n%s", string(snapshotData)) + } loadedDataPackage, err := store.LoadDataPackage(context.Background(), dataPackagePath) if err != nil { t.Fatalf("LoadDataPackage() error = %v", err)