Refactor the template variable framework

This commit is contained in:
2026-06-14 08:57:53 -05:00
parent bb8de054dc
commit 28b8391d53
8 changed files with 512 additions and 552 deletions

View File

@@ -559,6 +559,7 @@ func GenerateReport(ctx context.Context, req ReportRequest) (*ReportResult, erro
paths: paths,
moduleSnapshot: moduleSnapshot,
moduleSnapshotPath: moduleSnapshotPath,
reportFacts: reportFacts,
dataPackage: dataPackage,
dataPackagePath: dataPackagePath,
briefingMetadata: briefingMetadata,
@@ -638,6 +639,7 @@ type generatedReportRequest struct {
paths state.ArtifactPaths
moduleSnapshot module.Snapshot
moduleSnapshotPath string
reportFacts ReportFacts
dataPackage promptinput.Package
dataPackagePath string
briefingMetadata briefing.Metadata
@@ -690,7 +692,7 @@ func generateTextTemplateReport(ctx context.Context, req generatedReportRequest)
return nil, err
}
renderContext, err := buildRenderContext(req.Resolved.Definition, req.briefingMetadata, req.moduleSnapshot, hourlyText)
renderContext, err := buildRenderContext(req.Resolved.Definition, req.briefingMetadata, req.moduleSnapshot, req.reportFacts, hourlyText)
if err != nil {
return nil, generatedReportError(req.Resolved, req.metadata.RunID, "build render context", err)
}
@@ -1117,10 +1119,10 @@ func validateGeneratedText(definition report.Definition, data []byte) (generated
}
}
func buildRenderContext(definition report.Definition, metadata briefing.Metadata, snapshot module.Snapshot, hourly generatedtext.Hourly) (any, error) {
func buildRenderContext(definition report.Definition, metadata briefing.Metadata, snapshot module.Snapshot, reportFacts ReportFacts, hourly generatedtext.Hourly) (any, error) {
switch definition.TemplateID {
case "hourly":
return generatedtext.BuildHourlyRenderContext(metadata, snapshot, hourly)
return generatedtext.BuildHourlyRenderContext(metadata, snapshot, hourly, reportFacts.Collected, reportFacts.Derived)
default:
return nil, fmt.Errorf("report template %q is not supported for report %q", definition.TemplateID, definition.ID)
}

View File

@@ -450,8 +450,20 @@ func TestGenerateHourlyReportUsesGeneratedTextTemplateWorkflow(t *testing.T) {
if err != nil {
t.Fatalf("read render context: %v", err)
}
if !strings.Contains(string(renderContext), `"ReportTitle": "Hourly Report"`) || !strings.Contains(string(renderContext), `"LocationName": "Brentwood, MO"`) {
t.Fatalf("render context missing deterministic fields:\n%s", string(renderContext))
for _, want := range []string{
`"Report": {`,
`"Title": "Hourly Report"`,
`"LocationName": "Brentwood, MO"`,
`"GeneratedText": {`,
`"Modules": {`,
`"CurrentConditions": {`,
`"HourlyForecast": {`,
`"Collected": {`,
`"Derived": {`,
} {
if !strings.Contains(string(renderContext), want) {
t.Fatalf("render context missing %q:\n%s", want, string(renderContext))
}
}
reportData, err := os.ReadFile(result.ReportPath)
if err != nil {
@@ -751,54 +763,6 @@ func TestGenerateHourlyReportPreservesRawTextOnValidationFailure(t *testing.T) {
}
}
func TestGenerateHourlyReportPreservesValidatedTextOnRenderContextFailure(t *testing.T) {
server := hourlyBundleServer(t)
cfg := hourlyGeneratedTextConfigWithModules(t, server, []string{
"metadata",
"hourly_forecast",
"precip_timing",
"alert_digest",
"area_forecast_discussion",
"weather_story",
"spc_convective_outlooks",
})
resolved, store, notifier, outputPath := resolveHourlyGeneratedTextFixture(t, cfg)
renderer := &recordingRenderer{
renderResult: &scriptorium.RenderResult{ExitCode: 0},
structuredRunResult: &scriptorium.StructuredRunResult{ExitCode: 0},
structuredRunBody: validHourlyGeneratedTextJSON(),
}
_, err := GenerateReport(context.Background(), ReportRequest{
Config: cfg,
Resolved: resolved,
OutputPath: outputPath,
Renderer: renderer,
Store: store,
Notifier: notifier,
})
assertGeneratedReportError(t, err, resolved, "build render context")
assertNoGeneratedFailureSideEffects(t, notifier, outputPath)
paths := hourlyArtifactPaths(t, store, resolved)
assertPathsExist(t, paths.Preflight, paths.Metadata, paths.GeneratedTextRaw, paths.GeneratedTextResult, paths.GeneratedText)
assertPathsMissing(t, paths.RenderContext, paths.RenderedReport)
generatedText, readErr := os.ReadFile(paths.GeneratedText)
if readErr != nil {
t.Fatalf("read validated generated text: %v", readErr)
}
if string(generatedText) != validHourlyGeneratedTextJSON() {
t.Fatalf("validated generated text = %s, want normalized JSON", generatedText)
}
metadataData, readErr := os.ReadFile(paths.Metadata)
if readErr != nil {
t.Fatalf("read metadata: %v", readErr)
}
if !strings.Contains(string(metadataData), paths.GeneratedText) {
t.Fatalf("metadata missing validated generated text link:\n%s", string(metadataData))
}
}
func TestGenerateHourlyReportRejectsUnsupportedTemplateBeforeRenderContext(t *testing.T) {
cfg, resolved, store, notifier, outputPath := hourlyGeneratedTextFixture(t)
resolved.Definition.TemplateID = "missing-template"