docs: library indexing is scheduled and on request; panel note matches
All checks were successful
Forgejo Docker Build / Root app tests (push) Successful in 52s
Forgejo Docker Build / Build Docker image (push) Successful in 9s
Forgejo Docker Build / End-to-end (browser) (push) Successful in 5s

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
This commit is contained in:
Daniel 2026-09-13 16:34:16 +02:00
parent 34c495b5d8
commit e23d35a570
3 changed files with 14 additions and 11 deletions

View file

@ -207,18 +207,19 @@ Add or update tests when changing:
- model discovery or settings behavior. - model discovery or settings behavior.
## Library indexing runs when asked, not on a timer ## Library indexing: on a schedule, and on request
The clinical library lives in Nextcloud folders and is indexed by the The clinical library lives in Nextcloud folders and is indexed by the
clinical-assist indexer. It used to rescan every five minutes; a scan that clinical-assist indexer, which reconciles them every five minutes
also walked ten thousand news-feed items took half an hour, so the indexer was (`VECTOR_SYNC_SCAN_INTERVAL`). A scan used to walk ten thousand news-feed
never idle. It now reconciles once when it starts and then only when an admin items too and took half an hour; the News and Deck passes are now off, so a
presses **Run indexing now** (Admin → Clinical Assistant → Library index). scan is the files and notes only. **Run indexing now** (Admin → Clinical
Assistant → Library index) asks for a scan without waiting for the timer.
A reconciliation lists the library folders, queues documents that are new or A reconciliation lists the library folders, queues documents that are new or
whose modification time changed, and drops the index rows of documents that whose modification time changed, and drops the index rows of documents that
are gone — after a second consecutive scan confirms the absence, so one are gone — after the absence has persisted for one and a half scan
listing that happened to fail deletes nothing. Documents already indexed and intervals, so one listing that happened to fail deletes nothing. Documents already indexed and
unchanged are not touched, and nothing is re-extracted. unchanged are not touched, and nothing is re-extracted.
The button calls `POST /api/v1/vector-sync/scan` on the indexer with a bearer The button calls `POST /api/v1/vector-sync/scan` on the indexer with a bearer
@ -231,8 +232,10 @@ settings are empty):
| `clinical_assistant.indexer_token` | `CLINICAL_ASSISTANT_INDEXER_TOKEN` | none — the button refuses without one | | `clinical_assistant.indexer_token` | `CLINICAL_ASSISTANT_INDEXER_TOKEN` | none — the button refuses without one |
The token must equal `VECTOR_SYNC_TRIGGER_TOKEN` in the indexer's environment. The token must equal `VECTOR_SYNC_TRIGGER_TOKEN` in the indexer's environment.
On the indexer side the mode is `VECTOR_SYNC_ON_DEMAND=true`; `VECTOR_SYNC_SCAN_NEWS` On the indexer side `VECTOR_SYNC_SCAN_NEWS` and `VECTOR_SYNC_SCAN_DECK` are
and `VECTOR_SYNC_SCAN_DECK` are `false` for a documents-only library. Under `false` for a documents-only library; `VECTOR_SYNC_ON_DEMAND=true` would stop
the timer and leave only the button (deletions then need two consecutive
scans). Under
[lockdown](authentication.md#lockdown-the-admin-panel-as-view-only) the button [lockdown](authentication.md#lockdown-the-admin-panel-as-view-only) the button
still works — it is an operation, not a setting — but the address and token still works — it is an operation, not a setting — but the address and token
are read-only. are read-only.

View file

@ -420,7 +420,7 @@
<button type="button" class="btn btn-secondary btn-sm" id="btn-assistant-index-now"><i class="fas fa-sync"></i> Run indexing now</button> <button type="button" class="btn btn-secondary btn-sm" id="btn-assistant-index-now"><i class="fas fa-sync"></i> Run indexing now</button>
<button type="button" class="btn btn-link btn-sm" id="btn-assistant-index-refresh">Refresh status</button> <button type="button" class="btn btn-link btn-sm" id="btn-assistant-index-refresh">Refresh status</button>
</div> </div>
<span class="admin-note">Indexing no longer runs on a timer. This queues documents added or changed in the library folders, drops what has been removed (after a second scan confirms it), and leaves everything else alone.</span> <span class="admin-note">The indexer reconciles the library folders on its own schedule; this asks for a scan right now. New and changed documents are queued, removed documents are dropped once a second scan confirms it, everything already indexed is left alone.</span>
<details style="margin-top:4px;"> <details style="margin-top:4px;">
<summary style="cursor:pointer;font-size:13px;">Indexer address and token</summary> <summary style="cursor:pointer;font-size:13px;">Indexer address and token</summary>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:6px;"> <div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:6px;">

View file

@ -281,5 +281,5 @@ test('the library index button is an operation, allowed under lockdown, and the
assert.doesNotMatch(admin.slice(admin.indexOf("router.get('/config/library-index'"), admin.indexOf("router.post('/config/library-index/scan'")), /token: target\.token/, 'the status reply must not carry the token'); assert.doesNotMatch(admin.slice(admin.indexOf("router.get('/config/library-index'"), admin.indexOf("router.post('/config/library-index/scan'")), /token: target\.token/, 'the status reply must not carry the token');
const js = read('public/js/admin/clinicalAssistant.js'); const js = read('public/js/admin/clinicalAssistant.js');
assert.match(js, /setValue\('assistant-indexer-token', ''\)/); assert.match(js, /setValue\('assistant-indexer-token', ''\)/);
assert.match(read('docs/clinical-assistant.md'), /## Library indexing runs when asked/); assert.match(read('docs/clinical-assistant.md'), /## Library indexing: on a schedule, and on request/);
}); });