113 lines
5.7 KiB
Markdown
113 lines
5.7 KiB
Markdown
# State Internals
|
|
|
|
The `internal/state` package owns filesystem-backed run state: safe path
|
|
derivation, metadata persistence, prior-report lookup, and read-only report
|
|
inspection. It does not decide which reports to generate or deliver. For the
|
|
operator-facing layout and retention procedures, see the
|
|
[operations guide](../operations.md).
|
|
|
|
## Store construction and artifact paths
|
|
|
|
`NewFilesystemStore` requires a workspace root and rejects absolute or
|
|
escaping values for every configured state directory. `Paths` then validates a
|
|
run ID and artifact group before deriving all paths from the report's valid
|
|
start date (`YYYY-MM-DD`). This keeps a run's artifacts together while making
|
|
the paths safe to use below the configured workspace.
|
|
|
|
| Artifact | Derived location |
|
|
| --- | --- |
|
|
| Module snapshot | `snapshots/<group>/<date>/modules.<run-id>.json` |
|
|
| Metadata | `snapshots/<group>/<date>/metadata.<run-id>.json` |
|
|
| Data package | `data-packages/<group>/<date>/data_package.<run-id>.yaml` |
|
|
| Prompt preparation | `preflight/<group>/<date>/prompt_preparation.<run-id>.json` |
|
|
| Prompt execution | `snapshots/<group>/<date>/prompt_execution.<run-id>.json` |
|
|
| Render preflight | `preflight/<group>/<date>/render.<run-id>.json` |
|
|
| Notification record | `notifications/<group>/<date>/distributor.<run-id>.json` |
|
|
| Managed report | `reports/<group>/<date>/report.<run-id>.md` |
|
|
| Generated text | `snapshots/<group>/<date>/generated_text.<run-id>.json` |
|
|
| Generated-text source and result | `snapshots/<group>/<date>/generated_text_raw.<run-id>.json` and `generated_text_result.<run-id>.json` |
|
|
| Generated-text render context | `snapshots/<group>/<date>/render_context.<run-id>.json` |
|
|
|
|
The configured notification root separates notification artifacts from report
|
|
artifacts; single-report notification paths use the report's valid date. Report
|
|
producers create parent directories as needed and write the report body; state
|
|
is responsible for the surrounding paths and saved run artifacts.
|
|
|
|
Batch Distributor notifications are derived separately as
|
|
`notifications/batches/<batch>/<local-date>/distributor.<batch-run-id>.json`.
|
|
Their date is calculated from the batch start in its configured location, and
|
|
the batch identity and run ID receive the same path-segment validation as
|
|
single-report artifact identifiers.
|
|
|
|
## Metadata and durable writes
|
|
|
|
`Metadata` is the durable inventory for a run. It records its schema version,
|
|
run identity, generated and valid timestamps, artifact group, source content
|
|
and provenance, and the module snapshot, data-package, prompt preparation,
|
|
prompt execution, report, generated-artifact, and notification locations when
|
|
present. New prompt records use `weatherreporter.metadata.v2`; historic
|
|
`weatherreporter.metadata.v1` records remain readable and retain their legacy
|
|
JSON field names when inspected.
|
|
|
|
`BuildMetadataFromBriefingMetadata` establishes legacy common fields, while
|
|
`BuildPromptMetadataFromBriefingMetadata` establishes the V2 record. The
|
|
application adds locations only after the corresponding artifacts are
|
|
produced. `SaveMetadata` requires the run ID, module snapshot, data package,
|
|
metadata path, and the matching preparation reference for its schema. The
|
|
package also saves module snapshots, data packages, prompt preparation and
|
|
execution records, legacy preflight records, generated-text artifacts, render
|
|
contexts, and notifications. JSON writes use atomic replacement, so readers do
|
|
not observe a partially written state file.
|
|
|
|
## Explicit prompt debug storage
|
|
|
|
`PromptDebugWriter` is a separate, opt-in boundary for content-rich prompt
|
|
diagnostics. It is constructed with an explicit absolute operator root, rather
|
|
than a workspace-derived path. A blank root produces a disabled writer that
|
|
does not access the filesystem.
|
|
|
|
Enabled debug captures are grouped as
|
|
`<root>/<report-id>/<valid-date>/<run-id>/` and contain `preparation.json` and
|
|
`execution.json`. The writer rejects symlinks, unsafe path segments, path
|
|
escape, and non-directory roots; it creates its directories with `0700` and
|
|
writes files atomically with `0600`. Normal state discovery and inspection do
|
|
not read this root. Its wire records map only approved project-owned fields;
|
|
credentials and dependency objects are not persisted.
|
|
|
|
The data package itself follows the shared
|
|
[prompt-input contract](prompt-input.md). Report text, templates, and external
|
|
delivery payloads remain owned by their respective packages and integration
|
|
references.
|
|
|
|
## Prior reports and inspection
|
|
|
|
`FindPriorSnapshot` searches metadata rather than guessing from filenames. It
|
|
only considers an earlier compatible report in the same artifact group and
|
|
supports the comparison strategies defined by the report request:
|
|
|
|
- `same_valid_date` finds an earlier generated report for the same valid day.
|
|
|
|
The newest eligible metadata record wins; the current run is excluded.
|
|
Unreadable or malformed candidate metadata is ignored so a damaged historical
|
|
record does not block a new run.
|
|
|
|
`ListReports` walks saved metadata, returns results ordered newest-first by
|
|
generation time, and treats a missing snapshots directory as an empty history.
|
|
`LoadMetadataByRunID` builds on that inspection path. These APIs are read-only;
|
|
repairing or pruning stored state is an operational concern.
|
|
|
|
## Boundaries and verification
|
|
|
|
The package rejects unsafe path components and incomplete metadata before
|
|
writing. Callers must provide a valid report request, artifact group, and
|
|
store configuration. Its focused tests cover path derivation, atomic
|
|
persistence, metadata validation, comparison eligibility, and report listing:
|
|
|
|
```sh
|
|
go test ./internal/state
|
|
```
|
|
|
|
See [application orchestration](app-orchestration.md) for the order in which
|
|
these artifacts are created and [report templates](../templates.md) for the
|
|
user-facing report contract.
|