# Changelog All notable changes to Library Desk will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ## [1.9.2] - 2026-08-16 ### Fixed - `/health` no longer reports the whole service unhealthy because one dependency is merely slow. Its five probes (neo4j, qdrant, wikijs, searxng, ollama) previously ran one after another with no timeout on neo4j or qdrant, so a single hung dependency could block the response past the container healthcheck's 10s timeout and get the container marked unhealthy for a reason unrelated to its own liveness. Each probe is now bounded at 2s and all five run concurrently, so one hanging dependency is reported unhealthy on its own without holding up the others or the response. - Internal-only: the three probes `check_service_health()` also computes (paperless, system_settings, scheduler) received the same bounding and concurrency, for consistency and because they carried the identical unbounded-hang risk internally. This has no visible effect today — none of the three is currently returned by `/health` — but protects a future caller that does read them. ## [1.9.1] - 2026-08-08 ### Fixed - The Wiki.js change listener now survives a database restart. It held a single `LISTEN` connection with no supervision, so when the connection dropped it was gone permanently while `running` stayed `True` — the service kept reporting healthy and silently stopped indexing every page edit until someone restarted the container. This happened for real on 2026-08-08 when `postgres-shared` was redeployed. It now detects the drop via asyncpg's termination callback and reconnects with bounded exponential backoff (1s doubling to a 60s cap), retrying indefinitely because a database in maintenance does come back and giving up would recreate the same silent deafness. - `WikiChangeListener.running` is derived from the live connection instead of being assigned once at startup, so it can no longer claim a subscription that does not exist. ### Added - `/health` reports the change listener under `services.wiki_listener` (`subscribed`, `reconnects`, `last_gap_seconds`). Nothing previously exposed its state anywhere, which is why a dead listener went unnoticed. It is deliberately excluded from the overall healthy/degraded verdict: it recovers on its own, and flipping the container unhealthy for the duration of a database outage would add a restart loop to an incident rather than information. - On reconnect the listener logs the outage duration and warns that `NOTIFY` events emitted during the gap were lost and cannot be replayed, pointing at `POST /maintenance/integrity-check` to reconcile. A reconciliation pass is not performed automatically — tenant attribution for a changed page is non-trivial here, and guessing it wrong writes content into the wrong user's namespace. ## [1.9.0] - 2026-07-20 ### Security - The Wiki.js integration buttons no longer embed an API key in the browser. The re-index and entity-link endpoints now authenticate via the NPM `/library-desk/` proxy (Authentik session for external users, LAN bypass for internal), verified by a trusted proxy marker header. The previously-embedded key was a full-privilege key served to every wiki visitor; it has been rotated out of service. - `verify_api_key` now uses a constant-time comparison. ### Changed - `static/wikijs-integration.js` calls library-desk same-origin (`/library-desk/...`) with `credentials: same-origin` and no `Authorization` header. Update the Wiki.js code-injection snippet to `