Skip to content

feat: validate the distance type in the model header (closes #23) - #24

Merged
danielhuici merged 2 commits into
reverseame:apotheosis2from
Dani-giron:i1-validate-distance-in-header
Sep 1, 2026
Merged

danielhuici merged 2 commits into
reverseame:apotheosis2from
Dani-giron:i1-validate-distance-in-header

Conversation

@Dani-giron

Copy link
Copy Markdown

Summary

dump()/load() validated M, M0, EF and HEURISTIC but not the distance type. A model built with one distance loaded silently into a type using another: bincode does not depend on D (distance structs are zero-sized, no trace in the serialized body), so the graph deserialized fine and every later search computed distances with the wrong function, with no error. Verified empirically: with the check disabled, loading a NormalDistance model into an InvertedDistance type returns Ok with the full graph recovered.

Changes

  • src/datalayer/algorithms.rs: DistanceAlgorithm gains a stable const TYPE_NAME: &'static str, declared by both implementations (NormalDistance, TlshDistance).
  • src/controllers/apotheosis.rs: dump() writes an FNV-1a hash of D::TYPE_NAME as 4 extra header bytes (17 -> 21). load() recomputes it for the loading type and rejects a mismatch with a descriptive error. FNV-1a instead of type_name()/std hashers because it is fully specified and stable across Rust versions, which a persistence format needs.
  • tests/header_distance.rs (new): mismatch is rejected, matching distance loads fine.

Record type R is not validated here, intentionally out of scope (see issue #23): R types usually have non-zero-sized fields, so a mismatch there is more likely to surface through bincode on its own.

Test plan

  • cargo test --test header_distance: 2/2 pass.
  • Manually reproduced the pre-fix bug by temporarily disabling the check: load() returned Ok with the graph fully populated under a mismatched distance, confirming the silent-acceptance behavior before writing the fix.
  • cargo clippy/cargo fmt on the full crate could not be verified locally (unrelated toolchain issue on this machine, disk near full); the two changed files were checked individually with rustfmt --check and pass. Will be validated by CI on this PR.

Closes #23

Instead of requiring every DistanceAlgorithm implementor to declare a
TYPE_NAME constant and hashing it with FNV-1a, write the bare type name
(std::any::type_name without the module path, length-prefixed) into the
header. The trait stays unchanged for implementors, the header is
readable in a hexdump, and a mismatch error can report both the distance
the file was built with and the one it is being loaded as.

Drop the dedicated header test per review.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@danielhuici
danielhuici force-pushed the i1-validate-distance-in-header branch from 3736694 to da0de78 Compare September 1, 2026 11:47
@danielhuici
danielhuici merged commit e548ccb into reverseame:apotheosis2 Sep 1, 2026
9 of 12 checks passed
danielhuici added a commit to Dani-giron/APOTHEOSIS that referenced this pull request Sep 1, 2026
The documentation was written in July and reviewed against the code of
that moment. Meanwhile reverseame#24 (distance type in the dump/load header),
reverseame#25 (GEXF export extracted to export::gexf, gexf fork emits the
attribute schema), reverseame#27 (record constructors return Result) and reverseame#31
(facade read accessors) landed. Update the interface document, the
three views, the glossary and the README accordingly. Text only; the
C&C component model and diagrams are untouched.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants