M6: commands — pause/resume/delete end to end - #3
Merged
Conversation
`pending_delete`, silme akışının ara durumunu ("emir verildi, cihaz henüz
duymadı") işaretlemek için tasarlanmıştı. Ama yazacak kimse yoktu:
* dashboard yazamaz — db/rls.sql `devices` üzerindeki UPDATE yetkisini tek
sütuna daraltıyor: grant update (device_name). Bu kilit bilinçliydi;
key_hash / last_seen / logging_enabled'ın yazarı collector'dır.
* collector yazmıyor — supabase_client.py'deki DEVICE_WRITABLE_COLUMNS
listesinin dışındaydı ve yanındaki not "kimin yazacağı M6'da karara
bağlanacak" diyordu.
Yazan olmayınca sütun her satırda `false` kaldı: kimsenin dolduramadığı bir
bayrak hiçbir şey işaretlemiyordu. Aynı bilgi `commands` tablosunda zaten
duruyor — bekleyen silme = (type='delete' and status='pending'). Kopyayı
yaşatmak için ya kilidi gevşetmek ya yeni bir mekanizma (trigger / ayrı
endpoint) eklemek gerekiyordu; kaldırmak üçünün de bedelini sıfırlıyor.
Değişiklikler:
* db/migrations/0003_drop_pending_delete.sql — yeni migration, doğrulama
sorgusu ve geri alma notuyla birlikte
* db/schema.sql — sütun çıkarıldı (her DB değişikliğinde iki dosya kuralı)
* db/rls.sql — kolon-yetki yorumundaki atıf temizlendi
* collector/auth.py — DeviceIdentity.pending_delete alanı ve satır eşlemesi
* collector/supabase_client.py — find_device_by_key_hash select listesi
ÇALIŞTIRMA SIRASI: migration, `pending_delete`'i artık SELECT etmeyen collector
Fly'a deploy EDİLDİKTEN SONRA çalıştırılır. Ters sırada canlı collector olmayan
bir sütunu istemeye devam eder ve device key ile gelen her istek hata alır.
Veri kaybı yok: sütun hiç yazılmadı. Testler: 226 passed.
Komut kuyruğunun sunucu tarafı: dashboard `commands` tablosuna pending satır ekler, agent poll ile alır, uygular ve id'sini `POST /ingest` gövdesinde geri yollar. - endpoints_commands.py: GET /commands (device key) + process_acks() - db_access.py: server_now() ve call_or_503() — iki uç noktanın paylaştığı yardımcılar; ingest'in içindeki yereller buraya taşındı - supabase_client: delete_device / list_pending_commands / mark_commands_applied; `logging_enabled` allowlist'e eklendi Kilitli kararlar (md/memory/decisions.md → "Komutlar (M6)"): - #6 GET /commands de `last_seen` tazeler — pause'daki agent offline görünmesin - #7 `devices.logging_enabled` komut VERİLDİĞİNDE değil, agent UYGULADIĞINI bildirdiğinde yazılır; değer gövdeden değil DB'deki `type` alanından türer - ack, satır yazımından SONRA işlenir: delete cihaz satırını siler (CASCADE), ters sırada aynı gövdedeki son ölçümler foreign key'e takılırdı - mark_commands_applied'da `status=eq.pending` filtresi bilerek YOK: yarıda kalmış bir delete, tekrarlanan ack ile tamamlanabilsin collector 0.3.0 → 0.4.0 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Buradaki hataların hepsi sessiz: komut teslim edilmezse agent hiç duraklamaz, ack işlenmezse aynı komut sonsuza kadar tekrar gelir, delete yanlış sırada işlenirse cihaz kaydı öksüz kalır. Hiçbiri istisna fırlatmaz. Kapsanan: poll'ün last_seen tazelemesi, yanıtın yalnızca id+type taşıması, sorgunun doğrulanmış cihaza kilitli olması, ack'in device_id ile sınırlanması, pause/resume sunucu kopyası, "son komut kazanır", delete'in her şeyin önüne geçmesi, silinmiş satıra yazmama, 503 yolları ve satırların delete'ten önce yazılması. Suite 226 → 248. 25 sabotaj denendi, hepsi yakalandı (md/memory/decisions.md → "Her test, koruduğu kod bozularak doğrulanır"). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Agent artık `GET /commands` ile bekleyen komutları çekiyor, uyguluyor ve `applied_command_ids` ile ack'liyor. Poll'ün kendi HTTP istemcisi var: pause sırasında ve backoff altında da sorulmaya devam eder, yoksa `resume` cihaza hiç ulaşamazdı. Spec'ten iki bilinçli sapma: 1. Ack, telemetriye bağlanmadı. CLAUDE.md §7 yalnızca `delete` ack'ini pause istisnası sayıyor — ama pause ack'i de gitmezse sunucu komutu her poll'da yeniden verir ve `devices.logging_enabled` kopyası hiç güncellenmez. `send_acks` bu yüzden ölçüm taşımayan küçük bir kontrol mesajı: pause telemetriyi durdurur, agent'ın "uyguladım" demesini değil. 2. Self-uninstall doğrudan yapılamıyor. Agent yetkisiz kullanıcıyla, NoNewPrivileges=yes ve ProtectSystem=strict altında çalışır; uninstall.sh'i kendi içinden çağırsa hem yetkisi yetmez hem de `systemctl disable --now` betiği kendi cgroup'uyla öldürürdü. Bunun yerine agent state dizinine bir işaret dosyası bırakıyor; yeni tracebox-uninstall.path onu görüp kaldırmayı root tarafında çalıştırıyor. Yalıtım ayarlarının hiçbiri gevşetilmedi. delete sırası (§11 Boşluk E) korundu: ack → 200 → yerel wipe → işaret. Ack gitmezse hiçbir şey silinmez, komut `pending` kalır ve tekrar denenir. install.sh iki yeni birimi kurup izleyiciyi başlatıyor; başlatmadan önce eski kurulumdan kalan işareti siliyor (yoksa yeni kurulum ilk saniyede kendini kaldırırdı). uninstall.sh her iki birimi de temizliyor ama kendisini çalıştıran servisi durdurmuyor. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Yeni dosyalar: test_commands.py (poll ayrıştırma, idempotent uygulama, delete
sırası), test_loop_commands.py (ack'lerin state'e girip çıkışı),
test_entrypoint.py (silinmiş cihaz bir daha açılmaz). test_shipper.py,
test_spool.py ve test_install_scripts.py genişletildi.
En kritik üçü:
- tekrar gelen komut yeniden ack'lenir — edilmezse duraklatılmış agent
sonsuza kadar öyle kalır ve dashboard onu "çalışıyor" gösterir
- delete, yerel veriye dokunmadan ÖNCE ack atar — tersi anahtarı silip
cihaz satırını sunucuda ölümsüz bırakırdı
- path unit'in izlediği yol ile agent'ın yazdığı yol aynı sabitten gelir —
ayrılırlarsa kaldırma sessizce hiç başlamaz
41 kasıtlı bozmanın 41'i ilgili testi kırmızıya çevirdi.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.