Validate render identity and daypart fallbacks
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/briefing"
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/collect"
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/config"
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/facts"
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/generatedtext"
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/module"
|
||||
"gitea.maximumdirect.net/eric/weatherreporter/internal/promptinput"
|
||||
@@ -18,7 +19,7 @@ import (
|
||||
// executions for one resolved report.
|
||||
type preparedReport struct {
|
||||
resolved report.Resolved
|
||||
reportFacts ReportFacts
|
||||
derived facts.DerivedFacts
|
||||
moduleSnapshot module.Snapshot
|
||||
identity briefing.PreparedIdentity
|
||||
sourceWarnings []weatherdata.SourceWarning
|
||||
@@ -73,9 +74,9 @@ func prepareReport(req prepareReportRequest) (preparedReport, error) {
|
||||
return preparedReport{}, &preparationError{operation: "lookup generated text catalog", err: err}
|
||||
}
|
||||
|
||||
clonedFacts, err := clonePreparedValue(reportFacts)
|
||||
clonedDerived, err := clonePreparedValue(reportFacts.Derived)
|
||||
if err != nil {
|
||||
return preparedReport{}, &preparationError{operation: "copy prepared report facts", err: err}
|
||||
return preparedReport{}, &preparationError{operation: "copy prepared derived facts", err: err}
|
||||
}
|
||||
clonedSnapshot, err := clonePreparedValue(moduleSnapshot)
|
||||
if err != nil {
|
||||
@@ -87,7 +88,7 @@ func prepareReport(req prepareReportRequest) (preparedReport, error) {
|
||||
}
|
||||
prepared := preparedReport{
|
||||
resolved: cloneResolved(req.Resolved),
|
||||
reportFacts: clonedFacts,
|
||||
derived: clonedDerived,
|
||||
moduleSnapshot: clonedSnapshot,
|
||||
identity: clonedIdentity,
|
||||
sourceWarnings: append([]weatherdata.SourceWarning(nil), clonedIdentity.SourceWarnings...),
|
||||
@@ -120,20 +121,20 @@ func (p preparedReport) sourceWarningsCopy() []weatherdata.SourceWarning {
|
||||
return append([]weatherdata.SourceWarning(nil), p.sourceWarnings...)
|
||||
}
|
||||
|
||||
func (p preparedReport) renderInputs() (briefing.PreparedIdentity, module.Snapshot, ReportFacts, error) {
|
||||
func (p preparedReport) renderInputs() (briefing.PreparedIdentity, module.Snapshot, facts.DerivedFacts, error) {
|
||||
identity, err := clonePreparedValue(p.identity)
|
||||
if err != nil {
|
||||
return briefing.PreparedIdentity{}, module.Snapshot{}, ReportFacts{}, err
|
||||
return briefing.PreparedIdentity{}, module.Snapshot{}, facts.DerivedFacts{}, err
|
||||
}
|
||||
snapshot, err := clonePreparedValue(p.moduleSnapshot)
|
||||
if err != nil {
|
||||
return briefing.PreparedIdentity{}, module.Snapshot{}, ReportFacts{}, err
|
||||
return briefing.PreparedIdentity{}, module.Snapshot{}, facts.DerivedFacts{}, err
|
||||
}
|
||||
reportFacts, err := clonePreparedValue(p.reportFacts)
|
||||
derived, err := clonePreparedValue(p.derived)
|
||||
if err != nil {
|
||||
return briefing.PreparedIdentity{}, module.Snapshot{}, ReportFacts{}, err
|
||||
return briefing.PreparedIdentity{}, module.Snapshot{}, facts.DerivedFacts{}, err
|
||||
}
|
||||
return identity, snapshot, reportFacts, nil
|
||||
return identity, snapshot, derived, nil
|
||||
}
|
||||
|
||||
func clonePreparedValue[T any](value T) (T, error) {
|
||||
|
||||
@@ -37,14 +37,15 @@ func TestPrepareReportBuildsImmutableDeterministicInputs(t *testing.T) {
|
||||
|
||||
originalDataPackage := append([]byte(nil), prepared.dataPackage...)
|
||||
originalIdentity := prepared.identity
|
||||
originalDerived := prepared.derived
|
||||
originalWarnings := append([]weatherdata.SourceWarning(nil), prepared.sourceWarnings...)
|
||||
identity, snapshot, reportFacts, err := prepared.renderInputs()
|
||||
identity, snapshot, derived, err := prepared.renderInputs()
|
||||
if err != nil {
|
||||
t.Fatalf("renderInputs() error = %v", err)
|
||||
}
|
||||
identity.SourceWarnings = append(identity.SourceWarnings, weatherdata.SourceWarning{Source: "test", Message: "consumer mutation"})
|
||||
snapshot.Outputs = nil
|
||||
reportFacts.Collected.Hourly.Periods[0].TextDescription = "consumer mutation"
|
||||
derived.PrecipTiming.ThunderMentioned = false
|
||||
bundle.Hourly.Periods[0].TextDescription = "mutated after preparation"
|
||||
bundle.Warnings = append(bundle.Warnings, weatherdata.SourceWarning{Source: "test", Message: "mutated warning"})
|
||||
if len(bundle.Sources) > 0 {
|
||||
@@ -54,13 +55,10 @@ func TestPrepareReportBuildsImmutableDeterministicInputs(t *testing.T) {
|
||||
bundle.Sources[0].Query["mutated"] = "true"
|
||||
}
|
||||
|
||||
if !bytes.Equal(prepared.dataPackage, originalDataPackage) || !reflect.DeepEqual(prepared.identity, originalIdentity) || !reflect.DeepEqual(prepared.sourceWarnings, originalWarnings) {
|
||||
if !bytes.Equal(prepared.dataPackage, originalDataPackage) || !reflect.DeepEqual(prepared.identity, originalIdentity) || !reflect.DeepEqual(prepared.derived, originalDerived) || !reflect.DeepEqual(prepared.sourceWarnings, originalWarnings) {
|
||||
t.Fatalf("prepared values changed after caller mutation: %#v", prepared)
|
||||
}
|
||||
if prepared.reportFacts.Collected.Hourly.Periods[0].TextDescription == "mutated after preparation" {
|
||||
t.Fatal("prepared report facts retain caller-owned weather data")
|
||||
}
|
||||
if prepared.reportFacts.Collected.Hourly.Periods[0].TextDescription == "consumer mutation" || len(prepared.moduleSnapshot.Outputs) == 0 {
|
||||
if len(prepared.moduleSnapshot.Outputs) == 0 {
|
||||
t.Fatal("prepared report values retain consumer mutation")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,11 +115,11 @@ func executePreparedProfile(ctx context.Context, req profileExecutionRequest) (p
|
||||
if err != nil {
|
||||
return outcome, nil, &profileExecutionError{operation: "validate generated text", err: err}
|
||||
}
|
||||
identity, snapshot, reportFacts, err := req.Prepared.renderInputs()
|
||||
identity, snapshot, derived, err := req.Prepared.renderInputs()
|
||||
if err != nil {
|
||||
return outcome, nil, &profileExecutionError{operation: "copy prepared render inputs", err: err}
|
||||
}
|
||||
renderContext, err := req.Prepared.handler.BuildRenderContext(identity, snapshot, reportFacts.Collected, reportFacts.Derived, generatedText)
|
||||
renderContext, err := req.Prepared.handler.BuildRenderContext(identity, snapshot, derived, generatedText)
|
||||
if err != nil {
|
||||
return outcome, nil, &profileExecutionError{operation: "build render context", err: err}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user