Backend: add apt-get install libsqlcipher-dev before pip install so
pysqlcipher3 builds in the runner image.
Frontend: prep.test.ts was missing a qa mock (fetchFor now calls 5
endpoints in parallel; tests only mocked 4 — 5th returned undefined,
threw in catch, research.value never set). survey.test.ts: analyze()
was refactored from sync-result to async-task+poll; update test to
mock POST then poll completion.
Also remove Classic UI (Streamlit) button from AppNav — Streamlit is
deprecated and the button caused an unrecoverable redirect loop.
Insert Training at step 4 in WIZARD_STEPS (7→8), STEP_LABELS, and
STEP_ROUTES. Bump Identity→5, Inference→6, Search→7, Integrations→8 in
their respective saveStep calls. Cap resumeAt at 8. Await loadStatus()
before loadDbPairs() in FineTuneView onMounted so optedIn is set before
the early-exit guard runs.
Inserts a new optional Training Export step between Resume and Identity
in the setup wizard. Users can opt in to saving cover letters for
fine-tuning dataset export. Consent copy distinguishes local vs. cloud
storage. WIZARD_STEPS bumped to 7; router, and adjacent step
back/next navigation updated accordingly.
- CRITICAL: Remove X-CF-Tier header trust from _get_effective_tier; use
Heimdall in cloud mode and APP_TIER env var in single-tenant only
- HIGH: Add update_message_body helper + PUT /api/messages/{id} endpoint;
updateMessageBody store action; approveDraft now persists edits to DB
before calling approve so history always shows the final approved text
- Cleanup: Remove dead canDraftLlm ref, checkLlmAvailable function, and
v-else-if Enable LLM drafts link; show Draft reply button unconditionally
- MEDIUM: Cap GET /api/messages limit param with Query(ge=1, le=1000)
- Test: Update test_draft_without_llm_returns_402 to patch effective_tier
instead of sending X-CF-Tier header
- scripts/messaging.py: add logged_at param to create_message; use provided value or fall back to _now_utc()
- dev-api.py: add logged_at: Optional[str] = None to MessageCreateBody
- web/src/stores/messaging.ts: remove logged_at from Omit, add as optional intersection so callers can pass it through
- web/src/components/MessageLogModal.vue: pass logged_at in handleSubmit payload; move @keydown.esc from backdrop to modal-dialog (which holds focus); compute localNow fresh inside watch so it reflects actual open time
Move POST /api/jobs/:id/survey/analyze off the FastAPI worker thread
by routing it through the LLM task queue (same pattern as cover_letter,
company_research, resume_optimize).
- Extract prompt builders + run_survey_analyze() to scripts/survey_assistant.py
- Add survey_analyze to LLM_TASK_TYPES (task_scheduler.py) with 2.5 GB VRAM budget
(text mode: phi3:mini; visual mode uses vision service's own VRAM pool)
- Add elif branch in task_runner._run_task; result stored as JSON in error col
- Replace sync endpoint body with submit_task(); add GET /survey/analyze/task poll
- Update survey.ts store: analyze() now fires task + polls at 3s interval;
silently attaches to existing in-flight task when is_new=false
- SurveyView button label shows task stage while polling
Fixes load-test spike: ~22 greenlets blocking on LLM inference at 100 concurrent
users, causing 90s poll timeouts on cover_letter and research tasks.
Extends the resume Pinia store with EducationEntry interface, four new
refs (career_summary, education, achievements, lastSynced), education
CRUD helpers, and load/save wiring for all new fields. lastSynced is
set to current ISO timestamp on successful save.
API (dev-api.py):
- GET /api/settings/fine-tune/pairs — list pairs from JSONL with index/instruction/source_file
- DELETE /api/settings/fine-tune/pairs/{index} — remove a pair and rewrite JSONL
- POST /api/settings/fine-tune/submit — now queues prepare_training task (replaces UUID stub)
- GET /api/settings/fine-tune/status — returns pairs_count from JSONL (not just DB task)
Store (fineTune.ts):
- TrainingPair interface
- pairs, pairsLoading refs
- loadPairs(), deletePair() actions
Vue (FineTuneView.vue):
- Step 2 shows scrollable pairs list with instruction + source file
- ✕ button on each pair calls deletePair(); list/count update immediately
- loadPairs() called on mount