personal memory agent
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: atomic writes for voiceprint .npz files

Write to a temp file (.tmp.npz) then rename to the final path,
preventing CRC-32 corruption from concurrent write contention.
Fixes all three production write paths: _save_voiceprints_batch()
in bootstrap.py, _save_voiceprint() and _remove_voiceprint() in
routes.py.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+10 -4
+3 -1
apps/speakers/bootstrap.py
··· 123 123 ) 124 124 combined_meta = np.array(existing_meta + new_meta, dtype=str) 125 125 126 - np.savez_compressed(npz_path, embeddings=combined_emb, metadata=combined_meta) 126 + tmp_path = npz_path.with_name(npz_path.stem + '.tmp.npz') 127 + np.savez_compressed(tmp_path, embeddings=combined_emb, metadata=combined_meta) 128 + tmp_path.rename(npz_path) 127 129 return len(new_items) 128 130 129 131
+7 -3
apps/speakers/routes.py
··· 235 235 new_embeddings = np.vstack([existing_embeddings, embedding.reshape(1, -1)]) 236 236 new_metadata = np.append(existing_metadata, metadata_json) 237 237 238 - # Write back 239 - np.savez_compressed(npz_path, embeddings=new_embeddings, metadata=new_metadata) 238 + # Write back (atomic: temp file + rename) 239 + tmp_path = npz_path.with_name(npz_path.stem + '.tmp.npz') 240 + np.savez_compressed(tmp_path, embeddings=new_embeddings, metadata=new_metadata) 241 + tmp_path.rename(npz_path) 240 242 return npz_path 241 243 242 244 ··· 294 296 295 297 new_embeddings = embeddings[keep] 296 298 new_metadata = metadata_arr[keep] 297 - np.savez_compressed(npz_path, embeddings=new_embeddings, metadata=new_metadata) 299 + tmp_path = npz_path.with_name(npz_path.stem + '.tmp.npz') 300 + np.savez_compressed(tmp_path, embeddings=new_embeddings, metadata=new_metadata) 301 + tmp_path.rename(npz_path) 298 302 return True 299 303 300 304