13 KiB
Cleanup Roadmap
Purpose
This roadmap defines the staged implementation plan for the code quality and
deduplication cleanup identified in docs/roadmap/audit.md.
The target audience is an LLM coding agent. Implement each stage in order. Each stage should leave the repository buildable, tested, and behaviorally equivalent unless the stage explicitly removes unused public-facing surface.
Cleanup Principles
- Preserve public CLI syntax and output behavior unless a stage explicitly says otherwise.
- Preserve current managed artifact paths, report group names, RunID naming, and batch output copy filenames.
- Keep domain policy in
internal/report,internal/forecast,internal/briefing, andinternal/changes, not in CLI or adapter packages. - Keep external system details behind adapter boundaries.
- Prefer narrow, behavior-preserving helpers over broad framework-style abstractions.
- Add or update focused tests in the package that owns the behavior being cleaned up.
- Update non-roadmap documentation only after implemented behavior changes.
- Do not revert unrelated worktree changes.
Decisions Locked
- Add a narrow
internal/fileutilpackage for reusable atomic file helpers. - Remove the unused
reportsconfig surface instead of implementing config-driven output defaults. - Move report artifact group, batch copy filename, generated-report eligibility,
and compatible-prior policy into
internal/report. - Keep public CLI command names and command-to-report mapping in
internal/appfor now. - Do not include Weather API source-spec refactoring in the main cleanup sequence.
- Do not include broad briefing signal consolidation in the main cleanup sequence.
- Do not introduce Cobra, a workflow engine, plugin system, manifest/resume/progress system, logging subsystem, or global test framework.
- Treat the current unrelated deletion of
docs/roadmap/documentation.mdas out of scope for cleanup implementation. Do not restore or further modify it unless a later prompt explicitly asks for that.
Stage 1: Report Catalog And Path Policy
Goal: make internal/report the canonical source for report identity policy.
Implementation:
- Extend
report.Definitionwith:ArtifactGroup stringBatchOutputName stringGenerated boolCompatiblePriorIDs []report.ID
- Populate current exact values:
- Daily Today: artifact group
daily, batch outputdaily.md, generated true, compatible with Daily Today and Daily Tomorrow. - Daily Tomorrow: artifact group
daily, batch outputtomorrow.md, generated true, compatible with Daily Today and Daily Tomorrow. - 3-Day: artifact group
three-day, batch outputthree-day.md, generated true, compatible with 3-Day. - Weekend: artifact group
weekend, batch outputweekend.md, generated true, compatible with Weekend. - Storm: artifact group
storm, batch outputstorm.md, generated true, compatible with Storm.
- Daily Today: artifact group
- Add small methods or helpers in
internal/reportfor compatibility checks if direct slice checks would duplicate logic in callers. - Update
internal/stateto use the resolved report definition'sArtifactGroupinstead of privatereportGroup. - Update prior snapshot lookup to use
CompatiblePriorIDsinstead of a state-owned compatibility switch. - Update
internal/appto useBatchOutputNamedirectly and remove underscore-to-hyphen derivation. - Update generated-report eligibility checks to use
Definition.Generated. - Preserve all existing managed artifact paths and batch copy filenames.
Tests:
- Add or update report registry tests that assert each definition's
ArtifactGroup,BatchOutputName,Generated, andCompatiblePriorIDs. - Keep state path tests as path-contract tests and preserve their expected path strings.
- Keep app batch output tests and preserve expected filenames such as
tomorrow.md. - Run:
go test ./internal/report ./internal/state ./internal/app
Acceptance criteria:
- No report grouping switch remains in
internal/state. - No batch output filename derivation by underscore replacement remains in
internal/app. - Existing artifact paths and output copy names are unchanged.
Stage 2: Atomic Artifact Writes And Adapter Boundary
Goal: centralize durable write mechanics and remove adapter type leakage from state.
Implementation:
- Add
internal/fileutilwith:WriteFileAtomic(path string, data []byte) errorWriteJSONAtomic(path string, value any) errorCopyFileAtomic(source string, target string) error
- Implement helpers with the current behavior:
- create parent directories with
0o755; - create temp files in the target directory;
- write, close, rename, and defer temp-file cleanup;
- preserve useful path context in errors.
- create parent directories with
- Route these through
internal/fileutil:- state JSON writes;
- briefing package save;
- prompt input package save;
- Weather API bundle save;
- Scriptorium render result save if the helper remains;
- generated report extra-copy writes.
- Remove duplicate private atomic write helpers once callers are migrated.
- Remove
scriptorium.SaveRenderResultif no caller still needs it after the refactor. - Add
state.PreflightArtifactwith the same persisted JSON shape currently produced fromscriptorium.RenderResult. - Change
state.Store.SavePreflightto acceptstate.PreflightArtifact, not*scriptorium.RenderResult. - Convert
scriptorium.RenderResulttostate.PreflightArtifactininternal/appimmediately before saving preflight output. - Keep subprocess result construction and interpretation in
internal/adapters/scriptorium.
Tests:
- Add
internal/fileutiltests for parent directory creation, overwrite behavior, and cleanup/error behavior. - Keep state, app, adapter, briefing, and prompt input save tests.
- Run:
go test ./internal/fileutil ./internal/state ./internal/app ./internal/briefing ./internal/promptinput ./internal/adapters/weatherapi ./internal/adapters/scriptorium
Acceptance criteria:
- Durable JSON and Markdown copy writes share one implementation.
internal/stateno longer importsinternal/adapters/scriptorium.- Persisted preflight JSON remains shape-compatible with current artifacts.
Stage 3: Remove Unused Report Output Config
Goal: remove config fields that do not affect implemented behavior.
Implementation:
- Remove these unused config surfaces:
Config.ReportsReportOutputConfigLoadOptions.Output- default report output config values;
reports.output_dirvalidation;reports.pathsmap initialization.
- Update CLI generation config loading so
--outremains onlyGenerateRequest.OutputPath. - Keep
--outand--out-dirbehavior unchanged. - Update config tests and examples so they mention only implemented config fields.
- Update documentation in the same stage if non-roadmap docs still mention the
removed
reportsconfig surface.
Tests:
- Update config tests to assert config loading no longer has output-related config behavior.
- Keep CLI tests for
--outand--out-dir. - Run:
go test ./internal/config ./internal/cli ./internal/app
go run ./cmd/weatherreporter --help
Acceptance criteria:
- No
ReportOutputConfigorLoadOptions.Outputsymbols remain. - Example config files load through existing config tests.
- CLI output-copy behavior remains command request behavior, not config behavior.
Stage 4: Inspect Command And State Lookup Cleanup
Goal: remove repeated inspect scaffolding while preserving inspect output.
Implementation:
- Add a small inspect command table in
internal/cli. - Keep
inspect reportsseparate because it accepts--limitand does not require a RunID. - For run-specific inspect commands, centralize:
- command name;
- flag parsing;
- config loading;
- app handler invocation;
- JSON output writing.
- In
internal/app, add an unexported helper that loads the default store and metadata for a RunID. - Use the app helper for metadata, briefing, data-package, prior, and sources inspection.
- Collapse
writeRunSummaryandwriteJSONinto one JSON writer helper. - Preserve current JSON indentation and output shapes.
Tests:
- Keep
TestRunInspectGeneratedArtifacts. - Keep missing metadata tests.
- Add a table test proving run-specific inspect commands reject missing RunID
and accept
--config. - Run:
go test ./internal/cli ./internal/app ./internal/state
Acceptance criteria:
- Inspect command output is unchanged.
- Config loading remains consistent across inspect commands.
- Repeated store and metadata lookup code in app inspection paths is removed.
Stage 5: Small Adapter And Parser Deduplication
Goal: reduce low-risk repeated validation and execution logic.
Implementation:
- In
internal/adapters/scriptorium, add a private execution helper shared byRenderandRun. - Keep command-specific request validation and result structs.
- Preserve:
- argv order;
- result JSON fields;
- stdout/stderr capture;
- truncation fields;
- timeout behavior;
- nonzero exit behavior and error text.
- In storm CLI parsing, keep CLI-specific missing
--startand--enderrors. - After both storm bounds are present, delegate timestamp parsing and
end-after-start validation to
report.ParseStormPeriod. - Do not introduce a generic Weather API ingestion framework in this stage.
Tests:
- Keep or add tests for Scriptorium render/run nonzero exits.
- Keep storm tests for local timestamps, RFC3339 timestamps, missing flags, and invalid bounds.
- Run:
go test ./internal/adapters/scriptorium ./internal/cli ./internal/report
Acceptance criteria:
- Scriptorium render/run behavior remains byte-for-byte compatible where tests assert argv or output shape.
- Storm accepted timestamp formats and error behavior remain stable.
Stage 6: Legacy Wrapper And Test Helper Cleanup
Goal: remove stale generic-vs-daily duplication and reduce noisy test setup.
Implementation:
- Replace tests and internal callers of:
GenerateDailyBriefingGenerateDailyReportBuildDailyBriefingDailyBriefingRequestDailyReportRequest
- Use generic functions and types instead:
GenerateBriefingGenerateReportBuildBriefingBriefingRequestReportRequest
- Remove
FindPriorDailySnapshotfromstate.StoreandFilesystemStoreafter tests useFindPriorSnapshot. - Remove
dailyRecentChangesif no callers remain. - Add package-local test helpers in
internal/cliandinternal/appfor:- writing test config files;
- fake Scriptorium setup;
- representative Weather API test server setup;
- artifact glob and assertion helpers.
- Do not create a cross-package test framework.
Tests:
- Run:
go test ./internal/app ./internal/state ./internal/cli
go test ./internal/...
Acceptance criteria:
- Daily-specific app/state wrapper symbols listed above are gone.
- Daily behavior remains covered through generic report-generation paths.
- Test helper extraction does not reduce workflow coverage.
Stage 7: Documentation And Final Validation
Goal: align implemented documentation after cleanup.
Implementation:
- Update non-roadmap docs only for behavior or internal contracts actually changed by stages 1 through 6.
- Inspect and update, as needed:
docs/config.mddocs/internal/state.mddocs/internal/scriptorium-adapter.mddocs/internal/report-registry.mddocs/policy/development.md- relevant files under
docs/integrations/
- Keep future or deferred cleanup ideas only under
docs/roadmap/. - Do not document deferred Weather API source-spec or briefing signal refactors as implemented.
Validation:
go test ./...
go run ./cmd/weatherreporter --help
git diff --check
Run stale-symbol searches:
rg -n "ReportOutputConfig|LoadOptions\\.Output|FindPriorDailySnapshot|GenerateDailyReport|DailyReportRequest|SaveRenderResult" .
Review any matches manually. Matches under roadmap files may be acceptable because they describe planned or completed cleanup work.
Acceptance criteria:
- Non-roadmap docs describe only implemented behavior.
- Config examples still load through config tests.
- CLI help remains accurate.
- No removed production symbols remain outside tests or roadmap references.
Deferred Refactors
Do not include these in the main cleanup sequence:
- Weather API optional-source spec/helper refactor.
- Broad briefing weather-signal consolidation.
- Generic workflow engine.
- Plugin architecture.
- Cobra migration.
- Manifest/resume/progress system.
- Global test helper package.
- Logging subsystem.
These can be revisited only when new source types, report types, or operational requirements make the duplication materially more expensive.
Global Validation Checklist
Run focused tests after each stage, then run full validation after Stage 7.
Required final checks:
go test ./...
go run ./cmd/weatherreporter --help
git diff --check
Required manual checks:
- Public CLI syntax remains stable.
- Managed artifact paths remain stable.
- Batch output copy filenames remain stable.
scriptoriumargv construction remains stable.- Weather API request query behavior remains stable.
- Removed config fields are also removed from current-behavior docs and examples.
- Roadmap files are the only docs that describe deferred cleanup work.
- No unrelated worktree changes are reverted.