Correct curated prompt package contracts

This commit is contained in:
2026-08-13 00:11:31 +00:00
parent 0b869af75e
commit 5139c1a586
6 changed files with 210 additions and 19 deletions

View File

@@ -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))

View File

@@ -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