diff --git a/docs/CONTINUITY.md b/docs/CONTINUITY.md index bf035ec..1d6f11f 100644 --- a/docs/CONTINUITY.md +++ b/docs/CONTINUITY.md @@ -6,10 +6,10 @@ Bu dosya projenin tek canlı devir noktasıdır. Tarihsel continuity kronolojisi `ROADMAP.md` ve `ENGINEERING_AUDIT.md` içindedir. - Güncelleme: 29 Ağustos 2026 -- Kayıt hazırlanırken doğrulanan HEAD: `63b770498b8c8eff70b5270d5cff4159a62ccc4a` +- Kayıt hazırlanırken doğrulanan HEAD: `2c68648c82cbc3a6b56fc03b1317f07c322da1bd` - Güncel HEAD/origin farkı her oturumda `git rev-list --left-right --count` ile ölçülür; bu belge kendi commit hash'ini tahmin etmez. -- Dal: `codex/v040-ux-merge-record` (temiz canonical `master` ve `origin/master` exact `63b7704`, `0/0`; yalnız bu merge kaydı uncommitted) -- Son kanıt: `EV-20260829-001` +- Dal: `codex/ipc-offscreen-acceptance` (temiz canonical `master` ve `origin/master` exact `2c68648`, `0/0` tabanında source/test/docs değişiklikleri uncommitted) +- Son kanıt: `EV-20260829-002` - Yayın kararı: **v0.40 canlı/latest; 87 varlık eş, public ana/add-on indirme hashleri ve Ed25519 imzaları geçti.** ## Canlı ürün ve yayın durumu @@ -41,6 +41,7 @@ Bu dosya projenin tek canlı devir noktasıdır. Tarihsel continuity kronolojisi ## Kalite kabul özeti - Windows P0 matrisi: `WIN-P0-01`–`WIN-P0-05` PASSED; drag/drop, playlist sınırları ve IPC için `P0-06`, `P0-07`, `P0-08` NOT_RUN. +- `WIN-P0-08` deterministik offscreen çok-süreç kapsamı gerçek secondary PID, dosya/URL/aktivasyon devri, exit `0` ve terminal kapanış ölçümüyle genişletildi; dar etki paketi **93 passed** verdi. Gerçek ürün penceresi foreground ve hedef-yükleme sonucu ölçülmediği için fiziksel satır hâlâ `NOT_RUN` (`EV-20260829-002`). - Video biçimi matrisi: SDR ekranda `VF-CORE-01` ve HDR ekranda SDR-on-HDR `VF-CORE-02` exact native ve kontrollü insan ramp kabulüyle PASSED. Kalan 14 biçim satırı ve genel `WIN-P2-01` BLOCKED; bu iki PASS genel HDR/format @@ -54,7 +55,6 @@ Bu dosya projenin tek canlı devir noktasıdır. Tarihsel continuity kronolojisi ## Açık çalışma ve korunan kapılar - Yayın sonrası oynatma/kontrol UX denetimi exact `59f6980` tabanında regression-first yürütüldü. Playlist/EOF ve görünür durum rollback'lerine ek olarak ses, seek exception, hız, loop ve görüntü ayarı başarısızlıkları; klavye yönlendirmeleri; tekrarlı title-bar, updater, panel ve pencere boyutu tıklamaları sertleştirildi. Yapışık playlist sınırındaki çift resize alanı, PiP/dar pencere kontrol-hit çakışması, mod geçişinde takılı resize imleci ve overlay'in yuttuğu çift/sağ tık kapatıldı. Derin kontrol-yolu taraması ayrıca dosya/URL/M3U seçimi, aktif öğe kaldırma, liste temizleme ve üç dosya-ekleme yolunu native ret halinde atomik geri almaya bağladı; klasik ses çubuğunda yatay ve yüksek çözünürlüklü teker davranışı düzeltildi. EV029 ve EV030 uygulamaları kaynak/test ağacından çıkarıldı; ilk görüntülerin eski `9090caf` checkout'undan geldiği ayrıca kaydedildi. Doğru ağaç yeniden açıldıktan sonraki görüntü klasör, playlist/menü ve sağ pencere ikonlarının tümünde hover aktifken dikey okun kaldığını doğruladı ve EV031 child-event teşhisini çürüttü; o uygulama/test de çıkarıldı. Kök neden, ayrı top-level overlay için gerekli `QApplication` override'ının ana pencere başlığında da açılmasıydı: Qt sözleşmesine göre bu cursor bütün uygulama widget'larını ezdiğinden ikonların kendi el cursor'ı görünemiyordu. Ana pencere ağacı artık yalnız widget cursor'ı kullanıyor; global override yalnız farklı top-level overlay ile sınırlı. Etki paketi **302 passed**, son tam deterministik paket **5160 passed / 11 skipped / 0 failed** verdi (`EV-20260828-033`). Değişiklik sonrası kullanıcı görüntülerinde bütün ikonlar doğru el cursor'ını, yalnız boş gerçek üst kenar dikey resize cursor'ını gösterdi; normal kapanıştan sonra player/launcher child süreçleri sıfırdı (`EV-20260828-034`). Kullanıcı tercihiyle başlık şeridi önce 36 px'e, ardından ikon/düğme ölçüleri korunarak güncel 40 px'e çıkarıldı; 40 px hedef paket **278 passed**, tam paket **5160 passed / 11 skipped / 0 failed** verdi (`EV-20260828-036`) ve kullanıcı güncel görünümü açıkça kabul etti (`EV-20260828-037`). Exact paket local `1abd905` commit'ine temiz readback ile bağlandı (`EV-20260828-038`). PR #69 exact `b244a7f` head'i required hosted `test` koşumunda **5149 passed / 22 skipped**, `LEDGER_APPEND_ONLY_OK` verdi ve iki ebeveynli exact `63b7704` merge commit'iyle protected `master`a alındı; canonical klasör clean `0/0` ile aynı commit'e fast-forward edildi (`EV-20260829-001`). Bu görsel source-tree ve hosted CI kabulüdür; captured exit-marker olmadığı için formal native smoke veya kurulu artifact kabulü değildir. İngilizce 456/456 tamam; 0/456 olan diğer altı katalog derlenmez ve menüde sunulmaz. - - Installer UX kararları `PACKAGING_PLAN.md` içinde tutulur. Üç private bitmap yönü karşılaştırıldı; kullanıcı **C — Dengeli Hibrit** yönünü açıkça seçti ve seçim kayıt paketi exact `f432c73` commit'iyle bağlandı @@ -182,7 +182,7 @@ merge/parent/run/`0/0` readback'ini sonraki gerçek kayıt provenance'ına bağl ## Sıradaki tek adım -Kullanıcının ayrı onayıyla `EV-20260829-001` iki-belge merge kaydını commit et; push ve PR onaylarını ayrıca iste. Tek-agent kısıtı nedeniyle bağımsız karşıt inceleme `NOT_RUN` ve formal bağımsız GO yoktur. Build, native/kurulu artifact ve fiziksel kurulum ayrı onaylıdır. +Mevcut toplu Git onayı kapsamında `EV-20260829-002` offscreen IPC kapsamını commit/push/PR kapılarından geçir; hosted test sonucunu kullanıcı bildirsin. Gerçek `WIN-P0-08` ürün-penceresi koşumu, build, native/kurulu artifact ve fiziksel kurulum ayrı onaylıdır. Tek-agent kısıtı nedeniyle bağımsız karşıt inceleme `NOT_RUN` ve formal bağımsız GO yoktur. ## Dokunulmayacaklar ve ayrı onaylar diff --git a/docs/VERIFICATION_LEDGER.json b/docs/VERIFICATION_LEDGER.json index 1e9473e..144ecb8 100644 --- a/docs/VERIFICATION_LEDGER.json +++ b/docs/VERIFICATION_LEDGER.json @@ -10923,6 +10923,45 @@ "No build, installation, uninstall, tag or release was performed." ], "next_action": "Commit this two-document merge record through the normal protected documentation workflow; keep build, installed-artifact acceptance, tag and release behind separate explicit approvals." + }, + { + "id": "EV-20260829-002", + "recorded_at_utc": "2026-08-28T23:04:31Z", + "proof_layer": "deterministic", + "result": "passed", + "commit": "2c68648c82cbc3a6b56fc03b1317f07c322da1bd", + "baseline_commit": "2c68648c82cbc3a6b56fc03b1317f07c322da1bd", + "working_tree_state": "uncommitted source/test/documentation changes on codex/ipc-offscreen-acceptance from clean canonical master equal to origin/master", + "changed_files": [ + "docs/CONTINUITY.md", + "docs/VERIFICATION_LEDGER.json", + "docs/WINDOWS_ACCEPTANCE_MATRIX.md", + "tests/test_single_instance_regressions.py" + ], + "subject": "Offscreen multi-process IPC coverage for file, URL and activation handoff terminal state", + "commands": [ + "read-only canonical master, release, continuity and open Windows acceptance matrix audit", + "python -m pytest -q tests/test_single_instance_regressions.py tests/test_playlist_panel_regressions.py tests/test_playlist_wrap_regressions.py tests/test_subtitle_drop_activation_regressions.py; pre-change 92 passed", + "red-first safe-URL secondary process test; expected failure because CompletedProcess exposed no PID", + "replace the test helper's subprocess.run with bounded subprocess.Popen/communicate, exact PID capture and timeout cleanup limited to the owned secondary process", + "target safe-URL test; 1 passed; complete single-instance family; 20 passed", + "four-family offscreen impact package; 93 passed; git diff --check" + ], + "evidence": [ + "the new red test reproduced the evidence gap exactly: the secondary process handed over the safe URL but the old helper could not report its PID or terminal liveness", + "the bounded helper now records the real secondary PID, return code, stdout/stderr and post-communicate liveness; timeout kills only that helper-owned PID before re-raising", + "file, safe HTTPS URL and empty activation-only requests each traverse a real second Python process, read back SECONDARY, exit zero, report terminal non-liveness and arrive exactly once at the primary guard", + "the complete single-instance family passed 20 tests and the combined IPC, playlist and subtitle-drop offscreen impact package passed 93 tests", + "PR #70 terminal merge provenance is carried into this first subsequent real record: required run 33218814715 emitted LEDGER_APPEND_ONLY_OK and 251 passed, then exact head c7e6922d75981050ad4a9ee043ca65f4d3a0939a merged as two-parent 2c68648c82cbc3a6b56fc03b1317f07c322da1bd; canonical master began this work clean at origin parity 0/0" + ], + "summary": "The deterministic IPC boundary now measures real secondary PIDs, exact file/URL/activation delivery, exit zero and terminal secondary-process absence across three offscreen multi-process scenarios.", + "limitations": [ + "Offscreen QLocalServer/QLocalSocket behavior does not prove foreground activation of the real product window or successful file/URL loading through MPVPlayer, so WIN-P0-08 remains NOT_RUN.", + "This does not cover Explorer OLE drag/drop or physical playlist row reordering; WIN-P0-06 and WIN-P0-07 remain NOT_RUN.", + "The user-required single-agent constraint leaves independent adversarial review NOT_RUN.", + "No Computer Use, physical/native run, build, installation, uninstall, tag or release was performed." + ], + "next_action": "Commit and submit this bounded offscreen IPC package through the protected PR workflow; after merge, require a separately approved exact real-window IPC runner before changing WIN-P0-08 from NOT_RUN." } ] } diff --git a/docs/WINDOWS_ACCEPTANCE_MATRIX.md b/docs/WINDOWS_ACCEPTANCE_MATRIX.md index 32c3c8a..c086fd1 100644 --- a/docs/WINDOWS_ACCEPTANCE_MATRIX.md +++ b/docs/WINDOWS_ACCEPTANCE_MATRIX.md @@ -175,7 +175,10 @@ değiştirmez. ### WIN-P0-08 — İkinci örnek ve IPC - **Deterministik sınır:** `tests/test_single_instance_regressions.py` mutex, - dosya/URL iletimi ve güvenli mesaj sözleşmesini korur. + dosya/URL iletimi ve güvenli mesaj sözleşmesini korur. Exact `2c68648` + tabanındaki offscreen çok-süreç kapsamı dosya, güvenli URL ve yalnız + aktivasyon isteklerinin her birinde gerçek secondary PID'i, exit `0` ve + terminal süreç kapanışını ayrıca ölçer (`EV-20260829-002`). - **Native ölçüm:** exact commit için fail-closed ikinci-örnek/IPC runner'ı yoktur. Eski kullanıcı kabulü yeni başlangıç çizgisine aktarılmaz. - **Exact girdiler:** temiz ilk kaynak örneği, gerçek yerel video, güvenli URL, @@ -183,6 +186,9 @@ değiştirmez. kimliği. - **Açık boşluk:** dosya ve URL iki ayrı gerçek koşumda ilk örneğe geçmeden, ikinci süreç çıkmadan ve artık süreç olmadığı kaydedilmeden PASSED yazılmaz. + Offscreen secondary süreç kanıtı, gerçek ürün penceresinin foreground + dönüşünü veya hedef medyanın yüklendiğini ölçmediğinden bu satır `NOT_RUN` + kalır. ## Önerilen yürütme sırası diff --git a/tests/test_single_instance_regressions.py b/tests/test_single_instance_regressions.py index b571dbe..7ef1e4a 100644 --- a/tests/test_single_instance_regressions.py +++ b/tests/test_single_instance_regressions.py @@ -18,6 +18,7 @@ import uuid from concurrent.futures import ThreadPoolExecutor from pathlib import Path +from types import SimpleNamespace import pytest from PyQt6.QtNetwork import QLocalServer, QLocalSocket @@ -62,8 +63,23 @@ def _second_launch(name, payload, tmp_path): """) path = tmp_path / "second_launch.py" path.write_text(script, encoding="utf-8") - return subprocess.run([sys.executable, str(path)], capture_output=True, - text=True, timeout=60) + process = subprocess.Popen( + [sys.executable, str(path)], stdout=subprocess.PIPE, + stderr=subprocess.PIPE, text=True) + try: + stdout, stderr = process.communicate(timeout=60) + except subprocess.TimeoutExpired: + process.kill() + process.communicate() + raise + return SimpleNamespace( + args=process.args, + returncode=process.returncode, + stdout=stdout, + stderr=stderr, + pid=process.pid, + alive_after=process.poll() is None, + ) def _pump(qt_app, received, seconds=20): @@ -217,12 +233,39 @@ def test_second_launch_is_refused_and_hands_over_the_file(qt_app, name, _pump(qt_app, received) result = future.result(timeout=60) + assert result.pid > 0 assert result.stdout.strip() == "SECONDARY", result.stderr + assert result.returncode == 0 + assert result.alive_after is False assert received == [r"I:\film.mkv"] finally: primary.release() +def test_second_launch_hands_over_safe_url_and_exits_without_leak( + qt_app, name, tmp_path): + """URL devri gercek secondary PID'i ve terminal cikisi ile olculur.""" + primary = SingleInstanceGuard(name) + received = [] + url = "https://example.com/watch?v=mlc-ipc-probe" + try: + assert primary.acquire() is True + primary.activation_requested.connect(received.append) + + with ThreadPoolExecutor(max_workers=1) as pool: + future = pool.submit(_second_launch, name, url, tmp_path) + _pump(qt_app, received) + result = future.result(timeout=60) + + assert result.pid > 0 + assert result.stdout.strip() == "SECONDARY", result.stderr + assert result.returncode == 0 + assert result.alive_after is False + assert received == [url] + finally: + primary.release() + + def test_launch_without_a_file_only_asks_for_activation(qt_app, name, tmp_path): """Dosyasız ikinci başlatma da pencereyi öne getirmelidir.""" @@ -237,7 +280,10 @@ def test_launch_without_a_file_only_asks_for_activation(qt_app, name, _pump(qt_app, received) result = future.result(timeout=60) + assert result.pid > 0 assert result.stdout.strip() == "SECONDARY", result.stderr + assert result.returncode == 0 + assert result.alive_after is False assert received == [""], "boş yük = yalnız pencereyi öne getir" finally: primary.release()