YAML Configuration Refactor
This commit is contained in:
@@ -0,0 +1,325 @@
|
||||
Refactor toolkit configuration from JSON to YAML only.
|
||||
|
||||
# Context
|
||||
|
||||
Repositories currently use `config.json` for human-authored toolkit configuration.
|
||||
|
||||
However, JSON is also used heavily for generated datasets, manifests, caches, and machine-readable artifacts. This makes repository configuration harder to distinguish from generated data.
|
||||
|
||||
# Goal
|
||||
|
||||
Make YAML the source of truth for all human-authored repository configuration.
|
||||
|
||||
JSON should remain valid for generated data artifacts, but not as the preferred format for repository configuration.
|
||||
|
||||
# Core requirements
|
||||
|
||||
- Replace `config.json` with `config.yaml`.
|
||||
- Load repository configuration from YAML.
|
||||
- Treat YAML as the canonical source-of-truth.
|
||||
- Keep generated datasets, manifests, caches, and machine-readable outputs as JSON.
|
||||
- Do not move dataset artifacts to YAML.
|
||||
- Do not hardcode configuration behavior in code if it can reasonably be expressed in config.
|
||||
- The toolkit should be deterministic.
|
||||
|
||||
# Configuration philosophy
|
||||
|
||||
Configuration should control repository behavior.
|
||||
|
||||
Avoid hardcoded assumptions for:
|
||||
|
||||
- module names
|
||||
- resrefs
|
||||
- paths
|
||||
- HAK names
|
||||
- HAK priority
|
||||
- HAK split behavior
|
||||
- HAK size limits
|
||||
- include/exclude globs
|
||||
- optional HAKs
|
||||
- music prefixes
|
||||
- extract rules
|
||||
- topdata paths/packages
|
||||
- autogen producers
|
||||
- autogen consumers
|
||||
- manifest names
|
||||
- cache names
|
||||
- release tags
|
||||
- dataset names
|
||||
- derivation rules
|
||||
|
||||
If behavior varies by repository, it belongs in YAML.
|
||||
|
||||
# Example target config
|
||||
|
||||
Convert this kind of repository config:
|
||||
|
||||
```json
|
||||
{
|
||||
"module": {
|
||||
"name": "Shadows Over Westgate",
|
||||
"resref": "sow_module",
|
||||
"description": "Shadows Over Westgate asset pipeline.",
|
||||
"hak_order": ["sow_top", "group:sow_over", "group:sow_core"]
|
||||
},
|
||||
"paths": {
|
||||
"assets": "content",
|
||||
"build": "build"
|
||||
},
|
||||
"music": {
|
||||
"prefixes": {
|
||||
"envi/music/westgate": "mus_wg_"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Into:
|
||||
|
||||
```yaml
|
||||
module:
|
||||
name: Shadows Over Westgate
|
||||
resref: sow_module
|
||||
description: Shadows Over Westgate asset pipeline.
|
||||
hak_order:
|
||||
- sow_top
|
||||
- group:sow_over
|
||||
- group:sow_core
|
||||
|
||||
paths:
|
||||
assets: content
|
||||
build: build
|
||||
|
||||
music:
|
||||
prefixes:
|
||||
envi/music/westgate: mus_wg_
|
||||
```
|
||||
|
||||
# Implementation requirements
|
||||
|
||||
- Add YAML config loading.
|
||||
- Prefer `config.yaml`.
|
||||
- Optionally accept `config.yml`.
|
||||
- Remove reliance on `config.json` for repository configuration.
|
||||
- If `config.json` support is kept temporarily, mark it as legacy/deprecated.
|
||||
- If both YAML and JSON configs exist, YAML must win.
|
||||
- Emit a clear warning when legacy JSON config is used.
|
||||
- Preserve existing schema semantics.
|
||||
- Preserve existing defaults only where they are intentional toolkit defaults.
|
||||
- Move repository-specific defaults into YAML.
|
||||
- Keep validation strict.
|
||||
- Fail clearly on malformed YAML or unknown required fields.
|
||||
- Preserve deterministic ordering where configs are serialized, logged, or normalized.
|
||||
|
||||
# Validation requirements
|
||||
|
||||
- Validate YAML against the same schema expectations currently used for JSON.
|
||||
- Ensure required sections are present when needed.
|
||||
- Ensure paths are strings.
|
||||
- Ensure HAK entries have required fields.
|
||||
- Ensure autogen producers/consumers have valid ids, roots, includes, derive rules, and manifest config.
|
||||
- Ensure music prefixes are deterministic and unambiguous.
|
||||
- Ensure duplicate HAK names, producer ids, consumer ids, or dataset ids are rejected.
|
||||
- Ensure priority ordering is deterministic even when priorities match.
|
||||
- Ensure include glob ordering is stable.
|
||||
|
||||
# Migration requirements
|
||||
|
||||
- Convert existing `config.json` files to `config.yaml`.
|
||||
- Preserve all existing values exactly unless a change is intentional.
|
||||
- Update code paths, scripts, tests, and documentation to reference YAML.
|
||||
- Add or update tests for:
|
||||
- loading `config.yaml`
|
||||
- loading `config.yml`
|
||||
- legacy `config.json` fallback, if retained
|
||||
- YAML precedence over JSON
|
||||
- validation failures
|
||||
- deterministic ordering
|
||||
- representative configs matching the current repository examples
|
||||
|
||||
- Do not change generated artifact formats unless explicitly required.
|
||||
|
||||
# Generated artifacts
|
||||
|
||||
Keep these as JSON unless there is a separate reason to change them:
|
||||
|
||||
- datasets
|
||||
- manifests
|
||||
- caches
|
||||
- credits output
|
||||
- build summaries
|
||||
- machine-readable reports
|
||||
|
||||
Rationale:
|
||||
|
||||
- YAML is for human-authored repository configuration.
|
||||
- JSON is for generated or machine-readable data.
|
||||
|
||||
# Deliverables
|
||||
|
||||
1. YAML config loader design
|
||||
2. Updated config schema
|
||||
3. JSON-to-YAML migration plan
|
||||
4. Converted example configs
|
||||
5. Legacy JSON handling policy
|
||||
6. Validation updates
|
||||
7. Test plan
|
||||
8. Documentation updates
|
||||
9. List of code-level assumptions that should be moved into config
|
||||
10. Before/after examples
|
||||
|
||||
# Initial project-needs analysis
|
||||
|
||||
## Current state
|
||||
|
||||
- Main repository configuration is currently modeled by `internal/project.Config`.
|
||||
- The toolkit currently discovers and loads `nwn-tool.json`, not `config.json`.
|
||||
- Config loading is centralized in `internal/project.FindRoot` and `internal/project.Load`.
|
||||
- Config structs currently have JSON tags only.
|
||||
- There is no YAML dependency in `go.mod`.
|
||||
- Generated and machine-readable JSON is widespread and should remain JSON:
|
||||
- build HAK manifest: `build/haks.json`
|
||||
- topdata authored/generated datasets
|
||||
- topdata template conversion metadata: `topdata/templates/config.json`
|
||||
- topdata wiki state and deploy manifests
|
||||
- autogen manifest caches under `.cache`
|
||||
- credits inventory output
|
||||
- GFF canonical JSON documents
|
||||
|
||||
## Naming decision needed
|
||||
|
||||
The contract says to replace `config.json` with `config.yaml`, but the current toolkit root config file is `nwn-tool.json`.
|
||||
|
||||
Plan assumption:
|
||||
|
||||
- Treat `nwn-tool.yaml` as the direct YAML replacement for the existing root config.
|
||||
- Optionally accept `nwn-tool.yml`.
|
||||
- Keep temporary legacy fallback to `nwn-tool.json` with a warning.
|
||||
- Do not rename generated or nested metadata files unless they are confirmed to be human-authored repository root configuration.
|
||||
|
||||
If the intended final filename is instead literally `config.yaml`, update the loader plan before implementation.
|
||||
|
||||
## Code areas affected
|
||||
|
||||
- `internal/project/project.go`
|
||||
- config file discovery
|
||||
- YAML/legacy JSON loading
|
||||
- schema tags and strict decode behavior
|
||||
- validation for duplicate names, path fields, include ordering, and required config sections
|
||||
- currently hardcoded defaults such as `build`, `.cache`, `sow_top.hak`, `sow_tlk.tlk`, and `haks.json`
|
||||
- `internal/app/app.go`
|
||||
- project-load diagnostics and logging so commands clearly state which config file was loaded
|
||||
- user-facing descriptions that mention hardcoded paths or outputs
|
||||
- `internal/pipeline/*`
|
||||
- HAK ordering, manifest naming, music cache/credits paths, and music prefix behavior
|
||||
- generated JSON outputs must remain JSON
|
||||
- `internal/topdata/*`
|
||||
- package names, cache names, released manifest metadata, wiki state paths, and autogen consumer cache paths
|
||||
- topdata datasets and manifests must remain JSON
|
||||
- `internal/validator/*`
|
||||
- validation tests and duplicate/ordering rules
|
||||
- potential config control for built-in script prefixes if repository-specific
|
||||
- Tests under `internal/**/*_test.go`
|
||||
- many tests currently write `nwn-tool.json`; representative tests should move to YAML with targeted legacy JSON coverage retained
|
||||
- `README.md` and workflow docs
|
||||
- update root configuration references to YAML
|
||||
- explicitly document JSON artifacts that remain JSON
|
||||
|
||||
## Hardcoded assumptions to audit for config ownership
|
||||
|
||||
Move to YAML if repository-specific:
|
||||
|
||||
- root config filename policy and migration behavior
|
||||
- build output directory and HAK manifest filename
|
||||
- topdata build/cache paths
|
||||
- topdata package HAK/TLK filenames and derived TLK behavior
|
||||
- autogen release tags, asset names, cache names, producers, consumers, roots, includes, modes, and derive rules
|
||||
- released parts manifest repository/server metadata when not a universal toolkit default
|
||||
- HAK names, priorities, split behavior, optional flags, include globs, and module HAK order
|
||||
- music source roots, prefixes, credit overlay names, generated credits paths, and music stem constraints where repository-specific
|
||||
- source/asset include extension sets where repository-specific
|
||||
- validator script-prefix exclusions if they vary by repository
|
||||
|
||||
Keep in code if toolkit-intrinsic:
|
||||
|
||||
- generated JSON encoding for datasets, manifests, caches, GFF documents, and reports
|
||||
- NWN resource format constraints such as resref length limits
|
||||
- deterministic sort rules after config values are loaded
|
||||
- supported autogen derive kinds and consumer modes unless extensibility is implemented
|
||||
|
||||
# Implementation plan
|
||||
|
||||
## Phase 1: Loader and schema foundation
|
||||
|
||||
- Add YAML parsing dependency, likely `gopkg.in/yaml.v3`.
|
||||
- Add YAML tags to all config structs while preserving JSON tags for legacy decode.
|
||||
- Introduce config discovery order:
|
||||
1. `nwn-tool.yaml`
|
||||
2. `nwn-tool.yml`
|
||||
3. legacy `nwn-tool.json`
|
||||
- Return loaded config metadata from `project.Load`, including path, format, and legacy flag.
|
||||
- Make YAML win when both YAML and JSON are present.
|
||||
- Emit a clear legacy warning when `nwn-tool.json` is used.
|
||||
- Emit/log the selected config path for normal command execution.
|
||||
- Fail clearly for malformed YAML and unknown fields.
|
||||
|
||||
## Phase 2: Validation and determinism
|
||||
|
||||
- Preserve existing schema semantics while tightening validation.
|
||||
- Validate required module fields and path field types.
|
||||
- Reject duplicate HAK names, autogen producer IDs, autogen consumer IDs, and dataset IDs where represented in root config.
|
||||
- Validate HAK entries for name, priority, max bytes, include globs, and output-safe names.
|
||||
- Validate autogen manifest filenames and deterministic producer/consumer references.
|
||||
- Validate music prefixes for ambiguous duplicate normalized roots.
|
||||
- Ensure include globs and map-derived outputs are sorted before use where order matters.
|
||||
- Add deterministic tie-breakers for HAK priority sorting.
|
||||
|
||||
## Phase 3: Move repository-specific defaults into YAML
|
||||
|
||||
- Keep only intentional toolkit defaults in `defaultConfig`.
|
||||
- Move Shadows Over Westgate-specific defaults into repo YAML:
|
||||
- top package names
|
||||
- topdata cache/build paths
|
||||
- autogen manifest metadata
|
||||
- music prefixes
|
||||
- HAK ordering and include globs
|
||||
- Add config fields where needed before removing hardcoded assumptions.
|
||||
- Leave generated artifact paths as JSON outputs unless the path itself must be configurable.
|
||||
|
||||
## Phase 4: Migration
|
||||
|
||||
- Convert consumer root configs from `nwn-tool.json` to `nwn-tool.yaml`.
|
||||
- Preserve existing values exactly unless a separate behavior change is documented.
|
||||
- Keep `topdata/templates/config.json` unchanged for now because it is topdata conversion metadata, not root repository configuration.
|
||||
- Keep generated datasets, manifests, caches, credits inventory, and GFF JSON unchanged.
|
||||
- Add before/after examples for root config migration.
|
||||
|
||||
## Phase 5: Tests
|
||||
|
||||
- Add focused loader tests for:
|
||||
- `nwn-tool.yaml`
|
||||
- `nwn-tool.yml`
|
||||
- legacy `nwn-tool.json`
|
||||
- YAML precedence over JSON
|
||||
- malformed YAML
|
||||
- unknown YAML fields
|
||||
- Update representative build, validator, pipeline, topdata, and app tests to use YAML root config.
|
||||
- Keep targeted JSON tests only for legacy fallback and generated artifact behavior.
|
||||
- Add validation tests for duplicates, path type failures, deterministic HAK ordering, and ambiguous music prefixes.
|
||||
- Run `go test ./...`.
|
||||
|
||||
## Phase 6: Documentation
|
||||
|
||||
- Update `README.md` repository layout and consumer instructions to reference `nwn-tool.yaml`.
|
||||
- Document legacy JSON fallback and planned removal policy.
|
||||
- Document which JSON files remain intentional generated or machine-readable artifacts.
|
||||
- Document config precedence and command log behavior.
|
||||
|
||||
# Acceptance criteria
|
||||
|
||||
- A repository can build from the chosen YAML root config file (`nwn-tool.yaml` under the current plan, or `config.yaml` if the naming decision changes).
|
||||
- Existing generated JSON datasets and manifests still work.
|
||||
- No repository-specific behavior remains hardcoded if it can be expressed in YAML.
|
||||
- Builds remain deterministic.
|
||||
- Existing behavior is preserved after migration.
|
||||
- Logs clearly state which config file was loaded.
|
||||
Reference in New Issue
Block a user