# Distributor Report Paths Roadmap ## Purpose This roadmap defines the target behavior for naming Markdown reports inside distributor source bundles. Weatherreporter currently uses one application-level `notify.distributor.report_path_templates` list for every report type. That model is too coarse for the intended output layout because different reports need different archive paths, latest paths, and report-specific aliases. ## Locked Decisions - Remove `notify.distributor.report_path_templates`; do not keep a legacy fallback or compatibility alias. - Report definitions own canonical distributor output path templates. - Configuration may override distributor output path templates per report. - The app layer resolves report-specific distributor bundle paths before calling the distributor adapter. - The distributor adapter continues to receive explicit source-to-bundle file mappings and does not choose report types, render templates, scan workspaces, or apply report routing policy. - Managed Markdown report files remain the only distributor upload sources. Optional local output copies are not uploaded. - Batch distributor uploads, when enabled, use the same report-specific bundle path resolver for each included report. - Non-roadmap documentation must not describe this behavior until it is implemented. ## Target Configuration Model The global path template list is removed from `notify.distributor`: ```yaml notify: distributor: enabled: false endpoint: https://distributor.example.com token_env: DISTRIBUTOR_UPLOAD_TOKEN timeout: 30s failure_policy: error pipeline_id_template: "weatherreporter.{report_id}" bundle_id_template: "weatherreporter.{location_id}.{report_id}" idempotency_key_template: "{bundle_id}.{run_id}" ``` Per-report overrides live under `reports..distributor`: ```yaml reports: daily: distributor: path_templates: - "daily/{valid_start_date}/{run_id}.md" - "daily/{valid_start_date}/index.md" ``` If a report override is omitted, weatherreporter uses the defaults declared by that report definition. ## Default Report Paths Each generated report maps its managed Markdown source file to one or more bundle-relative distributor paths. | Report | Default distributor paths | | --- | --- | | `hourly` | `hourly/index.md` | | `daily` | `daily/{valid_start_date}/{run_id}.md`; `daily/{valid_start_date}/index.md` | | `today` | `daily/{valid_start_date}/{run_id}.md`; `daily/{valid_start_date}/index.md`; `today/index.md` | | `tomorrow` | `daily/{valid_start_date}/{run_id}.md`; `daily/{valid_start_date}/index.md`; `tomorrow/index.md` | | `three_day` | `three-day/{valid_start_date}/{run_id}.md`; `three-day/{valid_start_date}/index.md` | | `weekend` | `weekend/{valid_start_date}/{run_id}.md`; `weekend/{valid_start_date}/index.md` | | `storm` | `storm/{storm_id}/{run_id}.md`; `storm/{storm_id}/index.md` | `storm_id` is derived from the resolved storm valid period until a future explicit storm identity source exists. ## Template Values Report path templates keep the existing report template values: - `location_id` - `report_id` - `run_id` - `artifact_group` - `batch_output_name` - `valid_start_date` - `valid_end_date` - `valid_start_time` - `valid_end_time` - `valid_start_stamp` - `valid_end_stamp` - `storm_id` The initial `storm_id` value is `{valid_start_stamp}-{valid_end_stamp}` in the effective report timezone. It is available for all single-report distributor templates, but it renders as an empty value for non-storm reports. Rendered paths must stay unique relative paths using `/` separators. They must not contain backslashes, empty path segments, `.`, `..`, `manifest.json`, or `.distributor.json`. ## Intended Final State `internal/report.Definition` declares distributor path defaults alongside the other report-owned behavior such as report ID, prompt ID, valid-period resolution, module composition, comparison strategy, artifact group, and output name. `internal/config` owns per-report override loading and validation. Unknown fields under report config continue to fail validation or YAML unmarshalling. `internal/app` resolves bundle paths through one helper used by both single-report notification and batch notification. That helper applies this precedence: 1. `reports..distributor.path_templates`, when explicitly configured. 2. `report.Definition` distributor path defaults. There is no third global fallback. The distributor adapter API remains unchanged unless a separate adapter concern requires it. It should still upload the explicit file mappings passed by the app layer.