fix(capture): populate contentHash on captured samples to fix always-prompting remove

contentHash was left empty on every capture; hashReferencedElsewhere returns
false for empty hashes, so every remove looked like a last reference. Add
FNV-1a hashBytes to capture_paths, wire into both commit paths. NOTE: this
activates index dedup-by-hash in production — a bit-identical re-capture now
collapses onto the existing entry instead of adding a duplicate (spec-intended).
This commit is contained in:
2026-07-26 16:37:46 -04:00
parent 791a9c60eb
commit 5fabade90c
6 changed files with 133 additions and 5 deletions
+14 -1
View File
@@ -78,7 +78,7 @@
#include <string>
#include <vector>
#include "capture_paths.h"
#include "capture_paths.h" // hashBytes, deriveBankPaths
#include "peaks.h" // lastFrameAboveThreshold, AudioSample
#include "realtime_record.h"
#include "render_settings.h" // autoTrimEndRatio, realtimeRecordWindowEnd
@@ -512,6 +512,19 @@ CaptureResult finalizeRecording(RealtimeCaptureState& st) {
result.status = CaptureStatus::Ok;
result.sample = sampleFromRecordedCapture(cap);
// Content hash: FNV-1a over the (possibly trimmed) bank file bytes so
// hashReferencedElsewhere can identify copies in other banks and suppress the
// last-reference confirm when another bank still holds the same file.
// Best-effort: an unreadable file leaves contentHash empty — the safe,
// confirm-eliciting direction (bank_model treats "" as non-participating).
{
const std::vector<std::uint8_t> fileBytes = readAllBytes(destPath);
if (!fileBytes.empty()) {
result.sample.contentHash =
hashBytes(fileBytes.data(), fileBytes.size());
}
}
// The recorded file's true length differs from the request range when a tail was
// recorded, so the Sample length must reflect the FILE, not the range:
// Auto with a trim applied -> the trimmed length trimAutoTailInPlace returned.