Added a location block to the data package

This commit is contained in:
2026-05-29 19:57:08 -05:00
parent 42defcf4b9
commit 8a762bf34f
16 changed files with 152 additions and 9 deletions

View File

@@ -51,6 +51,19 @@ config test suite.
Timezone values may be IANA names, configured aliases such as `Chicago` and Timezone values may be IANA names, configured aliases such as `Chicago` and
`Stl`, US timezone abbreviations, or UTC offsets such as `-5` and `+09:30`. `Stl`, US timezone abbreviations, or UTC offsets such as `-5` and `+09:30`.
### `location`
`location` is descriptive prompt context included in briefing metadata and
Scriptorium data packages. It does not select a Weather API endpoint or enable
multiple configured forecast locations.
- `id`: short local identifier. Default: `home`.
- `name`: human-readable location name. Default: `Brentwood`.
- `region`: broader forecast area context. Default: `St. Louis Metro`.
The prompt-facing location object also includes `timezone`, derived from the
effective `weather_api.timezone` after CLI overrides such as `--tz`.
### `missing_source` ### `missing_source`
- `default`: missing-source behavior for optional sources. One of `error`, `warn`, or `none`. Default: `warn`. - `default`: missing-source behavior for optional sources. One of `error`, `warn`, or `none`. Default: `warn`.

View File

@@ -16,7 +16,7 @@ Inputs:
- resolved report definition, generation time, timezone, and valid period - resolved report definition, generation time, timezone, and valid period
- forecast bundle with source provenance and warnings - forecast bundle with source provenance and warnings
- derived daily or period summaries where required - derived daily or period summaries where required
- configured units and timezone - configured units, timezone, and descriptive location context
Outputs: Outputs:
@@ -34,6 +34,8 @@ Outputs:
The package receives configured units and timezone from the app layer. Daypart The package receives configured units and timezone from the app layer. Daypart
configuration is consumed by `internal/forecast` before briefing builders run. configuration is consumed by `internal/forecast` before briefing builders run.
Configured `location` values are prompt context only; Weather API
`sourceLocationId` and `sourceLocation` remain source provenance.
## External Adapters Used ## External Adapters Used
@@ -74,6 +76,6 @@ Inspect:
- Briefings contain structured weather facts and source context. - Briefings contain structured weather facts and source context.
- Common metadata includes RunID, report ID, prompt ID, valid period, source - Common metadata includes RunID, report ID, prompt ID, valid period, source
provenance, source hashes, and source warnings. provenance, source hashes, source warnings, and configured prompt location.
- LLM prompt input packaging and Scriptorium execution remain outside this - LLM prompt input packaging and Scriptorium execution remain outside this
boundary. boundary.

View File

@@ -18,8 +18,8 @@ Outputs:
- `promptinput.Package` containing schema version, RunID, report metadata, - `promptinput.Package` containing schema version, RunID, report metadata,
briefing content, Recent Changes, and source warnings. Briefing content briefing content, Recent Changes, and source warnings. Briefing content
includes discussion key messages and short/long-term AFD narratives when the includes configured location context, discussion key messages, and
Weather API provides them. short/long-term AFD narratives when the Weather API provides them.
- optional JSON file written by `promptinput.Save` - optional JSON file written by `promptinput.Save`
## Boundaries ## Boundaries
@@ -30,8 +30,8 @@ Outputs:
## Config Fields Used ## Config Fields Used
None directly. Config-derived values are already present in briefing metadata None directly. Config-derived values, including prompt location context, are
before this package runs. already present in briefing metadata before this package runs.
## External Adapters Used ## External Adapters Used

View File

@@ -66,8 +66,8 @@ valid-period start date for JSON artifacts, and the RunID.
``` ```
Metadata is stored beside briefing snapshots and links the briefing, data Metadata is stored beside briefing snapshots and links the briefing, data
package, preflight, and report paths. Report listing walks metadata files under package, preflight, report paths, and configured prompt location. Report
the snapshots directory. listing walks metadata files under the snapshots directory.
## Prior Lookup ## Prior Lookup

View File

@@ -6,6 +6,11 @@ weather_api:
timezone: "America/Chicago" timezone: "America/Chicago"
format: json format: json
location:
id: home
name: Brentwood
region: St. Louis Metro
missing_source: missing_source:
default: warn default: warn
sources: sources:

View File

