fix: WS5 hazards batch - CORS, scheduler auth, reranker dedupe, wiring, write txns

- CORS: drop allow_credentials (wildcard origin + credentials told
  browsers to attach credentials for any site); origins configurable via
  CORS_ALLOW_ORIGINS (default * is safe without credentials). Verified
  live: preflight no longer advertises access-control-allow-credentials.
- Scheduler tasks: auth moved from a plain Authorization header (which
  the Scheduler's rest_api_executor does NOT env-substitute) to its
  auth {type: bearer, token: ${LIBRARY_API_KEY}} block, substituted from
  the Scheduler's own environment at execution time. The registrar no
  longer resolves the real key client-side, so it can never be persisted
  into the scheduled_tasks.config JSONB column. Also fixed: JSON bodies
  moved from the ignored "body" key to "payload" (the executor only
  reads config["payload"], so the tasks would have POSTed empty bodies
  and failed required-user validation).
- Reranker: parsed ranking indices are deduplicated preserving first
  occurrence (an LLM answer like "3,3,1" duplicated a result).
- HybridRAG wiring consolidated into dependencies.get_hybrid_rag_service
  (now including volatile_service); the inline copies in /query/hybrid
  and /wiki/pages/smart-create are gone - smart-create previously ran
  without the volatile leg, and the singleton was unused.
- Remaining Neo4j writes (GraphService ingestion/deletes/purges/entity
  mentions, webhook rename+delete cleanup, document-sync _index_graph,
  consolidation mark-processed/add-entity) moved from auto-commit
  execute_query to execute_write managed transactions with retry.

Verified end-to-end on the local dev server as llm_tester: /query/hybrid
200 with all five legs ok (volatile now active), background persistence
landed as one transaction.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QbFZyDvYksazX6nYQYZ67L
This commit is contained in:
2026-07-14 14:50:03 +02:00
co-authored by Claude Fable 5
parent 69e6a01e65
commit 9ceec1464a
19 changed files with 159 additions and 144 deletions
+27 -14
View File
@@ -12,7 +12,6 @@ SCHEDULER_URL=http://<scheduler-host>:8090 \
# Actually register/update the tasks (deploy checklist step):
SCHEDULER_URL=http://<scheduler-host>:8090 \
LIBRARY_API_KEY=<the library-desk API key> \
.venv/bin/python scripts/register_scheduler_tasks.py --execute
```
@@ -21,8 +20,15 @@ Conventions:
- All tasks call the **production** library-desk container
(`http://library-desk:8089`) with the explicit production tenant
`user=jpmschweitzer` (there is no default tenant — Phase B).
- `${LIBRARY_API_KEY}` is a placeholder for the library-desk API key
(`LIBRARY_API_KEY` in the container env). Never commit the real value.
- `${LIBRARY_API_KEY}` is a literal placeholder stored in the task's
`auth.token` field. The Scheduler's `rest_api_executor` substitutes
`${ENV_VAR}` placeholders from **its own environment at execution
time** (it substitutes `url`/`payload`/`auth` — NOT plain `headers`),
so the raw key is never stored in the `scheduled_tasks.config` JSONB
column. The **Scheduler container** must have `LIBRARY_API_KEY` in its
environment. Never commit or register the real value.
- The JSON body goes in `config.payload` (the executor ignores a `body`
key).
- Schedule fields use the Scheduler's convention: `-1` = every,
`day_of_week`: `0` = Monday … `6` = Sunday.
@@ -53,11 +59,14 @@ in Redis for the weekly quality report.
"method": "POST",
"url": "http://library-desk:8089/maintenance/integrity-check",
"headers": {
"Content-Type": "application/json",
"Authorization": "Bearer ${LIBRARY_API_KEY}"
"Content-Type": "application/json"
},
"body": {
"payload": {
"user": "jpmschweitzer"
},
"auth": {
"type": "bearer",
"token": "${LIBRARY_API_KEY}"
}
}
}
@@ -88,14 +97,17 @@ latest integrity results, and writes the dated report page to
"method": "POST",
"url": "http://library-desk:8089/maintenance/quality-report",
"headers": {
"Content-Type": "application/json",
"Authorization": "Bearer ${LIBRARY_API_KEY}"
"Content-Type": "application/json"
},
"body": {
"payload": {
"user": "jpmschweitzer",
"stale_days": 30,
"dedup_threshold": 0.9,
"write_page": true
},
"auth": {
"type": "bearer",
"token": "${LIBRARY_API_KEY}"
}
}
}
@@ -103,7 +115,7 @@ latest integrity results, and writes the dated report page to
## 3. Daily Paperless orphan cleanup — 05:00
Hits the **existing** cleanup endpoint (query parameters, empty body).
Hits the **existing** cleanup endpoint (query parameters, empty payload).
`dry_run=false` deletes vectors/graph nodes for documents that were
removed from Paperless-ngx.
@@ -125,10 +137,11 @@ removed from Paperless-ngx.
"config": {
"method": "POST",
"url": "http://library-desk:8089/maintenance/cleanup/paperless?user=jpmschweitzer&dry_run=false",
"headers": {
"Authorization": "Bearer ${LIBRARY_API_KEY}"
},
"body": {}
"payload": {},
"auth": {
"type": "bearer",
"token": "${LIBRARY_API_KEY}"
}
}
}
```