mirror of
https://github.com/razzant/ouroboros.git
synced 2026-10-02 19:58:46 +00:00
fix(#1195): an unrelated page change never cancels the hidden Widgets retention check
Review round 4 advisory (gpt-6-astra): widgets.js aborted the owned list requests on EVERY non-Widgets page-shown event. A skill disabled while Widgets was hidden started the retention read; navigating between other pages during that read cancelled it, and the disabled skill's kept-running frame stayed alive until the next visit. Leaving Widgets still cancels its own sync; once hidden, other navigation leaves the retention check alone. The retain browser case now holds the read across a dashboard -> skills navigation before letting it land (Chromium + WebKit pass; fails without the fix).
This commit is contained in:
parent
b6e82b095f
commit
c6a1e4139a
2 changed files with 14 additions and 1 deletions
|
|
@ -15,6 +15,7 @@ import json
|
|||
import os
|
||||
import pathlib
|
||||
import textwrap
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
||||
|
|
@ -848,11 +849,21 @@ def test_ui_smoke_widget_retain_keeps_running_across_pages(direct_server_with_da
|
|||
|
||||
# Leave, then disable the skill while Widgets is hidden: the kept frame
|
||||
# is force-stopped without a visit; the return finds the cards gone.
|
||||
# The read is HELD across dashboard -> skills: unrelated navigation must not cancel it.
|
||||
_click_nav(page, "dashboard")
|
||||
wait_active(page, False)
|
||||
page.wait_for_timeout(300)
|
||||
assert frame_count(page, "kept") == 1
|
||||
held = []
|
||||
page.route("**/api/widgets", lambda route: held.append(route))
|
||||
assert toggle(page, False) == 200
|
||||
deadline = time.monotonic() + 10
|
||||
while not held and time.monotonic() < deadline: page.wait_for_timeout(50)
|
||||
assert held, "the disable did not start the hidden retention read"
|
||||
_click_nav(page, "skills")
|
||||
page.wait_for_timeout(300)
|
||||
assert frame_count(page, "kept") == 1, "the read is still held; nothing may stop yet"
|
||||
[route.continue_() for route in held]; page.unroute("**/api/widgets")
|
||||
wait_frame(page, "kept", False, timeout=15_000)
|
||||
wait_active(page, False)
|
||||
_click_nav(page, "widgets")
|
||||
|
|
|
|||
|
|
@ -1576,7 +1576,9 @@ export function initWidgets(ctx = {}) {
|
|||
render();
|
||||
} else {
|
||||
cardMenus.close();
|
||||
listRequests.abortAll();
|
||||
// Leaving Widgets cancels ITS sync; once hidden, an unrelated page change
|
||||
// must not cancel a skill-disable retention check (its kept frame would run on).
|
||||
if (widgetsVisible) listRequests.abortAll();
|
||||
// Leaving disposes the mounted work — except the frames the owner
|
||||
// keeps running, which stay mounted in the hidden page — and stops
|
||||
// stale paints; the cards stay in the DOM so the next entry mounts
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue