- CRITICAL FIX: a real HF Space build was OOMKilled (exit 137) because
--setup started calling run_preprocess(limit=None) to pre-build the
candidates Parquet cache during the Docker build step. Build environments
are commonly more memory-constrained than the runtime container, and
loading+flattening 100K nested JSON records is exactly the kind of
Python-object-heavy operation that can spike past the build's memory
ceiling. OOMKilled is an OS-level SIGKILL, unrecoverable from Python, so
--setup no longer touches candidates at all -- it goes back to warming
only the models. The cache still gets built, just lazily on first real
use inside the already-running container (Streamlit's _warm_candidates,
or the first `rank.py --out`), in the runtime container's own budget.
- FIX: bm25_prefilter was wired into pipeline.py's run_full() but never
into streamlit_app.py's _rank_stages() -- the Streamlit phase explorer
was silently skipping it, meaning potion_broad there would…
- New Step 04.5 bm25_prefilter: cheap lexical BM25 pre-cut right after
hard_filter, before potion_broad's expensive embedding pass. Shrinks
potion's input from ~74K to 10K rows using JD-keyword overlap alone.
composite_narrow still runs its full potion+soft+bm25 blend later, once
those signals exist, so ranking quality is unchanged. Falls back to a
full passthrough on an empty/failed JD spec rather than an arbitrary cut.
- broad_retrieval/composite_narrow/precision all use fixed top_n counts
now (500/200/125) instead of a mix of top_pct and top_n.
- Moved the candidates Parquet cache down into load_candidates() itself
(was one layer up in run_preprocess, which Streamlit's per-phase
explorer bypasses). Now both the CLI and Streamlit share one cache —
verified Streamlit's eager warm-up dropped from 14.6s to 0.27s.
- Streamlit's _load_phase_input switched to st.cache_resource (avoids
copying the 100K-row frame on every cache hit; safe since every
downstream Polars st…
Run JD parse sequentially; reduce parse_max_tokens
Hemprasad Badgujar
1e50702
JD parse and preprocess were running concurrently via ThreadPoolExecutor, but both independently claim the full compute.cpu_threads budget (llama.cpp n_threads, Polars POLARS_MAX_THREADS). On constrained hardware (2 vCPUs), this causes thread contention rather than overlap — measured runs show JD parse itself ~20s slower (95.9s→116.0s) when concurrent, netting 5s worse total than sequential.
Reduce parse_max_tokens from 1536→1024 based on observed peak usage (~800 tokens); richest response (32 skills) stayed well under 1024, keeping ~28% headroom while bounding rare runaway costs.
Net effect: 57.8s end-to-end on local hardware (previously 118.1s).
Move JD extraction from data/artifacts/ (gitignored) to data/ so the demo-critical artifact ships with the repo/image. Increase n_ctx from 4096→6144 to handle longer JDs safely. Reduce parse_attempts from 2→1 (mitigated via improved prompt clarity). Retire target_industries/exclude_companies from LLM prompt to free budget for skill/title recall, but keep as [] in schema for stability. Major prompt refinements: simplify role/task structure, emphasize skill recall priority with explicit scan guidance, consolidate constraints. Add data/jd_extraction.json fixture (parsed from sample job_description.md) and empty secrets file. Update tests & docs to reflect retired prompt fields.