6.6 KiB
State Internals
This document describes filesystem state in internal/state.
Purpose
internal/state owns managed workspace paths, atomic JSON writes, persisted
metadata, prior snapshot lookup, and read-only artifact inspection helpers.
Inputs And Outputs
Inputs:
- workspace configuration
- resolved report definition and valid period
- module snapshot
- prompt input data package
- preflight artifact
- generated-text raw, run-result, validated text, and render-context artifacts
- rendered report path preparation request
- RunID for inspection lookups
Outputs:
- module snapshot JSON path
- prompt input data package YAML path
- render preflight JSON path
- generated-text raw JSON path
- generated-text run-result JSON path
- validated generated-text JSON path
- render context JSON path
- managed Markdown report path
- metadata JSON path
- distributor notification debug artifact paths
- prior comparable snapshot metadata
- loaded module snapshot, data package, generated text, generated-text run result, or render context
- recent report records for inspection
Boundaries
internal/state owns local filesystem layout, path validation, durable writes,
metadata reads, prior lookup, and report listing. It does not fetch weather
data, derive forecasts, build prompt input content, compare module contents,
invoke Scriptorium, import adapter result types, or parse CLI flags.
Preflight persistence uses the state-owned PreflightArtifact shape. The app
converts adapter render results into that shape before saving.
Config Fields Used
workspace.rootworkspace.snapshots_dirworkspace.reports_dirworkspace.data_packages_dirworkspace.preflight_dirworkspace.notifications_dir
Workspace subdirectories must be relative paths that stay under
workspace.root.
Managed Layout
Paths are derived from the resolved report definition's artifact group, the valid-period start date, and the RunID. Filenames put the artifact kind before the RunID.
<workspace.root>/
reports/<artifact_group>/<YYYY-MM-DD>/report.<run_id>.md
snapshots/<artifact_group>/<YYYY-MM-DD>/modules.<run_id>.json
snapshots/<artifact_group>/<YYYY-MM-DD>/metadata.<run_id>.json
snapshots/<artifact_group>/<YYYY-MM-DD>/generated_text_raw.<run_id>.json
snapshots/<artifact_group>/<YYYY-MM-DD>/generated_text_result.<run_id>.json
snapshots/<artifact_group>/<YYYY-MM-DD>/generated_text.<run_id>.json
snapshots/<artifact_group>/<YYYY-MM-DD>/render_context.<run_id>.json
data-packages/<artifact_group>/<YYYY-MM-DD>/data_package.<run_id>.yaml
preflight/<artifact_group>/<YYYY-MM-DD>/render.<run_id>.json
notifications/<artifact_group>/<YYYY-MM-DD>/distributor.<run_id>.json
notifications/batches/<batch>/<YYYY-MM-DD>/distributor.<batch_run_id>.json
Metadata is stored beside module snapshots and links the module snapshot, data package, preflight, report paths, notification path when attempted, and configured prompt location. For generated-text-template reports, metadata also records the generated text schema ID and links the raw generated text, Scriptorium run result, validated generated text, and render context artifacts. Markdown-report metadata omits those generated-text fields. Report listing walks metadata files under the snapshots directory.
Batch notification artifacts are stored under the notifications tree rather than report metadata because they describe a batch-level upload. The date directory is the batch start date in the effective report timezone.
Prior Lookup
Prior snapshot lookup reads stored metadata through the shared lookup path and selects the latest earlier snapshot whose report ID is compatible with the current report definition.
- Daily Report compares with prior Daily Report snapshots for the same valid local date.
- Today Report compares with prior Today Report snapshots for the same valid local date.
- Tomorrow Report compares with prior Tomorrow Report snapshots for the same valid local date.
- 3-Day Outlook compares with prior 3-Day snapshots for the same valid local date.
- Weekend Outlook compares with prior Weekend snapshots for the same weekend window.
- Hourly Report uses the rolling-window comparison strategy and currently returns no prior snapshot from filesystem lookup.
- Storm Report has no prior lookup because explicit event-window comparison is not searched by the filesystem store.
Writes And Inspection
Durable JSON writes use shared atomic file helpers. Generated-text raw and validated JSON artifacts are written atomically as bytes; generated-text run result and render context artifacts are written atomically as JSON. Managed Markdown reports are prepared by creating their parent directory; Scriptorium writes the report body to the prepared path. Extra Markdown copies are handled by app orchestration. Distributor notification debug artifacts are written atomically when notification is attempted and include rendered distributor pipeline ID, bundle ID, idempotency key, bundle paths, upload status, latest run status, and redacted errors.
Single-report notification artifacts use schema version
weatherreporter.distributor_notification.v1 and record one managed source
path plus that source's bundle paths. Batch notification artifacts use schema
version weatherreporter.batch_distributor_notification.v1 and record:
batchbatchRunIdattemptedAtendpointpipelineIdbundleIdidempotencyKeybundleCreatedincludedReports, each withreportId,runId,sourcePath, andbundlePathsstatusuploadrunStatusstatusErrorerror
Inspection helpers read existing metadata, module snapshot, data package, generated text, generated-text run result, and render context files. Missing metadata directories return no inspection records or no prior snapshot rather than creating state.
Failure Behavior
- Invalid workspace paths return validation errors.
- Missing required metadata fields prevent metadata writes.
- JSON writes use a temporary file followed by rename where practical.
- Read and decode failures include path context.
- Unknown RunIDs produce an actionable lookup error.
Tests
Inspect:
internal/state/filesystem_test.gointernal/app/app_test.go
Invariants
- Managed paths stay under the configured workspace root.
- Artifact grouping comes from report definitions.
- Metadata links artifacts produced for a run.
- Generated-text artifacts live under the snapshots tree beside module snapshots and metadata.
- Batch notification artifacts live under
notifications/batchesand are not linked from report metadata. - Prior lookup is based on structured metadata, not rendered report text.