WEB-421 · Задача · — · web
P1 ПРОД (prodeyes1): загруженный источник не открывается глазами — файл виден в списке, но содержимое прочитать нельзя
Закрыт
P2
ведёт: —
Доказательства
Обход прода PRODEYES1 (M4, 28.08, линия l64, QA-учётка qa-evisual): файл загружен (метка PRODEYES1_SEARCH_MARKER_7429, ~/prodeyes1-test.txt на M4), карточка источника видна, но открыть и прочитать содержимое нельзя. Скрины /Users/milamarty/prodeyes1-shots/ (05-source-open, 06-source-card-click). Отчёт /Users/milamarty/PRODEYES1-REPORT.md. Перепроверить на l66 — волна l66probe грузит второй файл (метка L66PROBE_MARKER_5137).
---
## 2026-08-29 06:55Z — ACC421SRC: NO-GO по приватности кэша (функционально открывается)
Принято: цепочка чтения доходит до реального GET-маршрута, тело проходит через ACL-bound resolver и отображается; прямой adversarial ACL-прогон утечки не показал.
БЛОКЕР: все три маршрута, отдающие тело источника, отвечают БЕЗ Cache-Control: private, no-store, клиентские GET не задают cache:'no-store'. Для одного URL это позволяет вернуть ранее закэшированный ответ ДРУГОГО владельца до повторной проверки ACL. С учётом WEB-047 (уже была утечка кэша между владельцами) — критично.
Круг WEB421SRC2 заряжен (queue/375): заголовки на всех трёх маршрутах + ЕДИНАЯ точка формирования ответа с телом (чтобы четвёртый маршрут не появился без заголовков) + аудит ВСЕХ маршрутов, отдающих пользовательское содержимое (вложения, экспорт, превью) + тесты на смену владельца по тому же URL.
---
## 2026-08-29 08:35Z — ACC421SRC2: NO-GO. Аудит ШИРЕ нашёл 8 голых маршрутов с личными данными
Принято: три source-body маршрута + большие группы (detail/preview/graph/wiki, media/video/podcast-audio/telephony-audio/meeting-transcript, export/pdf/user-export/GDPR/admin/reports/factcheck/deep-research) используют privateContentJson (Cache-Control: private, no-store + Vary: Cookie); клиентские чтения — cache:'no-store'. Негативный baseline на 1c62f899 подтверждён.
БЛОКЕР — авторизованные GET с пользовательским содержимым БЕЗ приватных заголовков: /api/comments?noteId (content, route.ts:59-64); /api/reports/archive (свои generated sources, content, имена notebook, download URLs, :56-63 и :344-354); /api/podcast и /api/podcast/[id]; /api/podcast/feed (+viewerHasLiked, зависит от сессии); /api/podcast/feed/rss?userId=me; /api/chronicle/weekly (в коде комментарий «Personal data → uncacheable», а заголовков нет); /api/analytics/virality (фрагменты social-post content); /api/analytics/timeline (названия notebook).
Круг WEB421SRC3 (queue/388): все восемь через приватный контракт + тест-страж на появление новых голых маршрутов + собственный аудит ещё шире.
---
## 2026-08-29 12:10Z — ✅ ACC421SRC4: GO. Приватность отдачи пользовательских данных закрыта КЛАССОМ
Четыре круга: (1) источник открывается + ACL; (2) приватные заголовки на трёх source-body маршрутах; (3) восемь голых маршрутов (комментарии, архив отчётов, подкасты+RSS, хроника, аналитика); (4) новый пласт — /api/settings/connections и семь /api/admin/*, где причина была в другом механизме аутентификации (getSession()/requireAdmin() мимо auth(handler)).
Принято: оба механизма покрыты, страж ловит появление голого маршрута. Кандидат следующей посадки.
[29.08 ЖИВАЯ ПРОВЕРКА НА ПРОДЕ l68 — РАБОТАЕТ]
Загрузил web421-src.txt (176 байт) через Add Source, кликнул карточку — открылось окно «Edit Document: web421-src.txt» с ПОЛНЫМ содержимым на экране, дословно видны все пять строк включая маркер MARKER-XQ7714-VISIBLE-CONTENT. Ошибок открытия в серверном логе нет. Лог загрузки: [ingest/sourceWriter] source queued for async indexing, contentLength 176, reason async-enrichment-enabled; source indexing left for external worker.
⚠️ ПОБОЧНАЯ НАХОДКА (не закрывает тикет, но требует отдельной починки): на ОДИН И ТОТ ЖЕ файл выдаются ДВЕ РАЗНЫЕ формулировки состояния индексации. В одном окне мягкая «The file is readable; search indexing is still in progress.», в другом красная с сырым текстом исключения: «Not searchable: The argument 'filename' must be a file URL object, file URL string, or absolute path string. Received undefined». Пользователю нельзя показывать сырой текст ошибки среды выполнения.
[29.08 ЗАКРЫТ по живой пробе] Загруженный источник открывается глазами: файл виден в списке (счётчик вырос до 5 sources) и его содержимое полностью отрисовано в окне «Edit Document» — все строки читаются, включая контрольный маркер. Ошибок открытия в серверном логе нет. Побочная находка (два разных текста состояния индексации на один файл, один из них — сырой текст исключения среды выполнения) вынесена в отдельную волну IDXBANNER, к предмету этого тикета не относится.
[29.08 ПОБОЧНАЯ НАХОДКА ЗАКРЫТА — ACCIDXBANNER_VERDICT=GO, коммит 2d01a4ccc6e22cf26e60fe6a820f97956f1d076f]
Сырые тексты исключений убраны из интерфейса. Пользователю больше не показывают «Not searchable: The argument 'filename' must be a file URL object... Received undefined» и подобное — состояние индексации теперь классифицировано и берётся из одного источника, поэтому просмотрщик и редактор не расходятся. Факт отказа при этом не спрятан: состояние «упало» отличимо от «идёт» и «готово».
Воркер
не привязан — привязать:
curl -X POST https://bugs.wool2.online/api/web/assign -H 'content-type: application/json' \
-d '{"issueId":"WEB-421","session":"<имя tmux-сессии>","host":"m4"}'
Обновлён
2026-08-29T10:45:25.327Z