## What Two correctness fixes surfaced in review of the direct-depot HAK artifact work. ### Reject resref+type collisions in `chunksFromManifest` A manifest can name two distinct source paths that collapse to the same `resref+type` (e.g. `creature/foo.tga` and `placeable/foo.tga` — resref is the lowercase basename minus extension). The ERF writer keys resources on `Name:Type`, so the second silently shadowed the first: an asset would vanish from the packed HAK with no error. `chunksFromManifest` now runs `ensureUniqueChunkResources` per chunk and fails the build on a duplicate. This guards **both** build paths — the legacy `--source-manifest` flow and the direct content-addressed flow (`chunksFromSourceManifest` → `chunksFromManifest`). ### Document erf post-write hash coupling `writeResourceData` streams the source into the output while hashing, so size/SHA mismatches are only detected *after* the bytes are written. A non-nil return therefore means the writer holds partial, unverified output and the caller must discard it. Added a comment making that contract explicit; `writeHAKArchive` already honours it (writes to a temp file, removes on any Write error, never renames a bad archive into place). ## Tests - `TestChunksFromManifestRejectsResrefCollision`: collision → error, distinct resrefs → clean. Asserts only error presence/absence — silent asset loss is the contract, not any specific wording. - `go vet ./internal/erf/ ./internal/pipeline/` clean. - `go test ./internal/erf/ ./internal/pipeline/` green. ## Follow-up A new crucible release must be cut after this merges so the guard ships in the binary `sow-assets-manifest` pins. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Reviewed-on: #8 Co-authored-by: vickydotbat <vickydotbat@tutamail.com> Co-committed-by: vickydotbat <vickydotbat@tutamail.com>
2.1 KiB
description, alwaysApply
| description | alwaysApply |
|---|---|
| sow-tools / Crucible — the build/conversion/sync toolchain repo. | true |
sow-tools / Crucible Agent Guide
This repo owns the builder logic: one Go module
(git.westgate.pw/ShadowsOverWestgate/sow-tools) producing the crucible
dispatcher and the crucible-<name> binaries.
What this repo owns / does not own
Owns: build/extract/validate/compare pipeline, ERF/HAK packing, topdata 2da/tlk
compilation, wiki rendering/deploy, depot blob verify, music conversion,
changelog. Does not own authored game content (that is sow-module /
sow-topdata / sow-assets-manifest) or any production deploy authority (that
is sow-platform).
Rules
- Fail closed, never fake. A builder with no migrated logic yet (
depot) exits70. Do not stub a builder to emit a placeholder artifact. - Binaries are not committed. They are CI artifacts / image layers.
/bin/,*.exe,nwn-tool,sow-toolkitare gitignored. - The registry is the command surface.
internal/dispatch.Registryis the single source of truth; keep it in sync withcmd/anddocs/command-surface.md. Adding a builder = acmd/crucible-<name>/main.goshim + aRegistryentry + a doc row.
Wiring a builder
- Ensure the relevant
internal/package(s) cover the work. - Add tests; keep outputs deterministic (same input → same bytes).
make checkmust stay green; updatemake smoketo expect the wired exit.
Commands
nix develop && make check # vet + test + shellcheck + yamllint
make build # cmd/* -> ./bin
make smoke # assert fail-closed contract
make image # crucible:<sha>
Tests
Tests must survive harmless changes to constants, defaults, wording, ordering, fixture data, and internal implementation details. A test that fails merely because a basic value changed is usually a bad test. Only assert exact values when the value is part of a documented public contract, external protocol, compatibility requirement, security rule, migration, or business rule.