feat(streamer): purge après ACK + buffering SQLite persistant

- Nouveau module persistent_buffer.py (SQLite WAL, thread-safe)
- Purge automatique des captures locales après ACK 200 serveur
- Drain loop 15s, retry exponentiel, plafonds tentatives
- Enum ImageSendResult.{OK, FAILED, FILE_GONE} pour distinguer les cas
- FileNotFoundError n'est plus un faux succès (P0-E audit)
- 14 tests intégration

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dom
2026-04-14 16:47:35 +02:00
parent 203dc00d53
commit 013fe071a2
5 changed files with 1282 additions and 24 deletions

View File

@@ -184,8 +184,12 @@ class TestImagePayloadFormat:
"""Le serveur distingue full/crop par '_crop' dans le shot_id."""
from agent_v0.agent_v1.network.streamer import TraceStreamer
fake_img = tmp_path / "crop.png"
fake_img.write_bytes(b"\x89PNG\r\n\x1a\n" + b"\x00" * 50)
# Dans le monde réel, full et crop sont deux fichiers distincts
# (la purge après ACK supprime le premier avant que le second parte).
fake_full = tmp_path / "full.png"
fake_full.write_bytes(b"\x89PNG\r\n\x1a\n" + b"\x00" * 50)
fake_crop = tmp_path / "crop.png"
fake_crop.write_bytes(b"\x89PNG\r\n\x1a\n" + b"\x00" * 50)
with patch("agent_v0.agent_v1.network.streamer.requests") as mock_req:
mock_req.post.return_value = MagicMock(ok=True)
@@ -194,9 +198,9 @@ class TestImagePayloadFormat:
streamer._server_available = True
# Full screenshot
streamer._send_image(str(fake_img), "shot_0001_full")
streamer._send_image(str(fake_full), "shot_0001_full")
# Crop screenshot
streamer._send_image(str(fake_img), "shot_0001_crop")
streamer._send_image(str(fake_crop), "shot_0001_crop")
img_calls = [
c for c in mock_req.post.call_args_list