Correct curated prompt package contracts
This commit is contained in:
@@ -67,11 +67,21 @@ type Metadata struct {
|
||||
}
|
||||
|
||||
type Package struct {
|
||||
SchemaVersion string `json:"schemaVersion" yaml:"schema_version"`
|
||||
RunID string `json:"runId" yaml:"run_id"`
|
||||
Report Report `json:"report" yaml:"report"`
|
||||
Briefing BriefingStanzas `json:"briefing" yaml:"briefing"`
|
||||
SourceWarnings []weatherdata.SourceWarning `json:"sourceWarnings,omitempty" yaml:"source_warnings,omitempty"`
|
||||
SchemaVersion string `json:"schemaVersion" yaml:"schema_version"`
|
||||
RunID string `json:"runId" yaml:"run_id"`
|
||||
Report Report `json:"report" yaml:"report"`
|
||||
Briefing BriefingStanzas `json:"briefing" yaml:"briefing"`
|
||||
SourceWarnings []SourceWarningSummary `json:"sourceWarnings,omitempty" yaml:"source_warnings,omitempty"`
|
||||
}
|
||||
|
||||
// SourceWarningSummary is the reviewed warning projection supplied to Promptkit.
|
||||
// Transport and provenance details intentionally remain outside the prompt package.
|
||||
type SourceWarningSummary struct {
|
||||
Source string `json:"source" yaml:"source"`
|
||||
Code string `json:"code" yaml:"code"`
|
||||
Severity string `json:"severity" yaml:"severity"`
|
||||
Message string `json:"message" yaml:"message"`
|
||||
CompletenessImpact string `json:"completenessImpact,omitempty" yaml:"completeness_impact,omitempty"`
|
||||
}
|
||||
|
||||
type Report struct {
|
||||
@@ -107,7 +117,7 @@ func Build(req BuildRequest) (Package, error) {
|
||||
ValidPeriod: req.Metadata.ValidPeriod,
|
||||
},
|
||||
Briefing: stanzasFromSnapshot(req.Modules),
|
||||
SourceWarnings: append([]weatherdata.SourceWarning(nil), req.Metadata.SourceWarnings...),
|
||||
SourceWarnings: sourceWarningSummaries(req.Metadata.SourceWarnings),
|
||||
}
|
||||
if err := Validate(pkg); err != nil {
|
||||
return Package{}, err
|
||||
@@ -115,6 +125,20 @@ func Build(req BuildRequest) (Package, error) {
|
||||
return pkg, nil
|
||||
}
|
||||
|
||||
func sourceWarningSummaries(warnings []weatherdata.SourceWarning) []SourceWarningSummary {
|
||||
out := make([]SourceWarningSummary, 0, len(warnings))
|
||||
for _, warning := range warnings {
|
||||
out = append(out, SourceWarningSummary{
|
||||
Source: warning.Source,
|
||||
Code: warning.Code,
|
||||
Severity: warning.Severity,
|
||||
Message: warning.Message,
|
||||
CompletenessImpact: warning.CompletenessImpact,
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func stanzasFromSnapshot(snapshot module.Snapshot) BriefingStanzas {
|
||||
values := map[string]any{}
|
||||
order := make([]string, 0, len(snapshot.Outputs))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package promptinput
|
||||
|
||||
import (
|
||||
"math"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -8,6 +9,7 @@ import (
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/module"
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/report"
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/timeutil"
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/weatherdata"
|
||||
)
|
||||
|
||||
func TestBuildDailyDataPackage(t *testing.T) {
|
||||
@@ -161,6 +163,37 @@ func TestBuildUsesPromptValuesFromSnapshot(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalYAMLProjectsSourceWarningsWithoutTransportDetails(t *testing.T) {
|
||||
req := validBuildRequest(t)
|
||||
req.Metadata.SourceWarnings = []weatherdata.SourceWarning{{
|
||||
Source: "hourly",
|
||||
Code: "missing_source",
|
||||
Severity: "warning",
|
||||
Message: "hourly source is unavailable",
|
||||
Endpoint: "/transport/path/only-for-this-test",
|
||||
CompletenessImpact: "source omitted",
|
||||
}}
|
||||
|
||||
pkg, err := Build(req)
|
||||
if err != nil {
|
||||
t.Fatalf("Build() error = %v", err)
|
||||
}
|
||||
data, err := MarshalYAML(pkg)
|
||||
if err != nil {
|
||||
t.Fatalf("MarshalYAML() error = %v", err)
|
||||
}
|
||||
text := string(data)
|
||||
|
||||
for _, safeDetail := range []string{"source_warnings:", "source: hourly", "code: missing_source", "severity: warning", "message: hourly source is unavailable", "completeness_impact: source omitted"} {
|
||||
if !strings.Contains(text, safeDetail) {
|
||||
t.Fatalf("YAML output missing safe warning detail %q:\n%s", safeDetail, text)
|
||||
}
|
||||
}
|
||||
if strings.Contains(text, "/transport/path/only-for-this-test") || strings.Contains(text, "endpoint:") {
|
||||
t.Fatalf("YAML output contains raw warning transport details:\n%s", text)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalYAMLIsDeterministicAndGroupsNamedStanzas(t *testing.T) {
|
||||
pkg, err := Build(validBuildRequest(t))
|
||||
if err != nil {
|
||||
@@ -287,6 +320,23 @@ func TestMarshalYAMLRejectsUncategorizedStanza(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalYAMLAttributesStanzaSerializationFailures(t *testing.T) {
|
||||
req := validBuildRequest(t)
|
||||
req.Modules = snapshotWithOutputs(t,
|
||||
module.Output{ID: module.Metadata, StanzaName: "metadata", Value: map[string]string{"run_id": req.Metadata.RunID}},
|
||||
module.Output{ID: module.CurrentConditions, StanzaName: "current_conditions", Value: map[string]float64{"temperature": math.Inf(1)}},
|
||||
)
|
||||
pkg, err := Build(req)
|
||||
if err != nil {
|
||||
t.Fatalf("Build() error = %v", err)
|
||||
}
|
||||
|
||||
_, err = MarshalYAML(pkg)
|
||||
if err == nil || !strings.Contains(err.Error(), `marshal briefing stanza "current_conditions"`) {
|
||||
t.Fatalf("MarshalYAML() error = %v, want current_conditions stanza context", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadYAMLRejectsMisplacedStanza(t *testing.T) {
|
||||
data := []byte(`
|
||||
schema_version: weatherreporter.data_package.v4
|
||||
|
||||
Reference in New Issue
Block a user