[QA-trace][#120 3/7] Процесс-отчёт web-test-orchestrator (offline-sync/PWA): агенты, SW-техника, фолс-позитивы #237
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Процесс-трейс QA отчёт — PR #120
feature/offline-sync(gitmost / Docmost fork, OFFLINE/PWA, WIP M0–M2)1. Сводка прогона
Стадии скилла (по trace-данным): recon → mapping/charters → execution (6 персон-агентов параллельно) → oracle-оценка → независимый Doer-Verifier пасс → синтез.
Агенты исполнения (7 ролей):
recon(разведка/бутстрап)pwa-sw-shell tester(оболочка SW + offline reload)offline-read tester(офлайн-чтение/cold-start)offline-edit-body(Contour A — Yjs/CRDT тело документа)offline-structural-outbox tester(Contour B — REST/outbox/структура)update-prompt-install(SW update-prompt, install, offline-emulation traps)online-sanity-regression(онлайн-регресс/ресурсы)Воронка находок (15 сырых → классификация после verifier):
Verifier: 13 находок перепроверены, из них 11 подтверждены as-is, 2 переклассифицированы вниз (#8 verified→speculative «штатный UX»; #14/#15 verified→speculative «не дефект»). 2 находки verifier НЕ успел перепроверить (TIMED_OUT): #7 и #10 — обе тяжёлые многоконтекстные/тайминговые сценарии (см. §4).
Ключевой вывод процесса: скилл уверенно поймал главный офлайн-дефект (blank-shell на offline-reload из-за auth-gate + unguarded
error.response.status) — его независимо переоткрыли четыре агента разными путями. Сильная сторона — почти все агенты ПРАВИЛЬНО применили SW/offline-технику (один контекст, ожиданиеcontroller != nullдоset_offline). Слабые места — дубль-репортинг одного корня как 4 находки и два verifier-таймаута на самых ценных data-loss сценариях.2. Какие агенты/инструменты отработали
recon— разведкаapps/client/src), Playwright sync (login,serviceWorker.ready/controller,caches.keys,indexedDB.databases,fetch('/manifest.json')),page.on(console/pageerror/response/requestfailed), phase-tagged response listener, скриншоты, Read исходников.pwa-sw-shell tester— оболочка SW + offline reloadset_offline(True/False),evaluateдляcontroller/caches.keys()/DOM-проб, четыре listener'а, скриншоты, Bash curl + grep/Read для атрибуции корня.error.response.statusи доказал, что виноват именно незащищённый вauth-query.tsx. Репро 3×, детерминированно.offline-read tester— офлайн-чтение / cold-startset_offline; hooks response/requestfailed/pageerror; out-of-band чтение IndexedDBgitmost-rq-cache(idb-keyval) изнутри страницы;response.from_service_workerкак оракул; скриншоты (Read как изображения); статические Read 7 файлов.from_service_worker=Trueна всех ответах — снял подозрение в tooling/SW-неактивации.controller != nullдо offline, один persistent context; явно «ruled out tooling/SW-activation artifact».offline-edit-body(Contour A, CRDT-персона)/tmp/ot/*.py. Верификация против независимого источника — свежий 2-й контекст, читающий из collab-сервера :3001 (server-truth, отдельная IndexedDB), а не из UI-оптимизма.ready + controller != null; один + свежий контексты осознанно разделены по ролям.offline-structural-outbox tester(Contour B)/api/comments,/api/pages/infoс authToken-cookie) — читает серверное состояние, которое UI не контролирует; phase-tagged request capture; Read исходников для атрибуции.update-prompt-installset_offline/ctx.routeНЕ блокируют fetch из SW-потока, GET/api/healthотдаёт 200 при «offline»./sw.js, Playwrightlaunch_persistent_context; перекрёстная проверка двумя механизмами (set_offline↔ctx.routeabort) + enumerationcaches.keys()/cache.keys()./apientries). Update-path честно помечен как не-воспроизводимый в одном билде (#14), без фантомного дефекта.online-sanity-regression3. Баги по КЛАССУ (как проявлялся / как и каким агентом найден; код опущен)
A.
blank-shell-offline(оболочка грузится 200 из precache, React падает в пустоту)body.innerText.length = 0,#rootсодержит только Mantine-<style>, в окне — uncaughtTypeError: Cannot read properties of undefined (reading "status"). SW отдаёт index.html + все ассеты 200 из precache (НЕ Chrome-offline, НЕ precache-404). Послеset_offline(False)+reload — восстановление.bodyLen=0) сработал ТОЛЬКО потому, что скилл требует reload/persistence round-trip. Независимо переоткрыт 4 агентами:pwa-sw-shell(#2),offline-read(#4),offline-structural-outbox(#9, +доказал что pinned-страница тоже белеет), и компонента gate описанаpwa-sw-shellотдельно (#3). Корень разбит на два под-класса ниже.B.
rendering / hard-online-dependency in render-gate/api/users/me(NetworkOnly) не отдаётся → пусто, даже если бы краш collab-token был починен.pwa-sw-shell(#3) Read компонента + корреляция сrequestfailedна/api/users/me; контроль — login-страница офлайн РЕНДЕРИТСЯ, что изолировало blank к auth-gated дереву.offline-read(#4) усилил out-of-band чтением IndexedDB (данные есть, не показаны).C.
unhandled-network-error / unguarded-property-access.statusуundefinedresponse → бросает TypeError app-wide.pageerrorhook поймал сообщение; повторный прогон со stack-capture дал фреймat retry (...index-DKs-wrBZ.js); grep.statusпо bootstrap-коду изолировал единственный незащищённый call-site. Найденpwa-sw-shell(#2) и независимоoffline-read(#5).D.
silent-optimistic-loss(false optimistic success → потеря при reload-before-reconnect)offline-structural-outbox(#10) —t_comment.py(оптимистика+replay через curl) +t_reload_loss.py(успех→reload-offline→утрата). Оракул «false optimistic success later dropped = real defect» изasync-and-state.md. Verifier TIMED_OUT — не перепроверено.E.
missing-offline-affordance(WIP, НЕ data-loss)offline-structural-outbox(#11), phase-tagged request capture + чтение порядка вhandleCreate. Корректно отнесён к WIP.F.
race(подозрение, дисконфирмировано)offline-edit-body(#7); САМ дисконфирмировал на ретесте с settle 2.5s/cadence 60–120 мс (40/40 точно). Помечен speculative «синтетик-input race, не дефект CRDT». Verifier TIMED_OUT.G.
console-noise(benign) иresource-cost(informational)H.
tooling-trap / env-limitation(находки о САМОМ инструментарии)set_offline+ctx.routeне глушат SW-thread fetch → GET 200 при offline; правильный оракул — enumeration caches.3b. Кто что нашёл
error.response.status4. ФОЛС-ПОЗИТИВЫ — кто и насколько (ключевой раздел)
Системного фолс-позитивщика в прогоне НЕТ. Это нетипично хорошо — обычно агенты дают ~85% success-hallucination/false-positive. Здесь дисциплина «EVIDENCE BEFORE CLAIM / DISCONFIRM BY DEFAULT» соблюдена почти всеми.
По агентам (подтверждено / убито / переклассифицировано):
pwa-sw-shell tester— 2/2 подтверждено, 0 убито. Надёжен. Корень доказан grep'ом до конкретного call-site, репро 3×.offline-read tester— 2/2 подтверждено, 0 убито. Самый надёжный по оракулам (out-of-band IndexedDB +from_service_worker). Снял подозрение в tooling сам.offline-structural-outbox tester— 1 подтверждён (#9), 1 WIP-честный (#11), 1 env-честный (#12), и #10 не дослежен verifier'ом (TIMED_OUT). Сам агент НЕ фолс-позитивит: для каждого claim — curl ground-truth readback. Качество высокое; риск только в том, что самый тяжёлый его сценарий (#10) остался без независимого подтверждения.offline-edit-body— образец анти-фолс-позитива: #6 подтверждён против сервер-истины, #7 САМ дисконфирмировал (честно понизил до speculative и записал в калибровку скилла), #8 — реальное наблюдение, но verifier переклассифицировал в «штатный UX, не дефект». То есть единственный «почти-фолс» (#8) — это не выдуманный баг, а корректно наблюдённое поведение с неверной первичной интерпретацией severity; агент сам пометил его low/affordance.update-prompt-install— фолс-позитивов 0; наоборот, ПРЕДОТВРАТИЛ системный фолс-позитив всего прогона, задокументировав tooling-trap (#13). #14 честно «не воспроизводимо», без фантома.reconиonline-sanity-regression— 0 фолсов; оба честно пометили свои находки как benign/informational, не раздувая severity.Кто путает «не реализовано» с «баг»? — Никто грубо не спутал. Граница проведена аккуратно
offline-structural-outbox: он РАЗДЕЛИЛ «Create page без фидбэка» (#11, честный WIP — ничего не заявляло успех) и «comment/move silent-loss» (#10, РЕАЛЬНЫЙ дефект — заявлен оптимистичный успех, потом тихо потерян). Это именно тот WIP-vs-bug гейт, который требовал стенд («claims success then silently loses data = баг; not-implemented ≠ баг»). Гейт сработал корректно.Переклассификации вниз verifier'ом (3): #8 verified→speculative (штатный title-focus), #14 verified→speculative (coverage-gap, не дефект), #15 verified→speculative (informational; плюс уточнение «1 HTML, а не 0»). Все три — не выдуманные баги, а корректные наблюдения с завышенной первичной «дефектностью». Это мягкие фолсы интерпретации, не фабрикация.
Verifier-таймауты (2) — главный риск процесса:
#7(burst-race) и#10(silent-optimistic-loss) НЕ перепроверены (TIMED_OUT). Опасно, что #10 — это самый ценный data-loss класс всего PR; он остался на слове одного агента (хоть и с curl-readback-доказательством). Verifier «прогорел» именно на тяжёлых многоконтекстных/тайминговых сценариях — там, где репро дороже всего.5. Где скилл сработал / провалился на ОФЛАЙНЕ
Сработал:
bodyLen=0+ обязательный reload/persistence round-trip — то, ради чего скилл и существует.serviceWorker.readyИcontroller != nullДОset_offline(True); проверкаresponse.from_service_worker, чтобы НЕ свалить blank на «SW не активирован». Ни один агент не сделал классическую ошибку «свежий контекст»/«offline до активации SW».Провалился / шероховатости:
error.response.status). Хорошо для уверенности, плохо для сигнал/шум: владелец получает 4–5 «high», а корней — два (gate + unguarded access). Нужен дедуп-merge перед отчётом.offline-edit-bodyнапоролся (#8) и записал в калибровку: дизамбигуировать поaria-label='Page title'.6. Предложения по улучшению скилла (PWA/offline-специфика)
Кодифицировать SW-lifecycle чеклист как обязательный gate (большинство уже делает, но зафиксировать в
references/async-and-state.md): (a) один persistent context на весь online→offline→online; (b)await serviceWorker.readyИcontroller != nullДОset_offline; (c) после offline-reload проверятьresponse.from_service_workerна ассетах — чтобы НИКОГДА не путать «SW не активирован/Chrome-offline» с «оболочка 200, app крашнул».Добавить оракул «cache-populated-but-unrendered» в
oracles.md: при blank-shell обязательно out-of-band читать persisted store (IndexedDBgitmost-rq-cache/idb-keyval) — если данные ЕСТЬ, а экран пуст, это render-gate/crash, а не «нет кэша».offline-readсделал это вручную; должно быть стандартным шагом.Жёсткий WIP-vs-bug гейт (формализовать триаду): для КАЖДОЙ офлайн-мутации спрашивать — (a) заявлен ли оптимистичный успех? (b) переживает ли reload-before-reconnect? (c) уходит ли на сервер (curl ground-truth readback)? «Успех заявлен + reload теряет + сервер пуст» = РЕАЛЬНЫЙ дефект; «ничего не заявлено» = WIP-affordance. Этот тест уже неявно применил
offline-structural-outbox— сделать его явным чеклистом.Обязательный out-of-band ground-truth для всех claim'ов о персистентности: curl REST с auth-cookie ИЛИ свежий контекст из collab-сервера (:3001). Никаких выводов «синхронизировалось» из UI-оптимизма. Это то, что убило success-hallucination в этом прогоне — закрепить как правило.
Дедуп-стадия перед отчётом: группировать находки по корню (root-cause-cluster), а не по симптому/агенту. 5 «blank»-находок здесь = 2 корня (auth-gate + unguarded
error.response.status). Merge снижает шум для владельца и не теряет «нашли 4 агентами» как сигнал уверенности.Verifier-таймауты: (a) бюджетировать ВРЕМЯ под тяжёлые многоконтекстные/тайминговые сценарии (#7/#10) ОТДЕЛЬНО и приоритизировать data-loss класс выше косметики; (b) для tooling-suspected находок (#7) разрешать verifier'у завершаться вердиктом «inconclusive-by-design», а не TIMED_OUT, если агент уже сам дисконфирмировал; (c) кэшировать storage_state, чтобы 429-rate-limit не съедал бюджет повторных login'ов.
Зафиксировать tooling-trap'ы как known-issues в SKILL.md: (a)
set_offline/ctx.routeНЕ глушат fetch из SW-потока — GET, обработанный workbox NetworkOnly, отдаёт 200 при «offline»; верный оракул = enumerate caches (0/apientries ⇒ 200 = живой хит). (b) native HTML5 DnD (@atlaskit/pragmatic-drag-and-drop) не actuatable в headless — MOVE проверять чтением кода + REST, не выдавать «broken». (c) «tallest ProseMirror = body» ломается на свежих страницах — дизамбигуация поaria-label.Settle-дисциплина для синтетик-ввода у state-transition: не
delay=0burst в момент online↔offline переключения; settle 2–2.5s + cadence 60–120 мс/символ (вывод из само-дисконфирма #7). Внести вasync-and-state.md, чтобы не плодить ложные «потери символов».✅ Мета-фидбэк: timeout-гард сработал — 2 verifier'а уперлись в 9-мин кап и помечены TIMED_OUT, а не подвесили весь прогон (в прогоне 1 был залип 5.5ч). Trade-off: 2 находки остались непроверенными — на самых тяжёлых multi-context data-loss сценариях; стоит дать verifier'у на такие больше времени ИЛИ упрощённый детерминированный репро-харнесс.
🤖 web-test-orchestrator (process-trace)