GR-004 — a gallery built with one embedding model is meaningless with another. Cosine similarities across models are garbage but look entirely plausible, so this fails silently and expensively; every measurement taken against a mismatched pair would have been quietly wrong. The stamp is the model basename plus a SHA-256 of its bytes, with embed_dim as a cheap extra guard. The hash decides and the name explains, because neither works alone: a name is a promise rather than a fact — models get re-exported in place under an unchanged filename, which is exactly the case where the weights differ and nothing else does — while a bare hash mismatch tells an operator nothing actionable. Mismatch is fatal in every mode with no bypass. Unstamped only warns, because unstamped is unknown rather than known-bad, and an error firing on every legacy gallery trains people to reach for the bypass reflexively. scripts/stamp_gallery.py binds an existing gallery in place with no re-embedding, so the warning is a migration step rather than a permanent state; --require-gallery-stamp promotes it to an error once a site has migrated. Two gaps found that would have defeated the requirement outright: - Embedding dumps carried no stamp, so a replay — which has no live embedder — had nothing to check the gallery against. Dumps now carry embedder_model and embedder_sha256 as root attributes. Additive; schema_version stays 1. This is the same gap the dump audit identified independently. - --merge produced one file holding two embedding spaces, which no later check can untangle. Merge paths now verify before writing. The stamp also survives identity_matcher's calibration write-back, which would otherwise have stripped it on the first analysis run — the check would have worked exactly once. Conflicts resolved additively: both branches appended a source to sae_gallery and to the test target, and both edited the GR-004 register row. Merged suite: 64 cases, 3199 assertions, passing on CPU with no GPU. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> TRACES: GR-004, VR-001 | SR-001
55 lines
2.3 KiB
CMake
55 lines
2.3 KiB
CMake
# ── Unit tests ────────────────────────────────────────────────────────────────
|
|
# Pure, GPU-free, model-free tests. The similarity tests compile the GEMM backend
|
|
# directly with SAE_GEMM_CPU so the suite builds and runs on a machine without a
|
|
# GPU regardless of the main build's SAE_GEMM_BACKEND selection.
|
|
|
|
find_package(Catch2 3 QUIET)
|
|
if(NOT Catch2_FOUND)
|
|
include(FetchContent)
|
|
FetchContent_Declare(
|
|
Catch2
|
|
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
|
|
GIT_TAG v3.5.3
|
|
)
|
|
FetchContent_MakeAvailable(Catch2)
|
|
endif()
|
|
|
|
add_executable(sae_tests
|
|
test_similarity.cpp
|
|
test_calibration.cpp
|
|
test_gallery_store.cpp
|
|
test_face_utils.cpp
|
|
test_track_gallery.cpp
|
|
test_face_tracker.cpp
|
|
test_audio_signature.cpp
|
|
${CMAKE_SOURCE_DIR}/src/backends/gemm_backend.cpp
|
|
${CMAKE_SOURCE_DIR}/src/gallery/gallery_store.cpp
|
|
${CMAKE_SOURCE_DIR}/src/audio_signature.cpp
|
|
${CMAKE_SOURCE_DIR}/src/gallery/embedder_stamp.cpp
|
|
)
|
|
target_include_directories(sae_tests PRIVATE ${CMAKE_SOURCE_DIR}/src)
|
|
# SAE_GEMM_CPU: build the CPU reference GEMM regardless of the main backend.
|
|
# SAE_MODELS_DIR: config.hpp (pulled in by track_gallery.hpp) bakes model paths.
|
|
# SAE_TEST_FIXTURES_DIR: the audio golden vector is read from the source tree,
|
|
# not copied, so the file the plugin repo shares is the file under test.
|
|
target_compile_definitions(sae_tests PRIVATE
|
|
SAE_GEMM_CPU
|
|
SAE_MODELS_DIR="${SAE_MODELS_DIR}"
|
|
SAE_TEST_FIXTURES_DIR="${CMAKE_CURRENT_SOURCE_DIR}/fixtures")
|
|
# gallery_store.cpp + gallery_calibration.hpp use nlohmann/json and HDF5
|
|
# (galleries are HDF5-native, see src/gallery/gallery_store.cpp); face_utils.hpp
|
|
# and the calibration GEMM pull in OpenCV (calib3d/imgproc/core) via types.hpp.
|
|
# ffmpeg_libs: audio_signature.cpp decodes the golden fixture (avformat/avcodec/
|
|
# avutil/swresample). Still GPU-free — the audio path is pure CPU.
|
|
target_link_libraries(sae_tests PRIVATE
|
|
Catch2::Catch2WithMain
|
|
nlohmann_json::nlohmann_json
|
|
ffmpeg_libs
|
|
${OpenCV_LIBS}
|
|
${HDF5_CXX_LIBRARIES})
|
|
target_include_directories(sae_tests PRIVATE ${HDF5_INCLUDE_DIRS})
|
|
|
|
include(CTest)
|
|
include(Catch)
|
|
catch_discover_tests(sae_tests)
|