Commit graph

380 commits

Author SHA1 Message Date
fb9f751321 chore: bump circuitforge-core dep comment to >=0.8.0 (orch split)
Some checks failed
CI / test (push) Failing after 22s
2026-04-04 22:49:03 -07:00
ac3e97d6c8 feat(#62): Fine-Tune tab — training pair management + real submit
Some checks failed
CI / test (push) Failing after 21s
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
2026-04-04 22:30:16 -07:00
42c9c882ee feat(#59): LLM-assisted generation for all settings form fields
Some checks failed
CI / test (push) Failing after 21s
API endpoints (dev-api.py):
- POST /api/settings/profile/generate-summary → {summary}
- POST /api/settings/profile/generate-missions → {mission_preferences}
- POST /api/settings/profile/generate-voice → {voice}
- POST /api/settings/search/suggest → replaces stub; handles titles/locations/exclude_keywords

Vue (MyProfileView.vue):
- Generate ✦ button on candidate_voice textarea (was missing)

Vue (SearchPrefsView.vue + search store):
- Suggest button for Exclude Keywords section (matches titles/locations pattern)
- suggestExcludeKeywords() in search store
- acceptSuggestion() extended to 'exclude' type
2026-04-04 22:27:20 -07:00
4f825d0f00 feat(#45): manual theme switcher (light/dark/solarized/colorblind-safe)
Some checks failed
CI / test (push) Failing after 18s
- theme.css: explicit [data-theme] blocks for light, dark, solarized-dark,
  solarized-light, colorblind (Wong 2011 palette); auto-dark media query
  updated to :root:not([data-theme]) so explicit themes always win
- useTheme.ts: singleton composable — setTheme(), restoreTheme(), initTheme();
  persists to localStorage + API; coordinates with hacker mode exit
- AppNav.vue: theme <select> in sidebar footer; exitHackerMode now calls
  restoreTheme() instead of deleting data-theme directly
- useEasterEgg.ts: hacker mode toggle-off calls restoreTheme()
- App.vue: calls initTheme() on mount before restore()
- dev-api.py: POST /api/settings/theme endpoint persists to user.yaml
2026-04-04 22:22:04 -07:00
64554dbef1 feat(#43): numbered SQL migration runner (Rails-style)
Some checks failed
CI / test (push) Failing after 19s
- migrations/001_baseline.sql: full schema baseline (all tables/cols)
- scripts/db_migrate.py: apply sorted *.sql files, track in schema_migrations
- Wired into FastAPI startup and Streamlit app.py startup
- Replaces ad-hoc digest_queue CREATE in _startup()
- 6 tests covering apply, idempotency, partial apply, failure rollback
- docs/developer-guide/contributing.md: migration authoring guide
2026-04-04 22:17:42 -07:00
065c02feb7 feat(vue): Home dashboard parity — Enrich button, Danger Zone, setup banners (closes #57)
Some checks failed
CI / test (push) Failing after 20s
API additions (dev-api.py):
- GET /api/tasks — list active background tasks
- DELETE /api/tasks/{task_id} — per-task cancel
- POST /api/tasks/kill — kill all stuck tasks
- POST /api/tasks/discovery|email-sync|enrich|score|sync — queue/trigger each workflow
- POST /api/jobs/archive — archive by statuses array
- POST /api/jobs/purge — hard delete by statuses or target (email/non_remote/rescrape)
- POST /api/jobs/add — queue URL imports
- POST /api/jobs/upload-csv — upload CSV with URL column
- GET  /api/config/setup-banners — list undismissed onboarding hints
- POST /api/config/setup-banners/{key}/dismiss — dismiss a banner

HomeView.vue:
- 4th WorkflowButton: "Fill Missing Descriptions" (always visible, not gated on enrichment_enabled)
- Danger Zone redesign: scope radio (pending-only vs pending+approved), Archive & reset (primary)
  vs Hard purge (secondary), inline confirm dialogs, active task list with per-task cancel,
  Kill all stuck button, More Options (email purge / non-remote / wipe+rescrape)
- Setup banners: dismissible onboarding hints pulled from /api/config/setup-banners,
  5-second polling for active task list to stay live

app/Home.py:
- Danger Zone redesign: same scope radio + archive/purge with confirm steps
- Background task list with per-task cancel and Kill all stuck button
- More options expander (email purge, non-remote, wipe+rescrape)
- Setup banners section at page bottom
2026-04-04 22:05:06 -07:00
53b07568d9 feat(vue): accumulated parity work — Q&A, Apply highlights, AppNav switcher, cloud API
API additions (dev-api.py split across this and next commit):
- /api/jobs/{job_id}/qa GET/PATCH/suggest — Interview Prep answer storage + LLM suggestions
- /api/settings/ui-preference POST — persist streamlit/vue preference to user.yaml
- cancel_task() added to scripts/db.py (per-task cancel for Danger Zone)

Vue / UI:
- AppNav: " Classic" button to switch back to Streamlit UI (writes cookie + persists to user.yaml)
- ApplyWorkspace: Resume Highlights panel (collapsible skills/domains/keywords with job-match highlighting)
- SettingsView: hide Data tab in cloud mode (showData guard)
- ResumeProfileView: minor improvements
- useApi.ts: error handling improvements

Infra:
- compose.cloud.yml: add api service (uvicorn dev_api running in cloud container)
- docker/web/nginx.conf: proxy /api/* to api service in cloud mode
- README.md: Vue SPA now listed as Free tier feature
2026-04-04 22:04:51 -07:00
173da49087 feat: wire circuitforge-core config.load_env at entry points (closes #68 partial)
Some checks failed
CI / test (push) Failing after 19s
- app/app.py: load_env at module level (safe in Docker, fills gaps on bare-metal)
- dev_api.py: load_env in startup handler (avoids test-env pollution)
- requirements.txt: note >= 0.7.0 requirement; TODO tag once cf-core cuts release

db.migration runner deferral: tracked in #43 (Rails-style numbered migrations)
CFOrchClient VRAM wiring: already present in task_scheduler via CF_ORCH_URL env var
2026-04-04 19:37:58 -07:00
1ab1dffc47 feat: cf-core env-var LLM config + coordinator auth (closes #67)
Some checks failed
CI / test (push) Failing after 38s
- LLMRouter shim: tri-level config priority (local yaml > user yaml > env-var)
- .env.example: document OLLAMA_HOST, OLLAMA_MODEL, OPENAI_MODEL, ANTHROPIC_MODEL,
  CF_LICENSE_KEY, CF_ORCH_URL
- Wizard Step 5: env-var setup hint + optional Ollama fields for remote profile
- Preflight: write OLLAMA_HOST to .env when Ollama is adopted from host process
2026-04-04 19:27:24 -07:00
9392ee2979 fix: address code review — drop OLLAMA_RESEARCH_HOST, fix test fidelity, simplify model guard 2026-04-04 19:26:08 -07:00
3f376347d6 feat(preflight): write OLLAMA_HOST to .env when Ollama is adopted from host
When preflight.py adopts a host-running Ollama (or ollama_research) service,
write OLLAMA_HOST (and OLLAMA_RESEARCH_HOST) into .env using host.docker.internal
so LLMRouter's env-var auto-config resolves the correct address from inside the
Docker container without requiring a config/llm.yaml to exist.
2026-04-04 19:02:26 -07:00
cd865a9e77 feat(wizard): surface env-var LLM setup hint + optional Ollama field in Step 5 2026-04-04 18:39:16 -07:00
c5e2dc975f chore: add LLM env-var config + CF coordinator vars to .env.example 2026-04-04 18:37:58 -07:00
f62a9d9901 feat: llm_router shim — tri-level config priority (local > user > env-var) 2026-04-04 18:36:29 -07:00
b79d13b4f2 feat(vue): parity gaps #50, #54, #61 — sort/filter, research modal, draft CL button
Some checks failed
CI / test (push) Failing after 30s
#50 Job Review list view — sort + filter controls:
- Sort by best match / newest first / company A-Z (client-side computed)
- Remote-only checkbox filter
- Job count indicator; filters reset on tab switch
- Remote badge on list items

#61 Cover letter generation from approved tab:
- ' Draft' button on each approved-list item → /apply/:id
- No extra API call; ApplyWorkspace handles generation from there

#54 Company research modal (all API endpoints already existed):
- CompanyResearchModal.vue: 3-state machine (empty→generating→ready)
  polling /research/task every 3s, displays all 7 research sections
  (company, leadership, talking points, tech, funding, red flags,
  accessibility), copy-to-clipboard for talking points, ↺ Refresh
- InterviewCard: new 'research' emit + '🔍 Research' button for
  phone_screen/interviewing/offer stages
- InterviewsView: wires modal with researchJobId/Title/AutoGen state;
  auto-opens modal with autoGenerate=true when a job is moved to
  phone_screen (mirrors Streamlit behaviour)
2026-04-02 19:26:13 -07:00
5f4eecbc02 chore(release): v0.8.5
Some checks failed
CI / test (push) Failing after 27s
2026-04-02 18:47:33 -07:00
9069447cfc Merge pull request 'feat(wizard): Vue onboarding wizard + user config isolation fixes' (#65) from feature/vue-wizard into main
Some checks failed
CI / test (push) Failing after 26s
2026-04-02 18:46:42 -07:00
deeba0211d fix(isolation): 4 user config isolation + resume upload bugs
Some checks failed
CI / test (pull_request) Failing after 33s
- _user_yaml_path(): remove dangerous fallback to /devl/job-seeker/
  config/user.yaml (Meg's legacy profile); a missing user.yaml now
  returns an empty dict via load_user_profile, never another user's data
- RESUME_PATH: replace hardcoded relative Path('config/plain_text_
  resume.yaml') with _resume_path() that derives from _user_yaml_path()
  so resume file is always co-located with the correct user.yaml
- upload_resume: was passing a file path string to structure_resume()
  which expects raw text; now extracts bytes, dispatches to the correct
  extractor (pdf/odt/docx), then passes text — matches Streamlit wizard
- WizardResumeStep.vue: upload response is {ok, data: {experience…}}
  but component was reading data.experience (top level); fixed to
  read resp.data.experience to match the actual API envelope
2026-04-02 18:23:02 -07:00
e0828677a4 feat(wizard): Vue onboarding wizard — all 7 steps + router wiring
- WizardLayout.vue: full-page card, progress bar, crash-recovery via
  loadStatus(isCloud); auto-skips steps 1/2/5 in cloud mode
- wizard.css: shared step styles (headings, banners, radio cards,
  chip lists, form fields, expandables, nav buttons)
- Step 1 — Hardware: GPU detection, profile select, mismatch warning
- Step 2 — Tier: Free/Paid/Premium radio cards
- Step 3 — Resume: upload (PDF/DOCX/ODT) or manual experience builder;
  pre-fills identity fields from parsed resume data
- Step 4 — Identity: name/email/phone/LinkedIn/career summary;
  full validation before saveStep
- Step 5 — Inference: remote API keys vs local Ollama; advanced
  service-host/port expandable; soft-fail connection test
- Step 6 — Search: chip-style job title + location input with
  comma/Enter commit; remote-only checkbox
- Step 7 — Integrations: optional tile-grid (Notion/Calendar/Slack/
  Discord/Drive); paid-tier badge for gated items; calls
  wizard.complete() on Finish
- wizard.ts Pinia store: loadStatus, detectHardware, saveStep,
  testInference, complete; cloud auto-skip logic
- wizardGuard.ts: gates all routes behind /setup until
  wizard_complete; redirects complete users away from /setup
- router/index.ts: /setup nested route tree; unified beforeEach guard
  (wizard gate → setup branch → settings tier gate)
- App.vue: hide AppNav + strip sidebar margin on /setup routes
2026-04-02 18:11:57 -07:00
104c1e8581 feat(wizard): add Vue wizard API endpoints and wizardComplete/isDemo to app config
New endpoints:
- GET  /api/wizard/status       — resume-after-refresh; returns wizard_step + saved_data
- POST /api/wizard/step         — persist step data; side effects per step
                                  (step 3: plain_text_resume.yaml, step 5: .env keys,
                                   step 6: search_profiles.yaml)
- GET  /api/wizard/hardware     — GPU detection + profile suggestion
- POST /api/wizard/inference/test — soft-fail Ollama/LLM connectivity check
- POST /api/wizard/complete     — set wizard_complete=true, apply service URLs

Updated:
- GET /api/config/app now includes wizardComplete (from user.yaml) and isDemo
  (from DEMO_MODE env) so the Vue nav guard can gate on a single config fetch

30 tests, all passing
2026-04-02 17:55:03 -07:00
b6baa664b4 chore(release): v0.8.4
Some checks failed
CI / test (push) Failing after 30s
2026-04-02 17:47:26 -07:00
8b1d576e43 Merge pull request 'feat(vue): open Vue SPA to all tiers; fix cloud navigation and feedback button' (#64) from feature/vue-streamlit-parity into main
Some checks failed
CI / test (push) Failing after 28s
2026-04-02 17:46:47 -07:00
3313eade49 test: update cover letter mock signature to include user_yaml_path param
Some checks failed
CI / test (pull_request) Failing after 31s
2026-04-02 17:43:01 -07:00
b06d596d4c feat(vue): open Vue SPA to all tiers; fix cloud nav and feedback button
Some checks failed
CI / test (pull_request) Failing after 1m16s
- Lower vue_ui_beta gate to "free" so all licensed users can access the
  new UI without a paid subscription
- Remove "Paid tier" wording from the Try New UI banner
- Fix Vue SPA navigation in cloud/demo deployments: add VITE_BASE_PATH
  build arg so Vite sets the correct subpath base, and pass
  import.meta.env.BASE_URL to createWebHistory() so router links
  emit /peregrine/... paths that Caddy can match
- Fix feedback button missing on cloud instance by passing
  FORGEJO_API_TOKEN through compose.cloud.yml
- Remove vLLM container from compose.yml (vLLM dropped from stack;
  cf-research service in cfcore covers the use case)
- Fix cloud config path in Apply page (use get_config_dir() so per-user
  cloud data roots resolve correctly for user.yaml and resume YAML)
- Refactor generate_cover_letter._build_system_context and
  _build_mission_notes to accept explicit profile arg (enables
  per-user cover letter generation in cloud multi-tenant mode)
- Add API proxy block to nginx.conf (Vue web container can now call
  /api/ directly without Vite dev proxy)
- Update .env.example: remove vLLM vars, add research model + tuning
  vars for external vLLM deployments
- Update llm.yaml: switch vllm base_url to host.docker.internal
  (vLLM now runs outside Docker stack)

Closes #63 (feedback button)
Related: #8 (Vue SPA), #50–#62 (parity milestone)
2026-04-02 17:41:35 -07:00
66dc42a407 fix(preflight): remove vllm from Docker adoption list
vllm is now managed by cf-orch as a host process — no Docker service
defined in compose.yml. Preflight was detecting port 8000 (llm_server)
and generating a vllm stub in compose.override.yml with no image,
causing `docker compose up` to error on startup.
2026-04-02 16:57:06 -07:00
bc80922d61 chore(llm): swap model_candidates order — Qwen2.5-3B first, Phi-4-mini fallback
Phi-4-mini's cached modeling_phi3.py imports SlidingWindowCache which
was removed in transformers 5.x. Qwen2.5-3B uses built-in qwen2 arch
and works cleanly. Reorder so Qwen is tried first.
2026-04-02 16:36:38 -07:00
11fb3a07b4 chore(llm): switch vllm model_candidates from Ouro to Phi-4-mini + Qwen2.5-3B
Ouro models incompatible with transformers 5.x bundled in cf env.
Phi-4-mini-instruct tried first (stronger benchmarks, 7.2GB);
Qwen2.5-3B-Instruct as VRAM-constrained fallback (5.8GB).
2026-04-02 15:34:59 -07:00
7c9dcd2620 config(llm): add cf_orch block to vllm backend 2026-04-02 12:20:41 -07:00
13cd4c0d8a fix(cloud): mount llm.cloud.yaml over llm.yaml; restrict to vllm+ollama only
Some checks failed
CI / test (push) Failing after 17s
Remove claude_code, github_copilot, and anthropic from all cloud fallback
orders — cloud accounts must not route through personal/dev LLM backends.
vllm_research and ollama_research are the only permitted research backends.
llm.cloud.yaml is now bind-mounted at /app/config/llm.yaml in compose.cloud.yml.
2026-04-01 19:59:01 -07:00
5b296b3e01 fix(discovery): per-user config dir in cloud mode; normalize job_titles key
Some checks failed
CI / test (push) Failing after 22s
- discover.py: run_discovery() accepts config_dir param; auto-derives it
  from db_path parent (per-user in cloud, falls back to /app/config)
- task_runner.py: passes db_path.parent/config as config_dir to run_discovery
- wizard (0_Setup.py): write 'titles' key not 'job_titles' — matches what
  discover.py and all custom board scrapers read
- adzuna/theladders/craigslist: fall back to 'job_titles' for existing
  profiles written by older wizard versions
- Fixed Sheridan's live config in place (job_titles → titles)
2026-04-01 19:37:29 -07:00
4700a2f6d6 chore(release): v0.8.3
Some checks failed
CI / test (push) Failing after 22s
2026-04-01 15:02:19 -07:00
b3223025fa fix(api): read STAGING_DB from env at call time in _user_yaml_path()
Some checks failed
CI / test (push) Failing after 25s
Module-level DB_PATH is frozen at import time, so monkeypatch.setenv()
in tests had no effect on _user_yaml_path(). Reading os.environ directly
fixes 6 test_dev_api_settings PUT/POST failures in CI where
/devl/job-seeker/ doesn't exist.
2026-04-01 14:02:08 -07:00
5266aa52e8 ci: configure Forgejo git credentials before pip install
Some checks failed
CI / test (push) Failing after 27s
FORGEJO_TOKEN secret injected via env var (not inline expression) to
avoid CI injection risk; git insteadOf redirect authenticates the
git+https:// circuitforge-core VCS URL at install time.
2026-04-01 13:43:54 -07:00
d31a31b263 chore: release v0.8.2
Some checks failed
CI / test (push) Failing after 28s
2026-04-01 13:22:43 -07:00
a153546335 fix(ci): replace local -e path with Forgejo VCS URL for circuitforge-core
Some checks failed
CI / test (push) Has been cancelled
CI checks out only the peregrine repo — ../circuitforge-core doesn't exist,
causing 'pip install -r requirements.txt' to fail.

requirements.txt now uses git+https://...@main as the fallback for CI and
bare pip installs. Dockerfile.cfcore installs cfcore from the local COPY
first (skipping the requirements.txt line) to avoid a redundant network
fetch during Docker builds.
2026-04-01 13:22:06 -07:00
88c662f08d feat: switch main compose to Dockerfile.cfcore parent-context build
Some checks failed
CI / test (push) Failing after 31s
compose.yml was still using build: . which fails because requirements.txt
has -e ../circuitforge-core outside the build context. Now matches
compose.cloud.yml and compose.test-cfcore.yml.
2026-04-01 13:00:45 -07:00
83c87d4a13 feat(cloud): promote cfcore integration to production cloud instance
Some checks failed
CI / test (push) Failing after 19s
Switch compose.cloud.yml build context to Dockerfile.cfcore (parent
context includes circuitforge-core/ as sibling). Adds CF_ORCH_URL so
the cloud container can reach the cf-orch coordinator on the host.
2026-04-01 11:25:00 -07:00
d00d74d994 feat(scheduler): read CF_ORCH_URL env var for coordinator address
Some checks failed
CI / test (push) Failing after 19s
Threads coordinator_url from CF_ORCH_URL env var (default localhost:7700)
into the cfcore TaskScheduler so Docker instances can point at
host.docker.internal:7700 instead of the container's own loopback.

Also adds CF_ORCH_URL to compose.test-cfcore.yml and mounts persistent
patched configs (llm.docker.yaml, user.docker.yaml) for the test instance.
2026-04-01 11:06:38 -07:00
a8b08f3a45 fix: prevent Vue-nav reload loop when running without Caddy proxy
Some checks failed
CI / test (push) Failing after 20s
sync_ui_cookie() was calling window.parent.location.reload() on every
render when user.yaml has ui_preference=vue, but no Caddy is in the
traffic path (test instances, bare Docker). This caused an infinite
reload loop because the reload just came back to Streamlit.

Gate the reload on PEREGRINE_CADDY_PROXY=1. Without it, the cookie is
still written silently but no reload is attempted. Add the env var to
compose.yml and compose.cloud.yml (both are behind Caddy); omit from
compose.test-cfcore.yml so test instances stay stable.
2026-04-01 08:21:15 -07:00
be19947cb4 chore(release): v0.8.1
Some checks failed
CI / test (push) Failing after 42s
2026-04-01 07:25:13 -07:00
a6b32917ea chore(docker): add cfcore-aware Dockerfile and test compose
- Dockerfile: restored to original (build: . context, no cfcore) so
  existing compose.yml / compose.cloud.yml builds are unaffected
- Dockerfile.cfcore: parent-context build that copies circuitforge-core/
  alongside peregrine/ before pip install; resolves -e ../circuitforge-core
- compose.test-cfcore.yml: single-user test instance on port 8516;
  run from parent dir with context: .. so both repos are in scope

Use this to smoke-test cfcore shims before promoting to prod cloud.
2026-04-01 07:24:47 -07:00
2959abb3da fix(settings): improve suggest feedback for empty/failed LLM results
- Catch all exceptions (not just RuntimeError) so FileNotFoundError,
  connection errors, etc. surface as error messages rather than crashing
  the page silently
- Show "No new suggestions found" info message when the LLM returns
  empty arrays — previously the spinner completed with no UI feedback
- Hint to upload resume when RESUME_PATH is missing (new users)
- Only rerun() when there are actual results to display
2026-04-01 07:17:21 -07:00
98754cbe43 chore(release): v0.8.0 2026-04-01 07:12:48 -07:00
8c42de3f5c feat(merge): merge feature/vue-spa into main
Full Vue 3 SPA merge — closes #8. Major additions:

Backend (dev API):
- dev_api.py → symlink to dev-api.py (importable module alias)
- dev-api.py: full FastAPI backend (settings, jobs, interviews, prep,
  survey, digest, resume optimizer endpoints); cloud session middleware
- scripts/user_profile.py: load_user_profile / save_user_profile helpers
- scripts/discover.py + scripts/imap_sync.py: API-compatible additions

Frontend (web/src/):
- ApplyWorkspace: ATS resume optimizer panel (gap report free, rewrite paid+)
- ResumeOptimizerPanel.vue: new component with task polling + .txt download

Test suite:
- test_dev_api_settings/survey/prep/digest/interviews: full API test coverage
- fix: replace importlib.reload with monkeypatch.setattr(dev_api, "DB_PATH")
  to prevent module global reset breaking isolation across test files

Docs:
- docs/vue-spa-migration.md: migration guide
2026-04-01 07:11:14 -07:00
faa1807e96 feat(api): add job ranker and credential store scripts
- scripts/job_ranker.py: two-stage rank pipeline for /api/jobs/stack
  endpoint; scores pending jobs by match_score + seniority signals
- scripts/credential_store.py: per-user credential management (BYOK
  API keys, email passwords); used by dev_api settings endpoints
2026-04-01 07:10:46 -07:00
ee66b6b235 feat(web): add task indicator component and task store for background jobs
- web/src/stores/tasks.ts: Pinia store polling /api/tasks/active
- web/src/components/TaskIndicator.vue: sidebar + mobile task queue
  display with live count badge
- web/public/: peregrine logo assets (SVG + PNG variants)
2026-04-01 07:09:55 -07:00
02e004ee5c feat(apply): ATS resume optimizer backend — gap report + LLM rewrite
- scripts/resume_optimizer.py: full pipeline (extract_jd_signals →
  prioritize_gaps → rewrite_for_ats → hallucination_check)
- scripts/db.py: add optimized_resume + ats_gap_report columns +
  save_optimized_resume / get_optimized_resume helpers
- tests/test_resume_optimizer.py: 17 unit tests; patches at source
  module (scripts.llm_router.LLMRouter), not consumer

Tier gate: gap report is free; full LLM rewrite is paid+.
2026-04-01 07:09:46 -07:00
9702646738 fix(cloud): replace DEFAULT_DB with get_db_path() across all Streamlit pages
Pages were hardcoding DEFAULT_DB at import time, meaning cloud-mode
per-user DB routing was silently ignored. Pages affected:
1_Job_Review, 5_Interviews, 6_Interview_Prep, 7_Survey.

Adds resolve_session("peregrine") + get_db_path() pattern to each,
matching the pattern already used in 4_Apply.py.

Fixes #24.
2026-04-01 07:09:35 -07:00
dfac0f3d7a fix(tests): replace importlib.reload with monkeypatch.setattr for DB_PATH isolation
importlib.reload(dev_api) reset all module-level globals (RESUME_PATH,
SEARCH_PREFS_PATH, etc.) on every digest/interviews test, causing
subsequent monkeypatch.setattr calls in test_dev_api_settings.py to
silently fail — the patched attribute was reset between fixture setup
and the actual HTTP request.

Fix: patch dev_api.DB_PATH directly via monkeypatch, which pytest reverts
cleanly after each test without touching any other module state.

Also sync resume optimizer endpoints to dev-api.py (hyphen variant).
2026-04-01 06:58:28 -07:00
931a07d4e0 chore(merge): merge main into feature/vue-spa — resolve ApplyWorkspace conflict
ApplyWorkspace.vue: kept HEAD (vue-spa) version for resume optimizer panel,
cl-error__actions wrapper, and ResumeOptimizerPanel import. main's older
version lacked these additions.
2026-03-31 21:25:15 -07:00