Skip to content

fix: select jobs for assessment by current CV match, not legacy column - #15

Merged
sangowu merged 1 commit into
mainfrom
fix/assess-uses-modern-match
Aug 7, 2026
Merged

sangowu merged 1 commit into
mainfrom
fix/assess-uses-modern-match

Conversation

@sangowu

@sangowu sangowu commented Aug 7, 2026

Copy link
Copy Markdown
Owner

问题

cache.get_unassessed_jobs 先用 SQL WHERE assessment IS NULL 筛一遍,再查 job_matches

legacy assessment不记录 cv_hash,所以任何被旧 CV 评过的职位都被永久视为"已评估"。实测本地缓存:

数量
job_cache 职位 293(全部带 legacy assessment)
assess 实际捞出的待评估 0(提示"所有 JD 已有评估")
当前 CV 下确实没有 match 的 205
被旧 CV 判 is_relevant=False、永远不会被重新考虑的 95

同一函数的过滤条件还误用了循环残留变量:

for job in jobs:
    _attach_latest_match(job)
return [j for j in jobs if not j.is_expired and job.match_score is None]
                                             #  ↑ 应为 j.match_score

整批结果的去留由最后一条职位决定,与每条自身状态无关。

改动

  1. cache.get_unassessed_jobs — 判定只依据当前 cv_hash 下有无 job_matches 记录;同时修正上述变量错误。先过滤过期再挂载 match,减少多余查询;limit 改为作用于实际返回条数(原先作用于过滤前的扫描量,会少评)。

  2. search_assessment_stage.evaluate_cached_jobs(新增公开入口)— 复用既有的并发评估与原子提交路径,为已缓存职位补算 JD profile + CV match。

  3. cli.assess — 改用上述入口写入 job_matches,并显式确定 cv_hash(给了 CV 文件用 sha256(cv_text),否则取 cache.get_latest_cv_hash())。

第 3 点是必须的:只改判定标准而仍然只写 legacy 列,会让 assess 每次都重新捞出同一批职位,陷入永远评不完的循环。

验证

单测新增 TestUnassessedJobs(8 个用例),覆盖旧评分不再遮挡、旧 CV 的 match 不算数、逐条独立过滤(变量 bug 回归)、过期排除、limit 语义、以及补跑后再查为空的幂等性。

回退实现后 3 个用例失败,恢复后全绿;全量 224 passed。

真实缓存端到端验证(gemini,3 条):

pending before: 205
evaluated ok/failed: 3 / 0
pending after:  202
  cameramatics|accounts assistant       -> match  0.0 skip
  codec|change coordinator              -> match 19.6 skip
  eirgrid|systems integration developer -> match  0.0 skip

说明

本 PR 只修 assess 这一条路径。搜索管道里同源的问题(search_prefilter.py:161 的缓存命中判定同样不看 cv_hash,是那 95 条被永久挡住的直接原因)留待单独 PR。

🤖 Generated with Claude Code

https://claude.ai/code/session_012DbPx4FbswofbGn41anE1q

get_unassessed_jobs filtered on `assessment IS NULL` before consulting
job_matches. The legacy assessment column carries no cv_hash, so any job
scored under an earlier CV counted as done forever: on a 293-job cache the
command reported "all assessed" while 205 had no match under the current CV,
and 95 rejected by a previous CV could never be reconsidered.

Its filter predicate also read `job.match_score` -- a leftover loop variable
-- instead of `j.match_score`, so the entire batch was kept or dropped based
on the last row alone.

Selection now depends only on whether a match exists for the current cv_hash.
That change alone would have made `assess` re-queue the same jobs forever,
since the command only refreshed the legacy column; it now persists matches
through the shared evaluation path (evaluate_cached_jobs), keeping repeat runs
idempotent.

Verified against the real cache: 0 jobs queued before, 205 after; evaluating 3
of them dropped the queue to 202 with matches written for all three.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012DbPx4FbswofbGn41anE1q
@sangowu
sangowu merged commit 474ca34 into main Aug 7, 2026
2 checks passed
@sangowu
sangowu deleted the fix/assess-uses-modern-match branch August 7, 2026 21:07
sangowu added a commit that referenced this pull request Aug 7, 2026
job_cache.assessment is no longer written or read for scoring. It recorded no
cv_hash, and its 0-10 scale was being mixed with MatchScore's 0-100 inside the
same effective_score property, so legacy and modern scores sorted against each
other on incompatible scales.

  - effective_* properties depend only on match_score
  - both display.py render paths drop their legacy branch
  - the assess listing filter drops `or j.assessment is not None`
  - flush_assessments stops populating the column
  - cache.update_job_assessment is removed (its only caller was rewired in #15)

classify_cache_hit no longer consults the column. With no cv_hash it returns
reuse rather than reassess: flush_assessments skips patch_pending when has_cv
is false, so reassess would strand those jobs.

The column, the JobAssessment model and JobResult.assessment are kept so
historical rows stay readable -- model_quality_audit exports them, and
_merge_job still preserves existing values. No data is modified.


Claude-Session: https://claude.ai/code/session_012DbPx4FbswofbGn41anE1q

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant