Files
sow-tools/AGENTS.md
T
archvillainette f1fd03ee83
test-image / build-image (push) Successful in 47s
test / test (push) Successful in 1m27s
build-binaries / build-binaries (push) Successful in 2m14s
build-image / publish (push) Successful in 13s
pipeline: reject resref collisions when chunking; document erf post-write hashing (#8)
## 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>
2026-06-20 07:53:04 +00:00

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

  1. Fail closed, never fake. A builder with no migrated logic yet (depot) exits 70. Do not stub a builder to emit a placeholder artifact.
  2. Binaries are not committed. They are CI artifacts / image layers. /bin/, *.exe, nwn-tool, sow-toolkit are gitignored.
  3. The registry is the command surface. internal/dispatch.Registry is the single source of truth; keep it in sync with cmd/ and docs/command-surface.md. Adding a builder = a cmd/crucible-<name>/main.go shim + a Registry entry + a doc row.

Wiring a builder

  1. Ensure the relevant internal/ package(s) cover the work.
  2. Add tests; keep outputs deterministic (same input → same bytes).
  3. make check must stay green; update make smoke to 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.