@@ -522,6 +522,7 @@ func BuildBriefing(req BriefingRequest, bundle *forecast.Bundle) (briefing.Packa
Bundle: bundle, Bundle: bundle,
Units: req.Config.WeatherAPI.Units, Units: req.Config.WeatherAPI.Units,
Timezone: req.Config.WeatherAPI.Timezone, Timezone: req.Config.WeatherAPI.Timezone,
Location: briefingLocation(req.Config),
}, summary) }, summary)
case report.ThreeDay, report.Weekend: case report.ThreeDay, report.Weekend:
summaries, err := forecast.BuildPeriodDailySummaries(bundle, req.Resolved.ValidPeriod, location, dayparts) summaries, err := forecast.BuildPeriodDailySummaries(bundle, req.Resolved.ValidPeriod, location, dayparts)
@@ -534,6 +535,7 @@ func BuildBriefing(req BriefingRequest, bundle *forecast.Bundle) (briefing.Packa
Bundle: bundle, Bundle: bundle,
Units: req.Config.WeatherAPI.Units, Units: req.Config.WeatherAPI.Units,
Timezone: req.Config.WeatherAPI.Timezone, Timezone: req.Config.WeatherAPI.Timezone,
Location: briefingLocation(req.Config),
}, summaries) }, summaries)
} }
return briefing.BuildThreeDay(briefing.BuildContext{ return briefing.BuildThreeDay(briefing.BuildContext{
@@ -541,6 +543,7 @@ func BuildBriefing(req BriefingRequest, bundle *forecast.Bundle) (briefing.Packa
Bundle: bundle, Bundle: bundle,
Units: req.Config.WeatherAPI.Units, Units: req.Config.WeatherAPI.Units,
Timezone: req.Config.WeatherAPI.Timezone, Timezone: req.Config.WeatherAPI.Timezone,
Location: briefingLocation(req.Config),
}, summaries) }, summaries)
case report.Storm: case report.Storm:
return briefing.BuildStorm(briefing.BuildContext{ return briefing.BuildStorm(briefing.BuildContext{
@@ -548,12 +551,26 @@ func BuildBriefing(req BriefingRequest, bundle *forecast.Bundle) (briefing.Packa
Bundle: bundle, Bundle: bundle,
Units: req.Config.WeatherAPI.Units, Units: req.Config.WeatherAPI.Units,
Timezone: req.Config.WeatherAPI.Timezone, Timezone: req.Config.WeatherAPI.Timezone,
Location: briefingLocation(req.Config),
}) })
default: default:
return briefing.Package{}, fmt.Errorf("briefing is not implemented for report %q", req.Resolved.Definition.ID) return briefing.Package{}, fmt.Errorf("briefing is not implemented for report %q", req.Resolved.Definition.ID)
} }
} }
func briefingLocation(cfg config.Config) *briefing.LocationContext {
location := briefing.LocationContext{
ID: cfg.Location.ID,
Name: cfg.Location.Name,
Region: cfg.Location.Region,
Timezone: cfg.WeatherAPI.Timezone,
}
if location.ID == "" && location.Name == "" && location.Region == "" && location.Timezone == "" {
return nil
}
return &location
}
func defaultStore(cfg config.Config) (*state.FilesystemStore, error) { func defaultStore(cfg config.Config) (*state.FilesystemStore, error) {
return state.NewFilesystemStore(cfg.Workspace) return state.NewFilesystemStore(cfg.Workspace)
} }

View File

