0.134.52

Security (C-M-5 — Re-indexing admin pipeline, финал)

Закрытие последней незакрытой задачи из backend-аудита (v0.134.12). В v0.134.46 инфраструктура (Store + Reindexer) была готова, но без HTTP/WS-интеграции. Теперь admin может запустить фоновую переиндексацию эмбеддингов при смене модели/размерности, видеть live-прогресс и отменять.

Backend

  • cmd/taigaclaw/main.go — wiring Reindexer рядом с SwappableEmbedder. SetEventBroadcaster(wsChannel.Hub()) — события прогресса транслируются через WSHub. reindexer.Cancel() в gracefulShutdown для корректной остановки при SIGTERM.
  • internal/server/handler/embeddings.go (новый) — EmbeddingsHandler с 4 эндпоинтами:
  • POST /api/v1/admin/embeddings/reindex{kind: "all"|"facts"|"chunks"} → 202 + job (409 если уже идёт, 400 если kind невалидный).
  • GET /api/v1/admin/embeddings/reindex/status — текущий active job или {"job": null}.
  • POST /api/v1/admin/embeddings/reindex/cancel — 204 (идемпотентно).
  • GET /api/v1/admin/embeddings/reindex/jobs?limit=N — история (default 50, max 200). Все под RequireGlobalAdmin.
  • internal/server/router.go — регистрация новой группы /admin/embeddings/reindex/*.
  • internal/channels/websocket.go — добавлены Hub() getter на WebSocketChannel и BroadcastReindexEvent на WSHub. В WSOutboundEvent добавлено поле Data json.RawMessage для произвольного JSON-payload (вместо опасного использования Tools).
  • internal/embeddings/reindex.goEventBroadcaster интерфейс + SetEventBroadcaster setter + emit() helper. Broadcast событий в Start/run/fail/cancelJob/progress. Также фикс race condition: Start отпускает r.mu перед go r.run(...) (раньше блокировал сам себя через re-entrant lock в emit). Фикс cancel flow: EnsureVectorDimensions/ListAgents/ListFacts/ListChunks теперь проверяют context.Canceled и вызывают cancelJob вместо fail. fail/cancelJob используют свежий context.Background() (5s timeout) для финального UpdateReindexJobStatus — run-ctx уже отменён в этот момент.

Frontend

  • web/src/lib/api/types.ts — типы ReindexJob, ReindexStatusResponse, ReindexJobsResponse, ReindexEventData.
  • web/src/lib/api/endpoints.tsapi.embeddings.{reindex, reindexStatus, reindexCancel, reindexJobs} (4 метода).
  • web/src/lib/stores/reindex.svelte.ts (новый) — $state-class ReindexStore с полями currentJob/jobs/loading/starting/ cancelling/error и методами loadStatus/loadJobs/start/ cancel/startPolling/subscribe/handleWSEvent/destroy. Опциональная WS-подписка через callback — ChatStore или другая WS-инстанция может прокидывать события reindex.* через handleWSEvent. Polling (2 сек) по умолчанию, останавливается через stopPolling()/destroy().
  • web/src/lib/stores/reindex.svelte.test.ts (новый) — 16 vitest-тестов: loadStatus/loadJobs/start/cancel, WS-события (started/progress/ completed/failed/cancelled), subscribe/unsubscribe, polling.
  • web/src/lib/features/system/ReindexSection.svelte (новый) — UI-компонент: статус-карточка (idle/running/completed/failed/cancelled) с прогресс-баром, кнопки Start/Cancel, select kind (all/facts/chunks), история последних 10 job’ов.
  • web/src/routes/settings/advanced/+page.svelte — вставка <ReindexSection /> в начало страницы (видимо только админу через +layout.svelte гард).

Tests

  • internal/server/handler/embeddings_test.go (новый) — 10 unit-тестов с real SQLiteStore + Reindexer + mock embedder: Start (default/ explicit kind/invalid/already-running), Status (no-active/with-active), Cancel (no-active/with-active), Jobs (history/limit-validation).
  • web/src/lib/stores/reindex.svelte.test.ts (новый) — 16 vitest-тестов с моками api.embeddings.*.

Documentation

  • docs/audit/backend-2026-06.md:
  • C-M-5 — ✅ FIXED v0.134.52 с перечислением всех изменений.
  • C-M-2 — VERDICT-блок «ложная тревога» (по аналогии с C-H-7, C-SC-1): compactAgent не вызывается из user-path, только из AutoCompactService (фоновый ticker) и handleCompact (явная слэш-команда с 5-мин таймаутом в tracked-горутине).