knowledge_base_service and analysis_service were local variables inside
the lifespan() function — not module-level exports. Importing them via
'from app.main import ...' always failed with ImportError → 500.
Use request.app.state (same pattern as analysis_routes.py) instead.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The background task runs in its own DB session but the job row hadn't been
committed yet by the request session. The background task couldn't find
the job, causing FK violations when trying to create spec_versions.
Fix: explicitly commit the request session after creating the job and
before adding the background task, ensuring the job row is visible.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Frontend: only treat parsing_documents/distilling as actively running;
pending jobs older than 2 minutes are ignored as stale
- Backend: add fail_stale_jobs() that marks pending/active jobs older than
5 minutes as failed before checking for active jobs in trigger_processing
- Prevents UI from getting stuck on old jobs that never completed
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Create DB record first to get the auto-generated UUID, then use that ID
for the storage key. Previously a separate UUID was generated for storage
but the DB record got a different one, causing file retrieval to fail
during processing.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>