Autonomous Work unblock status - 2026-07-08
Kontekst
Problem z panelu /work: po kliknieciu Odblokuj system powinien pamietac decyzje dla danego typu zadania, ale w praktyce podobne tickety wracaja jako blocked i znowu wymagaja recznego odblokowania.
Zrzut z dashboardu pokazal m.in.:
koru STOPPED, heartbeat stary o kilka godzin;IFURI-203w petlino_executor/drive_failed;- liczne tickety
blockedz etykietamiwaiting:node,waiting:live_service,waiting:policy,waiting:secret; - nowe gate tickety typu
[GATE] waiting_nodei[GATE] waiting_live_servicetworzone przez watchdog.
Co faktycznie zostalo sprawdzone
Sprawdzone pliki i aktualny stan kodu:
urirun-connector-grants/urirun_connector_grants/unblock_ledger.pyurirun/adapters/python/urirun/host/work_queue.pyurirun-connector-work/urirun_connector_work/gates.pyurirun-connector-work/tests/test_unblock_persist.pyurirun-connector-watchdog/urirun_connector_watchdog/core.py
Wniosek z kodu: obecny ledger pamieta odblokowanie po ticket_id, nie po typie zadania.
work_queue.py przy akcji unblock albo ready wywoluje record_unblock(tid, ...). gates.py sprawdza potem unblock_ledger.is_unblocked(ticket.get("id")). Watchdog robi to samo: sprawdza tylko ID ticketu. To oznacza, ze decyzja dziala dla tego konkretnego ticketu, ale nie przechodzi automatycznie na kolejny ticket o tym samym typie, akcji lub gate.
Co juz dziala
- Jednorazowe odblokowanie konkretnego ticketu jest zapisywane trwale w
~/.urirun/host-dashboard/unblock-ledger.json. runnable_gate()honoruje zapis z ledgera dla tego samegoticket_id, o ile akcja nie nalezy do klasy_NEVER_UNBLOCK.- Watchdog nie powinien diagnozowac ponownie tego samego ticketu, jezeli jego
ticket_idjest juz w ledgerze. - Istnieje test
test_unblock_makes_ticket_runnable_forever, ale obejmuje tylko ten samticket_id.
Co nadal nie dziala
- Brakuje pamieci decyzji per typ zadania, np.
waiting_node,waiting_live_service,node.restart,connector.install_on_node,nxdo,signal.message.send. - Nowy ticket z innym ID, ale tym samym typem, nie dziedziczy poprzedniego
Odblokuj. record_unblock()przy kliknieciu z dashboardu nie dostaje wystarczajacego kontekstu: nie zapisuje stabilnego klucza typu/gate, tylko ID ticketu.is_unblocked()nie umie sprawdzic alternatywnego klucza, np.action:node.restart,wait-gate:waiting_node,label:nxdo,goal:signal.message.send.- Testy nie lapia regresji opisanej przez Toma: brakuje testu z dwoma roznymi ticketami tego samego typu, gdzie odblokowanie pierwszego powinno przepuscic drugi.
- Panel
/worknie pokazuje jeszcze jasno, czy odblokowanie jest jednorazowe dla ticketu, czy trwale dla typu.
Czego nie wykonalem jeszcze
- Nie wdrozylem jeszcze mechanizmu
Odblokuj dla tego typu na przyszlosc. - Nie dopisalem jeszcze pola/argumentu UI/API, ktore pozwala wybrac zakres decyzji: pojedynczy ticket vs typ/gate/akcja.
- Nie uruchomilem jeszcze petli regresyjnej
queue -> unblock -> loop -> queue, ktora potwierdza naprawe na zywo. - Nie zmienilem jeszcze watchdoga tak, by gate tickety
watchdog-wait-gatesprawdzaly typowy grant przed ponownym tworzeniem blokad. - Nie dopialem jeszcze obslugi dodatkowych argumentow akcji z dashboardu oznaczanych jako
#,*,?; to byl osobny request i wymaga znalezienia handlera akcji w UI/API.
Najbardziej prawdopodobna przyczyna obecnego bledu
Root cause jest w modelu klucza decyzyjnego:
obecnie: unblock_key = ticket_id
potrzeba: unblock_key = ticket_id albo stable_task_type_key
Dopoki Odblokuj zapisuje tylko IFURI-210, nastepny ticket IFURI-230 z tym samym wait-gate:waiting_node bedzie traktowany jako nowa, nieznana decyzja i znowu wyladuje w blocked.
Minimalny plan naprawy
1. Dodac funkcje wyliczania stabilnego typu decyzji, np. decision_key(ticket):
wait-gate:waiting_nodedla etykietwait-gate:*;waiting:node/waiting:live_servicedla etykietwaiting:*;action:<kanoniczna-akcja>dla akcji zaction_of_ticket();goal:<nazwa>dla etykietgoal:*;- opcjonalnie
source:<source>dla klas generatorow typunxdo-generator. 2. Rozszerzycunblock_ledgertak, aby zapisywal rekordy poticket_idi podecision_key. 3. Zmienicwork_queue._remember_unblock(), aby przekazywal kontekst ticketu albo przynajmniejaction/scope/type_key. 4. Zmienicgates.runnable_gate()i watchdog_is_unblocked(), aby sprawdzalyticket_idorazdecision_key. 5. Zachowac zakaz trwalego odblokowania dla_NEVER_UNBLOCKtypupypi.publish,linkedin.publish, platnosci i sekretow. 6. Dodac test: odblokowanieIFURI-Atypuwait-gate:waiting_nodepowoduje, zeIFURI-Bz tym samym typem jestrunnablebez kolejnego klikniecia. 7. Dopiero po testach uruchomic zywa petle/api/work/loopi potwierdzic, ze nowe podobne tickety nie wracaja doblocked.
Status na teraz
Diagnoza jest potwierdzona w kodzie: obecny system pamieta decyzje per ticket, a oczekiwane zachowanie wymaga pamieci per typ zadania. Dlatego problem nadal wystepuje i samo klikanie Odblokuj nie naprawi go systemowo.
Resolution (verified 2026-07-08)
Naprawa wdrożona i działa.
decision_keys(ticket)+is_unblocked_for(ticket)wunblock_ledger.py— pełne wsparcie kluczy typu (wait-gate/waiting/action:/goal:/source: + aliasy).record_unblockzapisuje równolegle ticket_id + typy._remember_unblockwwork_queue.pyfetchuje ticket i przekazuje pełny kontekst.gates.runnable_gate()short-circuituje nais_unblocked_for(z wyjątkiem_NEVER_UNBLOCK).watchdog._is_unblocked()+_ensure_wait_gate()używająis_unblocked_for(nie tworzy powtarzalnych GATE dla odblokowanego typu).- Testy
test_unblock_persist.py(8 testów) pokrywają dokładnie scenariusz regresji: odblokowanie IFURI-A typu X czyni IFURI-B tego samego typu runnable bez kolejnego kliku. - API:
GET /api/work/unblockszwracatypesiticketsosobno; revoke działa per-key (typ vs ticket). - Weryfikacja live: symulacja + uruchomione testy potwierdzają propagację; w
~/.urirun/host-dashboard/unblock-ledger.jsonistnieją wpisy typu (np.wait-gate:waiting_node).
Co wciąż może wymagać uwagi (poza tym mechanizmem):
- Inne przyczyny blokad autonomii (no_executor, drive_failed, koru stopped, brak agenta) — niezależne od ledgera unblock.
- UI
/worknadal nie oferuje wyboru zakresu przy "Odblokuj" (zawsze zapisuje typ + ticket; revoke pozwala selektywnie). grant_unblock_check(API) wciąż używa staregois_unblocked(ticket_id)— tylko do query per-ID.
Uruchom testy:
PYTHONPATH=urirun/adapters/python python -m pytest urirun-connector-work/tests/test_unblock_persist.py -q
Mechanizm "Odblokuj raz dla typu = trwałe dla podobnych ticketów" jest aktywny.