@@ -2,6 +2,7 @@ package app
import ( import (
"context" "context"
"encoding/json"
"errors" "errors"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
@@ -195,6 +196,16 @@ func TestGenerateReportWritesReportAndPreflight(t *testing.T) {
if !strings.Contains(string(data), `"recentChanges"`) || !strings.Contains(string(data), `data_package.v1`) { if !strings.Contains(string(data), `"recentChanges"`) || !strings.Contains(string(data), `data_package.v1`) {
t.Fatalf("data package missing expected content:\n%s", string(data)) t.Fatalf("data package missing expected content:\n%s", string(data))
} }
var savedDataPackage struct {
Briefing briefing.Package `json:"briefing"`
}
if err := json.Unmarshal(data, &savedDataPackage); err != nil {
t.Fatalf("decode data package: %v", err)
}
location := savedDataPackage.Briefing.Metadata.Location
if location == nil || location.ID != "home" || location.Name != "Brentwood" || location.Region != "St. Louis Metro" || location.Timezone != "America/Chicago" {
t.Fatalf("data package location = %#v, want configured prompt location", location)
}
if !strings.Contains(string(data), "Short-term AFD narrative for generated report.") || !strings.Contains(string(data), "Long-term AFD narrative for generated report.") { if !strings.Contains(string(data), "Short-term AFD narrative for generated report.") || !strings.Contains(string(data), "Long-term AFD narrative for generated report.") {
t.Fatalf("data package missing AFD short/long-term discussion:\n%s", string(data)) t.Fatalf("data package missing AFD short/long-term discussion:\n%s", string(data))
} }

View File

@@ -29,6 +29,12 @@ func TestDailyBriefingFromRepresentativeFixture(t *testing.T) {
Bundle: bundle, Bundle: bundle,
Units: "us", Units: "us",
Timezone: "America/Chicago", Timezone: "America/Chicago",
Location: &LocationContext{
ID: "home",
Name: "Brentwood",
Region: "St. Louis Metro",
Timezone: "America/Chicago",
},
}, summary) }, summary)
if err != nil { if err != nil {
t.Fatalf("BuildDaily() error = %v", err) t.Fatalf("BuildDaily() error = %v", err)
@@ -46,6 +52,9 @@ func TestDailyBriefingFromRepresentativeFixture(t *testing.T) {
if pkg.Metadata.Units != "us" || pkg.Metadata.Timezone != "America/Chicago" { if pkg.Metadata.Units != "us" || pkg.Metadata.Timezone != "America/Chicago" {
t.Fatalf("metadata units/timezone = %q/%q", pkg.Metadata.Units, pkg.Metadata.Timezone) t.Fatalf("metadata units/timezone = %q/%q", pkg.Metadata.Units, pkg.Metadata.Timezone)
} }
if pkg.Metadata.Location == nil || pkg.Metadata.Location.ID != "home" || pkg.Metadata.Location.Name != "Brentwood" || pkg.Metadata.Location.Region != "St. Louis Metro" || pkg.Metadata.Location.Timezone != "America/Chicago" {
t.Fatalf("metadata location = %#v, want configured prompt location", pkg.Metadata.Location)
}
if len(pkg.Metadata.Sources) != 1 || pkg.Metadata.Sources[0].DataSHA256 != "abc123" { if len(pkg.Metadata.Sources) != 1 || pkg.Metadata.Sources[0].DataSHA256 != "abc123" {
t.Fatalf("Sources = %#v, want source hash", pkg.Metadata.Sources) t.Fatalf("Sources = %#v, want source hash", pkg.Metadata.Sources)
} }

View File

@@ -31,6 +31,7 @@ type Metadata struct {
Units string `json:"units"` Units string `json:"units"`
Timezone string `json:"timezone"` Timezone string `json:"timezone"`
ValidPeriod timeutil.Period `json:"validPeriod"` ValidPeriod timeutil.Period `json:"validPeriod"`
Location *LocationContext `json:"location,omitempty"`
SourceLocationID string `json:"sourceLocationId,omitempty"` SourceLocationID string `json:"sourceLocationId,omitempty"`
SourceLocation string `json:"sourceLocation,omitempty"` SourceLocation string `json:"sourceLocation,omitempty"`
Sources []SourceMetadata `json:"sources,omitempty"` Sources []SourceMetadata `json:"sources,omitempty"`
@@ -38,6 +39,13 @@ type Metadata struct {
Alerts *AlertStatus `json:"alerts,omitempty"` Alerts *AlertStatus `json:"alerts,omitempty"`
} }
type LocationContext struct {
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Region string `json:"region,omitempty"`
Timezone string `json:"timezone,omitempty"`
}
type SourceMetadata struct { type SourceMetadata struct {
Name string `json:"name"` Name string `json:"name"`
Endpoint string `json:"endpoint,omitempty"` Endpoint string `json:"endpoint,omitempty"`
@@ -61,6 +69,7 @@ type BuildContext struct {
Bundle *forecast.Bundle Bundle *forecast.Bundle
Units string Units string
Timezone string Timezone string
Location *LocationContext
} }
func BuildMetadata(ctx BuildContext) Metadata { func BuildMetadata(ctx BuildContext) Metadata {
@@ -76,6 +85,7 @@ func BuildMetadata(ctx BuildContext) Metadata {
Units: ctx.Units, Units: ctx.Units,
Timezone: ctx.Timezone, Timezone: ctx.Timezone,
ValidPeriod: metadata.ValidPeriod, ValidPeriod: metadata.ValidPeriod,
Location: copyLocation(ctx.Location),
SourceLocationID: sourceLocationID, SourceLocationID: sourceLocationID,
SourceLocation: sourceLocation, SourceLocation: sourceLocation,
Sources: sourceMetadata(ctx.Bundle), Sources: sourceMetadata(ctx.Bundle),
@@ -84,6 +94,14 @@ func BuildMetadata(ctx BuildContext) Metadata {
} }
} }
func copyLocation(location *LocationContext) *LocationContext {
if location == nil {
return nil
}
copied := *location
return &copied
}
func Save(path string, pkg Package) error { func Save(path string, pkg Package) error {
if err := fileutil.WriteJSONAtomic(path, pkg); err != nil { if err := fileutil.WriteJSONAtomic(path, pkg); err != nil {
return fmt.Errorf("save briefing package: %w", err) return fmt.Errorf("save briefing package: %w", err)

View File

@@ -437,6 +437,7 @@ func TestRunGenerateDailyWritesMarkdownReport(t *testing.T) {
"generate", "daily", "generate", "daily",
"--config", configPath, "--config", configPath,
"--date", "2026-05-29", "--date", "2026-05-29",
"--tz", "UTC",
"--out", outPath, "--out", outPath,
}, &stdout, &stderr) }, &stdout, &stderr)
if err != nil { if err != nil {
@@ -463,6 +464,24 @@ func TestRunGenerateDailyWritesMarkdownReport(t *testing.T) {
if !strings.Contains(string(data), `data_package.v1`) || !strings.Contains(string(data), `"daily_today"`) { if !strings.Contains(string(data), `data_package.v1`) || !strings.Contains(string(data), `"daily_today"`) {
t.Fatalf("data package output missing expected content:\n%s", string(data)) t.Fatalf("data package output missing expected content:\n%s", string(data))
} }
var decoded struct {
Briefing struct {
Metadata struct {
Location struct {
ID string `json:"id"`
Name string `json:"name"`
Region string `json:"region"`
Timezone string `json:"timezone"`
} `json:"location"`
} `json:"metadata"`
} `json:"briefing"`
}
if err := json.Unmarshal(data, &decoded); err != nil {
t.Fatalf("decode data package: %v", err)
}
if decoded.Briefing.Metadata.Location.ID != "home" || decoded.Briefing.Metadata.Location.Name != "Brentwood" || decoded.Briefing.Metadata.Location.Region != "St. Louis Metro" || decoded.Briefing.Metadata.Location.Timezone != "UTC" {
t.Fatalf("location = %#v, want configured location with overridden timezone", decoded.Briefing.Metadata.Location)
}
preflightMatches, err := filepath.Glob(filepath.Join(workspaceRoot, "preflight", "daily", "2026-05-29", "*.render.json")) preflightMatches, err := filepath.Glob(filepath.Join(workspaceRoot, "preflight", "daily", "2026-05-29", "*.render.json"))
if err != nil { if err != nil {
t.Fatalf("glob preflight: %v", err) t.Fatalf("glob preflight: %v", err)

View File

@@ -14,6 +14,7 @@ const (
type Config struct { type Config struct {
WeatherAPI WeatherAPIConfig `yaml:"weather_api"` WeatherAPI WeatherAPIConfig `yaml:"weather_api"`
Location LocationConfig `yaml:"location"`
MissingSource MissingSourceConfig `yaml:"missing_source"` MissingSource MissingSourceConfig `yaml:"missing_source"`
Scriptorium ScriptoriumConfig `yaml:"scriptorium"` Scriptorium ScriptoriumConfig `yaml:"scriptorium"`
Workspace WorkspaceConfig `yaml:"workspace"` Workspace WorkspaceConfig `yaml:"workspace"`
@@ -30,6 +31,12 @@ type WeatherAPIConfig struct {
Format string `yaml:"format"` Format string `yaml:"format"`
} }
type LocationConfig struct {
ID string `yaml:"id"`
Name string `yaml:"name"`
Region string `yaml:"region"`
}
type MissingSourceConfig struct { type MissingSourceConfig struct {
Default MissingSourcePolicy `yaml:"default"` Default MissingSourcePolicy `yaml:"default"`
Sources map[string]MissingSourcePolicy `yaml:"sources"` Sources map[string]MissingSourcePolicy `yaml:"sources"`

View File

@@ -23,6 +23,9 @@ func TestDefaults(t *testing.T) {
if cfg.WeatherAPI.Format != "json" { if cfg.WeatherAPI.Format != "json" {
t.Fatalf("Format = %q, want json", cfg.WeatherAPI.Format) t.Fatalf("Format = %q, want json", cfg.WeatherAPI.Format)
} }
if cfg.Location.ID != "home" || cfg.Location.Name != "Brentwood" || cfg.Location.Region != "St. Louis Metro" {
t.Fatalf("Location = %#v, want home/Brentwood/St. Louis Metro", cfg.Location)
}
if cfg.MissingSource.Default != MissingSourceWarn { if cfg.MissingSource.Default != MissingSourceWarn {
t.Fatalf("MissingSource.Default = %q, want warn", cfg.MissingSource.Default) t.Fatalf("MissingSource.Default = %q, want warn", cfg.MissingSource.Default)
} }
@@ -43,6 +46,9 @@ func TestLoadExampleConfig(t *testing.T) {
if cfg.MissingSource.Sources["alerts"] != MissingSourceNone { if cfg.MissingSource.Sources["alerts"] != MissingSourceNone {
t.Fatalf("alerts policy = %q, want none", cfg.MissingSource.Sources["alerts"]) t.Fatalf("alerts policy = %q, want none", cfg.MissingSource.Sources["alerts"])
} }
if cfg.Location.ID != "home" || cfg.Location.Name != "Brentwood" || cfg.Location.Region != "St. Louis Metro" {
t.Fatalf("Location = %#v, want example location", cfg.Location)
}
} }
func TestLoadMinimalExampleConfig(t *testing.T) { func TestLoadMinimalExampleConfig(t *testing.T) {
@@ -63,6 +69,9 @@ func TestLoadMinimalExampleConfig(t *testing.T) {
if cfg.Workspace.Root != "workspace" { if cfg.Workspace.Root != "workspace" {
t.Fatalf("Workspace.Root = %q, want default workspace", cfg.Workspace.Root) t.Fatalf("Workspace.Root = %q, want default workspace", cfg.Workspace.Root)
} }
if cfg.Location.Name != "Brentwood" {
t.Fatalf("Location.Name = %q, want default Brentwood", cfg.Location.Name)
}
} }
func TestExplicitMissingConfigReturnsError(t *testing.T) { func TestExplicitMissingConfigReturnsError(t *testing.T) {

View File

@@ -13,6 +13,11 @@ func Defaults() Config {
Timezone: "America/Chicago", Timezone: "America/Chicago",
Format: "json", Format: "json",
}, },
Location: LocationConfig{
ID: "home",
Name: "Brentwood",
Region: "St. Louis Metro",
},
MissingSource: MissingSourceConfig{ MissingSource: MissingSourceConfig{
Default: MissingSourceWarn, Default: MissingSourceWarn,
Sources: map[string]MissingSourcePolicy{}, Sources: map[string]MissingSourcePolicy{},

View File

@@ -31,6 +31,9 @@ func TestBuildDailyDataPackage(t *testing.T) {
if pkg.Briefing.Daily == nil { if pkg.Briefing.Daily == nil {
t.Fatal("Briefing.Daily = nil") t.Fatal("Briefing.Daily = nil")
} }
if pkg.Briefing.Metadata.Location == nil || pkg.Briefing.Metadata.Location.Name != "Brentwood" {
t.Fatalf("Briefing.Metadata.Location = %#v, want configured location", pkg.Briefing.Metadata.Location)
}
if pkg.RecentChanges.Items == nil || len(pkg.RecentChanges.Items) != 0 { if pkg.RecentChanges.Items == nil || len(pkg.RecentChanges.Items) != 0 {
t.Fatalf("RecentChanges.Items = %#v, want empty slice", pkg.RecentChanges.Items) t.Fatalf("RecentChanges.Items = %#v, want empty slice", pkg.RecentChanges.Items)
} }
@@ -155,6 +158,12 @@ func validBriefingPackage() briefing.Package {
GeneratedAt: generatedAt, GeneratedAt: generatedAt,
Units: "us", Units: "us",
Timezone: "America/Chicago", Timezone: "America/Chicago",
Location: &briefing.LocationContext{
ID: "home",
Name: "Brentwood",
Region: "St. Louis Metro",
Timezone: "America/Chicago",
},
ValidPeriod: timeutil.Period{ ValidPeriod: timeutil.Period{
Start: time.Date(2026, 5, 29, 5, 0, 0, 0, time.UTC), Start: time.Date(2026, 5, 29, 5, 0, 0, 0, time.UTC),
End: time.Date(2026, 5, 30, 5, 0, 0, 0, time.UTC), End: time.Date(2026, 5, 30, 5, 0, 0, 0, time.UTC),

View File

@@ -122,6 +122,9 @@ func TestSaveArtifactsAndMetadataRoundTrip(t *testing.T) {
if decoded.RenderedReportPath != renderedReportPath { if decoded.RenderedReportPath != renderedReportPath {
t.Fatalf("RenderedReportPath = %q, want %q", decoded.RenderedReportPath, renderedReportPath) t.Fatalf("RenderedReportPath = %q, want %q", decoded.RenderedReportPath, renderedReportPath)
} }
if decoded.Location == nil || decoded.Location.Name != "Brentwood" || decoded.Location.Timezone != "America/Chicago" {
t.Fatalf("metadata location = %#v, want briefing location", decoded.Location)
}
if strings.Contains(string(data), "MetadataPath") || strings.Contains(string(data), "metadataPath") { if strings.Contains(string(data), "MetadataPath") || strings.Contains(string(data), "metadataPath") {
t.Fatalf("metadata JSON includes runtime-only MetadataPath:\n%s", string(data)) t.Fatalf("metadata JSON includes runtime-only MetadataPath:\n%s", string(data))
} }
@@ -437,6 +440,12 @@ func stateBriefingPackage(resolved report.Resolved) briefing.Package {
GeneratedAt: resolved.GeneratedAt, GeneratedAt: resolved.GeneratedAt,
Units: "us", Units: "us",
Timezone: resolved.Timezone, Timezone: resolved.Timezone,
Location: &briefing.LocationContext{
ID: "home",
Name: "Brentwood",
Region: "St. Louis Metro",
Timezone: resolved.Timezone,
},
ValidPeriod: resolved.ValidPeriod, ValidPeriod: resolved.ValidPeriod,
}, },
Daily: &briefing.Daily{ForecastSummaryDate: "2026-05-29"}, Daily: &briefing.Daily{ForecastSummaryDate: "2026-05-29"},

View File

@@ -21,6 +21,7 @@ type Metadata struct {
GeneratedAt time.Time `json:"generatedAt"` GeneratedAt time.Time `json:"generatedAt"`
Timezone string `json:"timezone"` Timezone string `json:"timezone"`
ValidPeriod timeutil.Period `json:"validPeriod"` ValidPeriod timeutil.Period `json:"validPeriod"`
Location *briefing.LocationContext `json:"location,omitempty"`
SourceLocationID string `json:"sourceLocationId,omitempty"` SourceLocationID string `json:"sourceLocationId,omitempty"`
SourceLocation string `json:"sourceLocation,omitempty"` SourceLocation string `json:"sourceLocation,omitempty"`
Sources []briefing.SourceMetadata `json:"sources,omitempty"` Sources []briefing.SourceMetadata `json:"sources,omitempty"`
@@ -43,6 +44,7 @@ func BuildMetadata(resolved report.Resolved, briefingPackage briefing.Package, p
GeneratedAt: metadata.GeneratedAt, GeneratedAt: metadata.GeneratedAt,
Timezone: metadata.Timezone, Timezone: metadata.Timezone,
ValidPeriod: metadata.ValidPeriod, ValidPeriod: metadata.ValidPeriod,
Location: copyLocation(briefingPackage.Metadata.Location),
SourceLocationID: briefingPackage.Metadata.SourceLocationID, SourceLocationID: briefingPackage.Metadata.SourceLocationID,
SourceLocation: briefingPackage.Metadata.SourceLocation, SourceLocation: briefingPackage.Metadata.SourceLocation,
Sources: briefingPackage.Metadata.Sources, Sources: briefingPackage.Metadata.Sources,
@@ -53,3 +55,11 @@ func BuildMetadata(resolved report.Resolved, briefingPackage briefing.Package, p
RenderedReportPath: paths.RenderedReport, RenderedReportPath: paths.RenderedReport,
} }
} }
func copyLocation(location *briefing.LocationContext) *briefing.LocationContext {
if location == nil {
return nil
}
copied := *location
return &copied
}