# ADR 0043: Content-Addressed Import Fingerprints

## Status

Accepted

## Context

Generated model artifacts and the project asset registry must be stable across contributors, CI,
Git worktrees, and LFS checkouts. Git does not preserve source-file modification times. Persisting a
checkout mtime as source identity therefore caused the editor to rewrite otherwise equivalent
animation and static-mesh manifests during startup. Static-mesh manifests also used only byte length
and mtime, so a same-size source edit could evade the persisted identity contract.

Formatting-only publication was a second source of noise. Re-serializing an equivalent RON
document could normalize its final newline or layout even when import semantics had not changed.
That made clean-checkout release evidence unreliable and obscured intentional asset edits.

## Decision

`shared::AssetSourceFingerprint` is the persisted imported-source identity. It contains the exact
source byte length and lowercase BLAKE3 digest. Filesystem timestamps are not serialized or compared
as semantic identity; an importer may use them only as an in-memory scan hint before confirming
content.

The asset registry stores this fingerprint for every imported model, texture, and audio source.
Content identity also drives unique move reconciliation, so metadata-only drift cannot replace a
stable registry UUID. Ambiguous copies still receive a new identity.

Animation and static-mesh manifests use the same fingerprint. Animation schema v3 already contained
a content hash, so its schema remains v3 and legacy `modified_unix_secs` fields are accepted as
ignored unknown metadata. Static-mesh schema v4 replaces its length-plus-mtime record with length
plus BLAKE3. Existing schema-v3 static artifacts are regenerated once; unrelated assets are not
reimported.

Registry and generated-manifest writers parse the existing RON and compare the semantic value before
publication. Equivalent documents preserve their exact existing bytes, including layout and final
newlines. Changed documents publish canonical pretty RON. Registry records are ordered by normalized
project path before comparison, so filesystem enumeration order cannot change their serialized
sequence on a fresh checkout.

Authoritative project validation remains read-only. It validates registry, animation, and
static-mesh fingerprints by length and digest, including same-size source edits. CI runs both
headless validators and then asserts that tracked and untracked checkout state is unchanged.

## Consequences

- A source touch or fresh checkout mtime cannot dirty the project.
- Same-size source edits invalidate the affected registry/manifests deterministically.
- Model, texture, and audio IDs survive uniquely identifiable moves by content.
- Initial migration adds fingerprints to imported registry records and upgrades static manifests to
  schema v4. Legacy animation files can remain byte-identical indefinitely because their timestamp
  field is ignored.
- Startup hashing reads imported source bytes. Future scan caches may use metadata to avoid work,
  but they must verify content before persisting a changed identity.
- External glTF/FBX dependency paths remain explicit manifest dependencies; extending fingerprints
  to a dependency graph requires a separate versioned contract.
