724 lines
24 KiB
Markdown
724 lines
24 KiB
Markdown
# Model Compilation Build-Time Contract
|
||
|
||
## Status Snapshot
|
||
|
||
Current state as of 2026-05-13:
|
||
|
||
- This contract is still outstanding.
|
||
- `build-haks` does not currently compile authored ASCII `.mdl` files into
|
||
binary build artifacts.
|
||
- Toolkit validation and extraction understand `.mdl`, but there is no
|
||
config-backed build-time model compiler pipeline in `internal/pipeline/`.
|
||
|
||
Open work remains exactly in the areas this contract describes:
|
||
|
||
- schema and validation for `models.compile.*`
|
||
- compiler/tool resolution and staging
|
||
- generated-asset overlay integration in HAK builds
|
||
- cache/reuse semantics and regression coverage
|
||
|
||
## Scope
|
||
|
||
Expand the toolkit so authored ASCII Neverwinter Nights `.mdl` assets can be compiled into binary `.mdl` build artifacts during `sow-toolkit build-haks` without changing the authored source tree.
|
||
|
||
This contract covers:
|
||
|
||
- `toolkit/` as the implementation owner
|
||
- `sow-assets/` as the primary consumer repository
|
||
- any future consumer repo that packages NWN model assets through the same HAK build pipeline
|
||
|
||
This contract does not cover:
|
||
|
||
- replacing authored ASCII `.mdl` files in source control
|
||
- introducing a separate standalone shell-only build system as the primary path
|
||
- downloading or redistributing copyrighted NWN game data
|
||
- building an in-game runtime compiler workflow
|
||
|
||
## Goal
|
||
|
||
Make model compilation a first-class, deterministic, configurable build stage in the Go toolkit so generated HAKs contain compiled binary models while authored repositories continue to keep ASCII `.mdl` files as source of truth.
|
||
|
||
## Why This Exists
|
||
|
||
Repo-local context already shows that ASCII `.mdl` files are an intentional part of authored asset workflows:
|
||
|
||
- validation reports ASCII/decompiled models as informational, not erroneous
|
||
- topdata autogen manifest generation scans authored `.mdl` paths directly
|
||
- part discovery derives IDs from authored `.mdl` filenames
|
||
- HAK building already has other generated-asset stages such as NWScript and music conversion
|
||
|
||
Upstream NWN documentation also supports compiling before release:
|
||
|
||
- `nwn.wiki` documents that ASCII models are slower because the game compiles them at load time and recommends shipping compiled models
|
||
- `nwnmdlcomp` usage docs confirm ASCII-to-binary compilation as a standard flow
|
||
- community documentation shows `nwnmdlcomp.exe` expects old NWN registry/data layout and may need a 1.69-era data root
|
||
|
||
Therefore the correct implementation is not “replace asset scanning with binary models everywhere”. The correct implementation is:
|
||
|
||
1. keep authored ASCII `.mdl` in `paths.assets`
|
||
2. preserve current validation and manifest derivation behavior against source
|
||
3. compile only the build payload that becomes generated HAK content
|
||
|
||
## Ownership Split
|
||
|
||
- `toolkit/`
|
||
- owns config schema, validation, discovery, cache policy, build staging, and HAK integration
|
||
- owns Wine execution and NWN data preparation logic
|
||
- owns tests and user-facing CLI behavior
|
||
- `sow-assets/`
|
||
- owns opting into the feature through `nwn-tool.yaml`
|
||
- owns providing local tool binaries and any fake/minimal NWN data tree it wants to use
|
||
- owns wrapper scripts and CI invocation details
|
||
- `sow-module/`
|
||
- is an indirect consumer only when it consumes generated HAKs
|
||
- must not need authored-source changes for this feature to work
|
||
|
||
## Current Project-Needs Analysis
|
||
|
||
## Existing architecture
|
||
|
||
Current HAK packaging is Go-native and centered on:
|
||
|
||
- `cmd/nwn-tool/main.go`
|
||
- `internal/app/app.go`
|
||
- `internal/pipeline/build.go`
|
||
- `internal/project/*`
|
||
- `internal/validator/*`
|
||
|
||
`build-haks` already does all asset discovery, planning, manifest writing, HAK reuse, and generated-asset preparation inside the toolkit. Adding model compilation as a disconnected shell script would duplicate the existing build graph and create drift.
|
||
|
||
## Existing relevant behavior
|
||
|
||
- `project.AssetExtensions` already includes `.mdl`
|
||
- `validator.ValidateProject` detects text `.mdl` and reports them via `Report.DecompiledModels`
|
||
- `emitValidatorReport` already surfaces that information in CLI output
|
||
- `collectAssetResources` packages raw files from `paths.assets` directly into HAK resources
|
||
- `BuildHAKs` already supports generated assets and temporary staging through the music pipeline
|
||
- script compilation already establishes a precedent for:
|
||
- config-backed tool resolution
|
||
- environment discovery
|
||
- cache directories under `.cache`
|
||
- build-time generated resources that do not modify authored sources
|
||
|
||
## Constraints the plan must preserve
|
||
|
||
- authored `.mdl` files remain canonical inputs
|
||
- autogen and topdata logic must continue to see source `.mdl` paths
|
||
- validation must still be able to detect ASCII source models
|
||
- HAK duplicate detection and manifest generation must remain deterministic
|
||
- build output reuse must not falsely reuse HAKs built from stale compiled model content
|
||
- consumer repos must be able to opt out cleanly
|
||
|
||
## Architecture Decision
|
||
|
||
Implement model compilation as a generated-asset overlay inside the existing HAK build pipeline, not as a separate top-level shell build.
|
||
|
||
That means:
|
||
|
||
- source scanning still indexes authored `.mdl`
|
||
- a model preparation stage produces compiled build artifacts in cache/staging
|
||
- `collectAssetResources` substitutes compiled `.mdl` bytes for eligible source models during HAK packaging
|
||
- non-model assets continue to flow unchanged
|
||
- the written HAK manifest still records the authored relative asset path, not a cache path
|
||
|
||
This mirrors the existing music pipeline more than the script pipeline:
|
||
|
||
- source asset exists in `paths.assets`
|
||
- generated build artifact lives in cache/staging
|
||
- HAK includes the generated bytes under the original logical resource name
|
||
|
||
## Non-Goals
|
||
|
||
- no automatic decompilation
|
||
- no mutation of files under `paths.assets`
|
||
- no requirement to compile every `.mdl` in every repo by default
|
||
- no requirement to support Windows-only shell wrappers as the primary interface
|
||
- no requirement to support arbitrary model compilers on day one beyond `nwnmdlcomp.exe` via Wine
|
||
- no attempt to “fix” malformed source models automatically
|
||
|
||
## Config Contract
|
||
|
||
Add a new top-level config section:
|
||
|
||
```yaml
|
||
models:
|
||
compile:
|
||
enabled: true
|
||
source_extensions: [.mdl]
|
||
include: []
|
||
exclude: []
|
||
cache: "{paths.cache}/models"
|
||
compiler:
|
||
path: ""
|
||
env:
|
||
path: SOW_NWN_MODEL_COMPILER
|
||
wine: SOW_NWN_WINE
|
||
winepath: SOW_NWN_WINEPATH
|
||
prefix: SOW_NWN_WINEPREFIX
|
||
nwn_data: [SOW_NWN_MODEL_DATA, SOW_NWN_ROOT, NWN_ROOT]
|
||
search:
|
||
- "{paths.tools}/nwnmdlcomp/nwnmdlcomp.exe"
|
||
- "{paths.tools}/nwnmdlcomp.exe"
|
||
runtime:
|
||
mode: wine
|
||
jobs: 1
|
||
force: false
|
||
setup_registry: true
|
||
compiler_cwd: "{paths.tools}/nwnmdlcomp"
|
||
data:
|
||
root: ""
|
||
require_keys: [chitin.key, nwn_base.key, data/nwn_base.key]
|
||
writable_aliases: [chitin.key, nwn_base.key]
|
||
policy:
|
||
compile_ascii_only: true
|
||
preserve_binary_sources: true
|
||
fail_on_missing_output: true
|
||
fail_on_zero_byte_output: true
|
||
fail_on_warning: false
|
||
```
|
||
|
||
## Config design rules
|
||
|
||
- `models.compile.enabled` must default to `false`
|
||
- the feature must be opt-in
|
||
- config must be repository-driven, not hardcoded per consumer
|
||
- search/discovery semantics should match `scripts.compiler` where practical
|
||
- path templating should reuse the existing effective config path expansion model
|
||
- include/exclude filters apply to asset-relative paths under `paths.assets`
|
||
- default jobs should be serial unless parallel execution is explicitly enabled
|
||
|
||
## Environment precedence
|
||
|
||
Use this precedence for the compiler executable:
|
||
|
||
1. `models.compile.compiler.path`
|
||
2. env var named by `models.compile.compiler.env.path`
|
||
3. configured search paths
|
||
|
||
Use this precedence for NWN data root:
|
||
|
||
1. `models.compile.data.root`
|
||
2. env vars listed in `models.compile.compiler.env.nwn_data`
|
||
3. no implicit auto-discovery unless explicitly implemented and documented
|
||
|
||
Wine tools should resolve as:
|
||
|
||
1. env override for `wine`
|
||
2. `PATH:wine`
|
||
|
||
and:
|
||
|
||
1. env override for `winepath`
|
||
2. `PATH:winepath`
|
||
|
||
Do not silently guess a fake NWN data tree.
|
||
|
||
## Build Contract
|
||
|
||
## Eligibility rules
|
||
|
||
A model is eligible for build-time compilation when all of the following are true:
|
||
|
||
- asset extension is `.mdl`
|
||
- `models.compile.enabled` is true
|
||
- path passes include/exclude filters
|
||
- file is detected as ASCII when `compile_ascii_only` is true
|
||
|
||
If a `.mdl` file is already binary and `preserve_binary_sources` is true:
|
||
|
||
- do not recompile it
|
||
- package it as-is
|
||
- optionally log a verbose skip reason
|
||
|
||
## Integration point
|
||
|
||
Insert model preparation into `planOrBuildHAKs` before `collectAssetResources` finalizes HAK resource content, alongside other generated-asset preparation.
|
||
|
||
Expected flow:
|
||
|
||
1. validate project
|
||
2. prepare music assets if enabled
|
||
3. prepare compiled model assets if enabled
|
||
4. collect asset resources using source inventory plus prepared overlays
|
||
5. plan/write HAKs as today
|
||
|
||
## Prepared asset representation
|
||
|
||
Introduce a prepared-model result similar in spirit to `preparedMusicAssets`, for example:
|
||
|
||
- generated assets keyed by original asset-relative path
|
||
- skipped source-relative paths
|
||
- summary counts and loggable actions
|
||
- cleanup hook for temporary staging if needed
|
||
|
||
The HAK layer should continue to see:
|
||
|
||
- resource name from the original source path stem
|
||
- resource type `mdl`
|
||
- relative manifest path equal to the original source path
|
||
|
||
Only the file bytes should differ.
|
||
|
||
## Cache and staging contract
|
||
|
||
Compiled models are generated artifacts and must live outside the authored asset tree.
|
||
|
||
Default cache root:
|
||
|
||
```text
|
||
{paths.cache}/models
|
||
```
|
||
|
||
Suggested cache layout:
|
||
|
||
```text
|
||
.cache/models/
|
||
compiled/<asset-relative-path>.mdl
|
||
logs/<asset-relative-path>.log
|
||
metadata.json
|
||
wine-prefix/ # only if the repo chooses a toolkit-managed prefix
|
||
nwn-data-links/ # only if alias files/symlinks are staged
|
||
```
|
||
|
||
The exact layout may differ, but it must support:
|
||
|
||
- deterministic mapping from source asset path to compiled output path
|
||
- per-model logging for failures
|
||
- incremental stale detection
|
||
- cleanup without touching authored content
|
||
|
||
## Incremental contract
|
||
|
||
The plan must support incremental recompilation for persistent cache dirs.
|
||
|
||
At minimum, recompile when any of these change:
|
||
|
||
- source file content hash changed
|
||
- source file modtime is newer than compiled output
|
||
- compiler executable path or content fingerprint changed
|
||
- NWN data root fingerprint changed if the implementation tracks it
|
||
- relevant config changed
|
||
- `--force` or config `force: true` is active
|
||
- compiled output is missing or zero bytes
|
||
|
||
Recommended metadata key:
|
||
|
||
- source asset relative path
|
||
- source SHA-256
|
||
- output SHA-256
|
||
- compiler path
|
||
- compiler binary mtime or hash
|
||
- NWN data root path
|
||
- build config fingerprint
|
||
- compiled timestamp
|
||
|
||
If metadata is unavailable or invalid, fail open to recompilation, not reuse.
|
||
|
||
## NWN Data Contract
|
||
|
||
`nwnmdlcomp.exe` requires a classic NWN data/registry environment.
|
||
|
||
The implementation must:
|
||
|
||
- validate the configured NWN data root exists
|
||
- require at least one of:
|
||
- `chitin.key`
|
||
- `nwn_base.key`
|
||
- `data/nwn_base.key`
|
||
- never download game data
|
||
- never synthesize copyrighted content
|
||
|
||
If only `data/nwn_base.key` exists, the implementation may create a staged alias view for the compiler by:
|
||
|
||
- symlinking inside a cache-owned staging dir, or
|
||
- copying just the key file names into a cache-owned staging dir when symlinks are unavailable
|
||
|
||
Do not mutate the user’s real install directory unless they explicitly pointed the config at a writable fake data tree and the implementation clearly documents that behavior.
|
||
|
||
## Wine Registry Contract
|
||
|
||
When `runtime.setup_registry` is enabled, prepare the Wine registry keys needed by `nwnmdlcomp.exe`:
|
||
|
||
```text
|
||
HKLM\Software\WOW6432Node\BioWare\NWN\Neverwinter
|
||
Location = <wine path>
|
||
Path = <wine path>
|
||
Version = 1.69
|
||
GUID = 00000000-0000-0000-0000-000000000000
|
||
Language = 0
|
||
```
|
||
|
||
Implementation rules:
|
||
|
||
- convert Linux paths with `winepath -w`
|
||
- target the Wine prefix selected by config/env
|
||
- make registry setup idempotent
|
||
- separate “prepare registry” failure messages from “compile model” failures
|
||
|
||
The implementation may either:
|
||
|
||
- manage a dedicated toolkit prefix, or
|
||
- use a user-provided existing prefix
|
||
|
||
The contract should prefer an isolated prefix to avoid polluting unrelated Wine state.
|
||
|
||
## Compiler Invocation Contract
|
||
|
||
Primary supported compiler:
|
||
|
||
- `nwnmdlcomp.exe`
|
||
|
||
Expected invocation shape:
|
||
|
||
```bash
|
||
WINEDEBUG=-all wine "$COMPILER" -c "$INPUT_WIN" "$OUTPUT_WIN" -e
|
||
```
|
||
|
||
Implementation requirements:
|
||
|
||
- invoke through `os/exec`, not shell string concatenation
|
||
- convert input/output paths with `winepath -w`
|
||
- allow compiler working directory configuration if supermodel resolution or relative lookup requires it
|
||
- capture combined stdout/stderr per compile attempt
|
||
|
||
## Supermodel and sibling dependency considerations
|
||
|
||
The plan must explicitly account for model compilation not being a pure single-file transform.
|
||
|
||
Potential dependencies include:
|
||
|
||
- `setsupermodel` references
|
||
- sibling helper models in the same asset family
|
||
- textures or material references that may not block compilation but do matter for diagnostics
|
||
|
||
Minimum contract:
|
||
|
||
- compile against a staging layout that preserves original relative structure
|
||
- ensure each model’s directory context exists in staging
|
||
- document that some supermodel cases may require staging additional authored `.mdl` siblings into the compiler-visible workspace
|
||
|
||
Do not assume “compile one file in isolation” is always sufficient.
|
||
|
||
## Staging strategy
|
||
|
||
Preferred strategy:
|
||
|
||
1. keep source inventory rooted in `paths.assets`
|
||
2. materialize a compiler workspace under cache that mirrors required relative directories for eligible `.mdl`
|
||
3. compile outputs into a sibling compiled tree
|
||
4. package compiled output bytes while preserving source-relative logical names
|
||
|
||
This avoids:
|
||
|
||
- polluting source trees
|
||
- output collisions between models with the same basename in different folders
|
||
- broken relative assumptions inside asset packs
|
||
|
||
## Logging Contract
|
||
|
||
Progress output should fit existing `ProgressFunc` style.
|
||
|
||
Minimum messages:
|
||
|
||
- `Preparing model compiler...`
|
||
- `Preparing model compilation workspace...`
|
||
- `Compiling model 12/324: part/belt/pfa0_belt018.mdl`
|
||
- `Reusing compiled model: vfxs/head_accessories/hfx_bandana.mdl`
|
||
- `Skipping binary model source: creatures/foo.mdl`
|
||
- `FAILED model compile: placeables/broken_model.mdl`
|
||
|
||
At summary level, surface:
|
||
|
||
- models considered
|
||
- compiled
|
||
- reused
|
||
- skipped binary
|
||
- skipped filtered
|
||
- failed
|
||
|
||
Verbose/debug output may include:
|
||
|
||
- chosen compiler path
|
||
- chosen Wine/Wineprefix/Winepath tools
|
||
- chosen NWN data root
|
||
- per-model log file location
|
||
|
||
## Error Handling Contract
|
||
|
||
Model compilation is a build-critical stage once enabled.
|
||
|
||
The build must fail when an eligible model compile:
|
||
|
||
- exits non-zero
|
||
- does not produce the expected output file
|
||
- produces a zero-byte output file
|
||
- cannot be staged or fingerprinted
|
||
|
||
Warnings from the compiler do not fail the build unless future config enables that policy.
|
||
|
||
Failure output must include:
|
||
|
||
- original source-relative asset path
|
||
- compiler command context sufficient for debugging
|
||
- log file path if written
|
||
|
||
At the end of a failed run, include a concise failed-path summary.
|
||
|
||
## CLI Contract
|
||
|
||
The canonical user-facing entrypoint remains:
|
||
|
||
```bash
|
||
sow-toolkit build-haks
|
||
```
|
||
|
||
Add targeted flags only if they materially improve operability and match existing CLI patterns. Recommended flags:
|
||
|
||
- `build-haks --force-models`
|
||
- `build-haks --skip-models`
|
||
- `build-haks --model <glob-or-prefix>` optional, only if there is a real use case for scoped rebuilds
|
||
|
||
Flag rules:
|
||
|
||
- flags override config for the current invocation only
|
||
- `--skip-models` must bypass model preparation even if config is enabled
|
||
- `--force-models` must invalidate incremental reuse for model outputs only
|
||
|
||
Do not introduce a parallel standalone command as the only way to use the feature. A helper/diagnostic subcommand is acceptable later, but build-haks must own the real integration.
|
||
|
||
## Validation Contract
|
||
|
||
Current validation already reports authored ASCII `.mdl` as informational. That behavior should remain, but the plan should extend validation to cover model compilation readiness when the feature is enabled.
|
||
|
||
Recommended validation additions:
|
||
|
||
- compiler path resolves or search candidates exist
|
||
- `wine` and `winepath` are resolvable on non-Windows platforms when mode is `wine`
|
||
- NWN data root exists and has required keys
|
||
- cache path is safe and repo-relative unless explicitly documented otherwise
|
||
- include/exclude glob config is well-formed
|
||
- jobs is >= 1
|
||
|
||
Validation severity:
|
||
|
||
- config/discovery failures that make enabled compilation impossible should be errors
|
||
- authored ASCII `.mdl` detection remains info
|
||
- binary `.mdl` sources alongside enabled compilation are not errors
|
||
|
||
## Manifest And Reuse Contract
|
||
|
||
Generated `haks.json` must continue to describe authored asset-relative paths, not cache file paths.
|
||
|
||
HAK reuse logic must account for compiled model output bytes. Reuse must not mistakenly treat an unchanged authored path as unchanged content if the compiled artifact changed.
|
||
|
||
That means one of:
|
||
|
||
- the existing asset `ContentID` for `.mdl` must reflect compiled output hash when compilation is enabled, or
|
||
- chunk hashing must incorporate the prepared compiled output fingerprint
|
||
|
||
Without this, stale HAK reuse would be incorrect.
|
||
|
||
## Parallelism Contract
|
||
|
||
Support configurable parallel compilation with conservative defaults.
|
||
|
||
Requirements:
|
||
|
||
- default jobs is `1`
|
||
- jobs > 1 must not corrupt outputs or logs
|
||
- each compile must write to a unique output path and unique log path
|
||
- shared registry/prefix setup must happen before parallel work or under safe synchronization
|
||
|
||
If `nwnmdlcomp.exe` or Wine proves unstable under parallel execution:
|
||
|
||
- keep serial default
|
||
- document the risk
|
||
- allow opting into higher parallelism with clear caveats
|
||
|
||
## Testing Contract
|
||
|
||
Implementation is not complete without automated tests. Use fake executables and temporary directories rather than requiring a real Wine/NWN environment in unit tests.
|
||
|
||
## Unit tests
|
||
|
||
Add tests for:
|
||
|
||
- config loading and effective config defaults for `models.compile`
|
||
- compiler path/env/search resolution
|
||
- Wine tool resolution
|
||
- NWN data root validation and alias handling
|
||
- ASCII-vs-binary `.mdl` eligibility logic
|
||
- include/exclude filtering
|
||
- incremental reuse decisions
|
||
- metadata invalidation on source/config/compiler changes
|
||
- content hashing based on compiled output, not source text alone
|
||
|
||
## Pipeline tests
|
||
|
||
Add or extend `internal/pipeline/pipeline_test.go` coverage for:
|
||
|
||
- HAK build packages compiled `.mdl` bytes instead of source ASCII bytes
|
||
- non-`.mdl` assets remain unchanged
|
||
- binary source `.mdl` passes through unchanged
|
||
- failed model compile aborts build
|
||
- missing output aborts build
|
||
- zero-byte output aborts build
|
||
- `--skip-models` bypasses compilation
|
||
- `--force-models` rebuilds compiled outputs
|
||
- unchanged compiled output allows HAK reuse
|
||
- changed compiled output forces HAK rewrite
|
||
- duplicate asset collision rules still behave as before
|
||
|
||
## Validator tests
|
||
|
||
Keep and extend tests proving:
|
||
|
||
- ASCII source models are still reported as informational
|
||
- enabled compilation readiness errors surface when config is invalid
|
||
|
||
## Integration/manual acceptance tests
|
||
|
||
Document real-world manual checks for a workstation with Wine and `nwnmdlcomp.exe` available.
|
||
|
||
### Test 1: readiness validation
|
||
|
||
```bash
|
||
sow-toolkit validate
|
||
```
|
||
|
||
Expected:
|
||
|
||
- no model-compiler readiness errors when config/env are correct
|
||
- ASCII `.mdl` info line still appears for source models
|
||
|
||
### Test 2: single-model HAK packaging
|
||
|
||
Given an authored ASCII model under `paths.assets`, run:
|
||
|
||
```bash
|
||
sow-toolkit build-haks --force-models
|
||
```
|
||
|
||
Expected:
|
||
|
||
- build succeeds
|
||
- resulting HAK contains a binary `.mdl`
|
||
- authored source file remains unchanged
|
||
|
||
### Test 3: incremental reuse
|
||
|
||
Run `build-haks` twice without changes.
|
||
|
||
Expected:
|
||
|
||
- second run reports model reuse
|
||
- unchanged HAKs are reused when manifest/chunk fingerprints match
|
||
|
||
### Test 4: source change invalidation
|
||
|
||
Edit one ASCII `.mdl` source and rebuild.
|
||
|
||
Expected:
|
||
|
||
- only affected compiled output is rebuilt
|
||
- affected HAK chunk is rewritten
|
||
- unrelated HAK chunks remain reusable
|
||
|
||
### Test 5: missing NWN data
|
||
|
||
Misconfigure `models.compile.data.root` and run build.
|
||
|
||
Expected:
|
||
|
||
- validation/build fails clearly before or during preparation
|
||
- error names the missing key/data requirement
|
||
|
||
## Documentation Contract
|
||
|
||
Update `README.md` to include:
|
||
|
||
- why compiled models are shipped even though ASCII remains authored source
|
||
- the new `models.compile` config section
|
||
- required local dependencies:
|
||
- `nwnmdlcomp.exe`
|
||
- `wine`
|
||
- `winepath`
|
||
- NWN data root
|
||
- environment override behavior
|
||
- cache/staging behavior
|
||
- `build-haks` flags related to model compilation
|
||
- limitations and troubleshooting notes
|
||
|
||
Optional but recommended:
|
||
|
||
- `tools/nwnmdlcomp/README.md` for consumer repo operators
|
||
|
||
## Suggested Implementation Breakdown
|
||
|
||
1. Schema and config foundation
|
||
- add `models.compile` config structs to `internal/project/project.go`
|
||
- add effective config defaults and path expansion in `internal/project/effective.go`
|
||
- add project helper methods for compiler/cache/env resolution
|
||
|
||
2. Validation foundation
|
||
- extend project/config validation for enabled compilation readiness
|
||
- extend CLI validation reporting where needed
|
||
|
||
3. Preparation layer
|
||
- add model compiler resolution, Wine resolution, NWN data staging, registry setup, and incremental metadata logic
|
||
- add a `preparedModelAssets` representation
|
||
|
||
4. Pipeline integration
|
||
- plug model preparation into `planOrBuildHAKs`
|
||
- teach `collectAssetResources` to substitute compiled model payloads
|
||
- ensure `ContentID` and HAK reuse reflect compiled output
|
||
|
||
5. CLI polish
|
||
- add build-haks flags if approved
|
||
- add progress messages and summary output
|
||
|
||
6. Tests
|
||
- config tests
|
||
- validator tests
|
||
- pipeline tests with fake compiler/Wine shims
|
||
|
||
7. Docs
|
||
- repo README updates
|
||
- optional operator README under `tools/`
|
||
|
||
## Open Design Decisions To Resolve Before Coding
|
||
|
||
These should be decided explicitly during implementation, not left implicit:
|
||
|
||
1. Should the toolkit own a dedicated Wine prefix under cache by default, or require a user-provided prefix?
|
||
2. Should NWN data alias files be created in a separate staging tree, or should the configured data root be used directly when already compatible?
|
||
3. Is parallel model compilation stable enough to expose beyond best-effort?
|
||
4. Do we want dedicated `build-haks` flags now, or only config for the first implementation?
|
||
5. Should per-model logs always be persisted, or only on failure / debug mode?
|
||
|
||
## Acceptance Criteria
|
||
|
||
The feature is complete when all of the following are true:
|
||
|
||
- `sow-toolkit build-haks` can package compiled binary `.mdl` content from authored ASCII `.mdl` source when `models.compile.enabled: true`
|
||
- authored `.mdl` files remain unchanged on disk
|
||
- validation and topdata/autogen behaviors that depend on authored `.mdl` source still work
|
||
- generated HAK manifests still reference authored asset-relative paths
|
||
- HAK reuse logic correctly tracks compiled output changes
|
||
- the feature is opt-in, deterministic, and tested
|
||
- failures are actionable and name the offending model paths
|
||
- README/config docs are updated
|
||
|
||
## Relevant References
|
||
|
||
- Repo code:
|
||
- `internal/pipeline/build.go`
|
||
- `internal/validator/validator.go`
|
||
- `internal/topdata/autogen.go`
|
||
- `internal/topdata/parts_discovery.go`
|
||
- `README.md`
|
||
- Upstream docs consulted for this contract:
|
||
- `nwn.wiki` MDL page: compiled models are recommended for release because ASCII loads more slowly
|
||
- Neverwinter Vault `nwnmdlcomp` page: standard compile/decompile CLI usage
|
||
- Neverwinter Vault forum discussions: `nwnmdlcomp` expects old NWN registry keys/data layout and some supermodel cases need additional care
|