diff --git a/docs/internal/app-orchestration.md b/docs/internal/app-orchestration.md index 174184f..1550406 100644 --- a/docs/internal/app-orchestration.md +++ b/docs/internal/app-orchestration.md @@ -4,37 +4,46 @@ This document describes the implemented workflow coordinator in `internal/app`. ## Purpose -`internal/app` coordinates top-level use cases: generating one report through -the shared report-generation path, running morning or evening batches, building -inspectable briefing artifacts, fetching weather bundles, and reading existing +`internal/app` coordinates the top-level use cases after CLI parsing and config +loading are complete. It resolves report definitions, fetches weather data, +builds briefing and prompt-input artifacts, invokes Scriptorium through the +adapter boundary, persists managed state, runs batches, and reads existing artifacts for inspection. ## Inputs And Outputs Inputs: -- app request structs containing config, report or batch selection, clock time, - optional report date, optional Storm Report bounds, output paths, renderer - fakes, or state-store fakes +- `GenerateRequest` for one report command +- `BatchRequest` for morning or evening batch commands +- `FetchBundleRequest` for explicit bundle fetch and save workflows +- `BriefingRequest` and `ReportRequest` for package-level orchestration tests + and internal composition - resolved report definitions from `internal/report` -- forecast bundles from the Weather API adapter -- prior briefing snapshots from `internal/state` +- forecast bundles from `internal/adapters/weatherapi` +- prior snapshots loaded from `internal/state` +- optional renderer and state-store fakes for tests Outputs: -- report results for generated report definitions with briefing, data package, - preflight, report, metadata, prior snapshot, Recent Changes, and Scriptorium - results -- batch summaries with per-report status and artifact paths +- generated report results with briefing, data package, preflight, report, + metadata, prior snapshot, Recent Changes, and Scriptorium result details +- batch summaries with per-report status, artifact paths, and error text +- saved Weather API bundle JSON for fetch workflows - inspection JSON values for reports, metadata, briefings, data packages, prior snapshots, and source provenance ## Boundaries -- The package coordinates workflow order. -- It does not parse CLI flags, load YAML files directly, implement HTTP calls, - derive forecast facts, define report periods, compare Markdown, or construct - Scriptorium argv. +`internal/app` owns workflow order and request composition. It does not parse +CLI flags, load YAML files directly, implement HTTP transport, derive forecast +facts, define report periods, compare rendered Markdown, or construct +Scriptorium argv. + +Report selection and report identity policy come from `internal/report`. +Weather API transport stays in `internal/adapters/weatherapi`. Scriptorium +subprocess behavior stays in `internal/adapters/scriptorium`. Filesystem layout +and persisted metadata stay in `internal/state`. ## Config Fields Used @@ -44,36 +53,57 @@ Outputs: - `dayparts` for daily and outlook summarization - `recent_change.*` for structured Recent Changes thresholds -## External Adapters Used +Output copy flags are command request fields. They are not configuration +defaults. -- `internal/adapters/weatherapi` for forecast bundle fetching -- `internal/adapters/scriptorium` for render preflight and report generation -- `internal/state` filesystem store for persisted artifacts +## Generation Workflow -## State Or Manifest Behavior +Single-report generation follows this order: -Generation saves the briefing snapshot, data package, preflight result when -available, rendered report, and metadata. Metadata links all managed artifact -paths. Inspection workflows read existing state and do not fetch weather data or -invoke Scriptorium. +1. Resolve the command report to a `report.Resolved` value. +2. Create or use a filesystem store. +3. Locate any prior compatible snapshot through `internal/state`. +4. Fetch a Weather API bundle. +5. Build a report-specific briefing package. +6. Save the briefing snapshot. +7. Compute Recent Changes from structured prior and current briefings. +8. Build and save the Scriptorium `data_package`. +9. Run Scriptorium render preflight. +10. Save preflight JSON when a render result is available. +11. Save metadata for inspection. +12. Run Scriptorium report generation to the managed report path. +13. Copy the managed report to the requested `--out` path when provided. +14. Save metadata with the managed report path. -## Skip And Resume Behavior +If render preflight returns both a result and an error, preflight JSON and +metadata are persisted before the error is returned. If Scriptorium report +generation returns an error after writing output, the managed report and +metadata remain inspectable. -There is no resume workflow. Batch generation continues remaining independent -reports after one report fails, then reports aggregate success and failure -counts. +## Batch Workflow + +`run morning` resolves Daily Today, 3-Day Outlook, and Weekend Outlook except +on Sunday. `run evening` resolves Daily Tomorrow. Batch output copy names come +from report definitions. Batch generation continues independent reports after a +failure, records each result, writes compact status lines to stderr, emits a +JSON summary to stdout, and returns an aggregate error when any report failed. + +## Inspection Workflow + +Inspection workflows load existing filesystem state only. They do not fetch +weather data or invoke Scriptorium. Run-specific inspect commands share the same +store and metadata lookup path, then load the requested artifact or derived +inspection view. ## Failure Behavior - Resolve errors stop the requested workflow before fetching weather data. -- Weather API or briefing errors stop that report before Scriptorium is called. -- Render preflight runs before Scriptorium report generation. -- If render preflight returns a result and an error, preflight JSON and metadata - are persisted before the error is returned. -- If Scriptorium report generation returns an error after writing output, - metadata and the managed report path remain inspectable. -- Batch failures are recorded per report and surfaced through aggregate batch - failure. +- Weather API and briefing errors stop that report before Scriptorium runs. +- Prompt input validation fails before render preflight. +- Render and run errors preserve Scriptorium stderr and exit-code context. +- Metadata and artifact path errors include filesystem context. +- Batch failures are recorded per report and surfaced through an aggregate + batch error. ## Tests diff --git a/docs/internal/report-registry.md b/docs/internal/report-registry.md index 1b060d9..5afe92d 100644 --- a/docs/internal/report-registry.md +++ b/docs/internal/report-registry.md @@ -1,59 +1,81 @@ # Report Registry Internals This document describes report identity, valid-period resolution, batch -membership, and comparison declarations in `internal/report`. +membership, output naming, artifact grouping, and comparison declarations in +`internal/report`. ## Purpose -`internal/report` centralizes report definitions so report IDs, prompt IDs, -artifact groups, batch output names, generated-report eligibility, comparison -compatibility, comparison strategies, and valid periods are declared in one -package. +`internal/report` is the canonical source for report definitions. App, state, +briefing, and CLI wiring consume resolved definitions instead of owning report +identity policy themselves. -## Inputs And Outputs +## Definition Fields -Inputs: +Each report definition declares: -- report ID or batch name -- generation time -- timezone -- optional Daily date override -- optional Storm Report start and end times +- report ID and display name +- Scriptorium prompt ID +- valid-period resolver +- comparison strategy +- managed artifact group +- batch output copy filename +- generated-report eligibility +- prior-report compatibility list +- morning or evening batch membership -Outputs: +## Implemented Reports -- `report.Resolved` values with definition metadata and half-open valid periods -- `report.Metadata` values used by briefing and persisted metadata builders +| Report | ID | Prompt | Artifact group | Batch copy | Prior compatibility | +| --- | --- | --- | --- | --- | --- | +| Daily Today | `daily_today` | `weather.daily_report` | `daily` | `daily.md` | Daily Today, Daily Tomorrow | +| Daily Tomorrow | `daily_tomorrow` | `weather.daily_report` | `daily` | `tomorrow.md` | Daily Today, Daily Tomorrow | +| 3-Day Outlook | `three_day` | `weather.three_day_outlook` | `three-day` | `three-day.md` | 3-Day Outlook | +| Weekend Outlook | `weekend` | `weather.weekend_outlook` | `weekend` | `weekend.md` | Weekend Outlook | +| Storm Report | `storm` | `weather.storm_report` | `storm` | `storm.md` | Storm Report | + +All implemented report definitions are eligible for generation. + +## Valid Periods + +- Daily Today covers the selected local civil day, or the current local civil + day when no date override is supplied. +- Daily Tomorrow covers the next local civil day from generation time. +- 3-Day Outlook covers the interval from generation time through local midnight + three days later. +- Weekend Outlook covers the upcoming weekend window and is not scheduled for + Sunday morning batch resolution. +- Storm Report covers an explicit event window supplied by the caller. + +Storm event windows can be parsed from local `YYYY-MM-DDTHH:MM` timestamps in +the configured timezone or RFC3339 timestamps with explicit offsets. End time +must be after start time. ## Boundaries -- This package defines report identity and time coverage only. -- It does not fetch weather data, build briefings, compare snapshots, write - state, parse CLI flags, or invoke Scriptorium. +`internal/report` defines report metadata and time coverage. It does not fetch +weather data, build briefings, compare briefing contents, write state, parse CLI +flags, or invoke Scriptorium. + +The CLI owns public command names. The app maps those command names to report +IDs, then uses the registry for report policy. ## Config Fields Used The app supplies `weather_api.timezone` as a loaded `time.Location`. Batch output path copying uses batch output names from report definitions. -## External Adapters Used +## State And App Usage -None. - -## State Or Manifest Behavior - -None directly. Resolved metadata contributes RunID, report ID, prompt ID, -generation time, timezone, and valid period to later briefing and state -metadata. Artifact groups declared by report definitions are used by state path -construction. - -## Skip And Resume Behavior - -No resume behavior. Morning batch resolution skips Weekend Outlook on Sunday. +- State paths use `ArtifactGroup`. +- Batch output copies use `BatchOutputName`. +- Generation checks `Generated`. +- Prior lookup checks `CompatiblePriorIDs` and the comparison strategy. +- RunIDs include the resolved report ID. ## Failure Behavior -- Unknown reports and batch names return actionable errors. +- Unknown report IDs and batch names return actionable errors. - Weekend Outlook resolution returns an error when resolved directly on Sunday. - Storm Report resolution requires start and end, with end after start. diff --git a/docs/internal/scriptorium-adapter.md b/docs/internal/scriptorium-adapter.md index 9123734..1e3ea21 100644 --- a/docs/internal/scriptorium-adapter.md +++ b/docs/internal/scriptorium-adapter.md @@ -6,8 +6,9 @@ This document describes the subprocess adapter in ## Purpose The adapter runs `scriptorium render` for prompt preflight and `scriptorium run` -for Markdown report generation while isolating subprocess details from domain -packages. +for Markdown report generation. It isolates subprocess execution, argv +construction, timeout handling, output capture, and exit-code interpretation +from app and domain packages. ## Inputs And Outputs @@ -17,19 +18,25 @@ Inputs: - prompt input data package path - report output path for `run` - configured binary, config path, profile, timeout, and extra arguments +- context for cancellation Outputs: - argv used for execution -- captured stdout and stderr with truncation flags +- captured stdout and stderr +- truncation flags for captured output - exit code - report output path for `run` ## Boundaries -- This adapter owns Scriptorium argv construction and subprocess execution. -- It does not choose report types, build prompt input, fetch weather data, - decide workflow order, or persist workflow metadata. +`internal/adapters/scriptorium` owns Scriptorium command construction and +subprocess execution. It does not choose report types, build prompt input, +fetch weather data, decide workflow order, or persist workflow metadata. + +The adapter exposes request and result structs for render and run operations. +State persistence uses a state-owned preflight artifact shape; app +orchestration converts render results before saving. ## Config Fields Used @@ -39,29 +46,43 @@ Outputs: - `scriptorium.timeout` - `scriptorium.extra_args` -## External Adapters Used +## Commands -- external `scriptorium` CLI +Render preflight argv starts with: -See [Scriptorium integration](../integrations/scriptorium.md) for the external -CLI contract used by this project. +```text +scriptorium render --prompt --input data_package= --format json +``` -## State Or Manifest Behavior +Report generation argv starts with: -None directly. The adapter returns render and run results; app orchestration and -state own managed preflight paths and metadata links. +```text +scriptorium run --prompt --input data_package= --out +``` -## Skip And Resume Behavior +Configured `--config` and `--profile` flags are inserted after the subcommand +and before prompt-specific arguments. Extra arguments are appended after the +built-in arguments. -None. Context cancellation and configured timeout stop subprocess execution. +## Execution Behavior + +The adapter runs commands without shell interpolation. The same private +execution path is used by render and run after command-specific request +validation and argv construction. + +When `scriptorium.timeout` is greater than zero, each subprocess call uses a +context with that timeout. Stdout and stderr are captured separately, capped at +1 MiB each, and marked as truncated when the cap is reached. ## Failure Behavior -- Missing prompt ID, data package path, or run output path returns an error. -- Subprocess start or context errors are wrapped with operation context. -- Nonzero render and run exits return captured output plus an error containing - exit code and stderr. -- Captured stdout and stderr are size-limited and marked when truncated. +- Missing prompt ID or data package path returns an error before subprocess + execution. +- Missing run output path returns an error before subprocess execution. +- Subprocess start errors, context cancellation, and timeouts are wrapped with + operation context by the caller-facing method. +- Nonzero render and run exits return the captured result plus an error + containing the exit code and stderr. ## Tests @@ -75,4 +96,5 @@ Inspect: - No shell interpolation is used. - The Scriptorium input name is `data_package`. +- Render and run preserve command-specific result structs. - Scriptorium-specific flags stay inside adapter and config boundaries. diff --git a/docs/internal/state.md b/docs/internal/state.md index b235543..92f3b6c 100644 --- a/docs/internal/state.md +++ b/docs/internal/state.md @@ -4,7 +4,7 @@ This document describes filesystem state in `internal/state`. ## Purpose -`internal/state` owns managed artifact paths, atomic JSON writes, persisted +`internal/state` owns managed workspace paths, atomic JSON writes, persisted metadata, prior snapshot lookup, and read-only artifact inspection helpers. ## Inputs And Outputs @@ -32,11 +32,13 @@ Outputs: ## Boundaries -- This package owns managed workspace layout, path validation, filesystem - writes, and metadata reads. -- It does not fetch weather data, derive forecasts, build prompt input content, - compare briefing contents, invoke Scriptorium, import adapter result types, or - parse CLI flags. +`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 briefing 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 @@ -49,31 +51,48 @@ Outputs: Workspace subdirectories must be relative paths that stay under `workspace.root`. -## External Adapters Used +## Managed Layout -- local filesystem +Paths are derived from the resolved report definition's artifact group, the +valid-period start date for JSON artifacts, and the RunID. -## State Or Manifest Behavior +```text +/ + snapshots///.briefing.json + snapshots///.metadata.json + data-packages///.data_package.json + preflight///.render.json + reports//.md +``` -Managed paths are grouped by the report definition's artifact group and -valid-period start date for JSON artifacts. Reports are written under the same -artifact group. Metadata is stored beside briefing snapshots and links -briefing, data package, preflight, and report paths. Report listing walks -metadata files under the snapshots directory. +Metadata is stored beside briefing snapshots and links the briefing, data +package, preflight, and report paths. Report listing walks metadata files under +the snapshots directory. -Prior snapshot lookup reads metadata through the shared lookup path and selects -the latest earlier snapshot whose report ID is compatible according to the -current report definition. Daily Today and Daily Tomorrow are compatible with -each other 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. Storm Report currently has -no prior lookup because its comparison strategy is not searched by the -filesystem store. +## Prior Lookup -## Skip And Resume Behavior +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. -There is no resume workflow. Missing metadata directories return no inspection -records or no prior snapshot rather than creating state. +- Daily Today and Daily Tomorrow are compatible with each other 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. +- Storm Report currently 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. 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. + +Inspection helpers read existing metadata, briefing, and data package files. +Missing metadata directories return no inspection records or no prior snapshot +rather than creating state. ## Failure Behavior @@ -93,5 +112,6 @@ Inspect: ## Invariants - Managed paths stay under the configured workspace root. +- Artifact grouping comes from report definitions. - Metadata links artifacts produced for a run. - Prior lookup is based on structured metadata, not rendered report text.