(medium) scrape/all/page.tsx: смена filter не сбрасывает logsRunId — стейл-стейт показывает логи чужого прогона #1402

Closed
opened 2026-06-15 05:53:32 +00:00 by bot-backend · 1 comment
Collaborator

Severity: medium · Категория: frontend · Файл: frontend/src/app/admin/scrape/all/page.tsx:73, 85-96, 160-173, 343-345

frontend/src/app/admin/scrape/all/page.tsx:73 (state), 85-96 (query), 158-173 (табы), 343-345 (заголовок). setFilter (стр.163) не сбрасывает logsRunId. Сценарий: filter=kn, клик «логи» kn-run #12 → logsRunId=12; затем клик таба «NSPD» → запрос становится scraper_type=nspd&run_id=12. Поскольку run_id не уникален между скраперами (независимые BIGSERIAL PK, см. SQL), запрос вернёт логи nspd-run #12 — непустой, но не относящийся к исходному клику результат, а заголовок «· фильтр run_id=12» (стр.345) молча указывает на прогон другого скрапера. queryKey ["unified-logs", filter, logsRunId] (стр.86) переиспользует logsRunId при смене filter. Чинить: сбрасывать setLogsRunId("") внутри обработчика setFilter (или в useEffect на изменение filter). Это тот же корневой класс (run_id не scoped на scraper), что и находка [0], но иное проявление — стейл-стейт при переключении таба.

Почему баг: logsRunId — независимый кусок состояния, который queryKey ["unified-logs", filter, logsRunId] переиспользует при смене filter. Поскольку run_id не уникален между скраперами (см. соседнюю находку), один и тот же номер валиден для nspd, и запрос вернёт непустой, но не относящийся к исходному клику результат. Пользователь видит логи, считая их теми, что открывал.

Как чинить: Сбрасывать logsRunId при смене filter (в onClick таба: setFilter(t); setLogsRunId("")), либо хранить scraper_type вместе с run_id и игнорировать фильтр логов, если он не совпадает с активным скрапером.


deep-audit «армия ботов 2» · verify+harden, confidence 0.82 · unit U68

**Severity:** medium · **Категория:** frontend · **Файл:** `frontend/src/app/admin/scrape/all/page.tsx:73, 85-96, 160-173, 343-345` frontend/src/app/admin/scrape/all/page.tsx:73 (state), 85-96 (query), 158-173 (табы), 343-345 (заголовок). setFilter (стр.163) не сбрасывает logsRunId. Сценарий: filter=kn, клик «логи» kn-run #12 → logsRunId=12; затем клик таба «NSPD» → запрос становится `scraper_type=nspd&run_id=12`. Поскольку run_id не уникален между скраперами (независимые BIGSERIAL PK, см. SQL), запрос вернёт логи nspd-run #12 — непустой, но не относящийся к исходному клику результат, а заголовок «· фильтр run_id=12» (стр.345) молча указывает на прогон другого скрапера. queryKey ["unified-logs", filter, logsRunId] (стр.86) переиспользует logsRunId при смене filter. Чинить: сбрасывать setLogsRunId("") внутри обработчика setFilter (или в useEffect на изменение filter). Это тот же корневой класс (run_id не scoped на scraper), что и находка [0], но иное проявление — стейл-стейт при переключении таба. **Почему баг:** logsRunId — независимый кусок состояния, который queryKey ["unified-logs", filter, logsRunId] переиспользует при смене filter. Поскольку run_id не уникален между скраперами (см. соседнюю находку), один и тот же номер валиден для nspd, и запрос вернёт непустой, но не относящийся к исходному клику результат. Пользователь видит логи, считая их теми, что открывал. **Как чинить:** Сбрасывать logsRunId при смене filter (в onClick таба: setFilter(t); setLogsRunId("")), либо хранить scraper_type вместе с run_id и игнорировать фильтр логов, если он не совпадает с активным скрапером. --- <sub>deep-audit «армия ботов 2» · verify+harden, confidence 0.82 · unit U68</sub>
bot-backend added the
week ревью 1
label 2026-06-15 05:53:32 +00:00
bot-backend added the
scope/frontend
label 2026-06-15 11:01:59 +00:00
Owner

🔍 week ревью 1 — верификация (ПОДТВЕРЖДЕНО)

Текущее состояние кода: frontend/src/app/admin/scrape/all/page.tsx:73 (const [logsRunId, setLogsRunId] = useState<number | "">("")), :85-96 (logs query, queryKey ["unified-logs", filter, logsRunId] стр. 86, params.set("scraper_type", filter) стр. 89 + params.set("run_id", String(logsRunId)) стр. 90), :163 (onClick={() => setFilter(t)} — без сброса logsRunId), :295 (onClick={() => setLogsRunId(r.run_id)}), :343-345 (заголовок «· фильтр run_id={logsRunId}»).

Корень: setFilter (стр. 163) меняет filter, но не сбрасывает logsRunId. queryKey включает оба → при переключении таба прежний run_id переиспользуется с новым scraper_type. Так как run_id не уникален между скраперами (независимые BIGSERIAL PK в kn_scrape_runs/nspd_scrape_runs/objective_scrape_runs, см. data/sql/74_dedupe_unified_views.sql:212-237 — view просто UNION без префиксации run_id), запрос вернёт непустой, но не относящийся к исходному клику результат, а заголовок «run_id=N» молча указывает на прогон другого скрапера.

Что править:

  • В обработчике таба сбрасывать оба стейта: onClick={() => { setFilter(t); setLogsRunId(""); }} (стр. 163). Либо useEffect на изменение filtersetLogsRunId("").
  • Надёжнее: хранить scraper_type вместе с run_id (напр. {type, id}) и игнорировать лог-фильтр, если его scraper_type ≠ активному filter.

Что посмотреть:

  • Код: admin/scrape/all/page.tsx:73,86,90,163,295,345; view v_scrape_log_unified (74_dedupe_unified_views.sql:246-252) — log_id/run_id не scoped по scraper_type; родственная находка (run_id не scoped) — тот же корневой класс.
  • Vault: релевантных заметок не найдено.
**🔍 week ревью 1 — верификация (ПОДТВЕРЖДЕНО)** **Текущее состояние кода:** `frontend/src/app/admin/scrape/all/page.tsx:73` (`const [logsRunId, setLogsRunId] = useState<number | "">("")`), `:85-96` (`logs` query, queryKey `["unified-logs", filter, logsRunId]` стр. 86, `params.set("scraper_type", filter)` стр. 89 + `params.set("run_id", String(logsRunId))` стр. 90), `:163` (`onClick={() => setFilter(t)}` — без сброса logsRunId), `:295` (`onClick={() => setLogsRunId(r.run_id)}`), `:343-345` (заголовок «· фильтр run_id={logsRunId}»). **Корень:** `setFilter` (стр. 163) меняет `filter`, но не сбрасывает `logsRunId`. queryKey включает оба → при переключении таба прежний `run_id` переиспользуется с новым `scraper_type`. Так как `run_id` не уникален между скраперами (независимые BIGSERIAL PK в `kn_scrape_runs`/`nspd_scrape_runs`/`objective_scrape_runs`, см. `data/sql/74_dedupe_unified_views.sql:212-237` — view просто UNION без префиксации run_id), запрос вернёт непустой, но не относящийся к исходному клику результат, а заголовок «run_id=N» молча указывает на прогон другого скрапера. **Что править:** - В обработчике таба сбрасывать оба стейта: `onClick={() => { setFilter(t); setLogsRunId(""); }}` (стр. 163). Либо `useEffect` на изменение `filter` → `setLogsRunId("")`. - Надёжнее: хранить `scraper_type` вместе с `run_id` (напр. `{type, id}`) и игнорировать лог-фильтр, если его scraper_type ≠ активному filter. **Что посмотреть:** - Код: `admin/scrape/all/page.tsx:73,86,90,163,295,345`; view `v_scrape_log_unified` (`74_dedupe_unified_views.sql:246-252`) — `log_id`/`run_id` не scoped по scraper_type; родственная находка (run_id не scoped) — тот же корневой класс. - Vault: релевантных заметок не найдено.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#1402
No description provided.